mirror of
https://github.com/Jermolene/TiddlyWiki5.git
synced 2026-03-18 04:41:12 -07:00
Add Docker support with docker-compose and automated release workflow
- Add Dockerfile (Node Alpine, unprivileged user, configurable via env vars) - Add docker-compose.yml with named volume and environment variable support - Add docker/entrypoint.sh for wiki init and --listen argument assembly - Add bin/docker-publish.sh for manual multi-platform image publishing - Add .github/workflows/docker-publish.yml for automated Docker Hub release on GitHub Release publish - Add editions/tw5.com howto tiddler documenting Docker usage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e1cf523e2c
commit
25f0bf2cf0
7 changed files with 384 additions and 0 deletions
26
.dockerignore
Normal file
26
.dockerignore
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Version control
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# Node dependencies (re-installed during build)
|
||||
node_modules
|
||||
|
||||
# CI/CD and tooling
|
||||
.github
|
||||
.eslintrc*
|
||||
.eslintignore
|
||||
*.eslint*
|
||||
|
||||
# Test output and coverage
|
||||
output
|
||||
*.test.js
|
||||
|
||||
# Documentation source (not needed at runtime)
|
||||
tw5.com
|
||||
editions/tw5.com
|
||||
|
||||
# Misc
|
||||
*.md
|
||||
CNAME
|
||||
LICENSE
|
||||
76
.github/workflows/docker-publish.yml
vendored
Normal file
76
.github/workflows/docker-publish.yml
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
name: Publish Docker Image
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published] # triggers when a GitHub Release is published
|
||||
workflow_dispatch: # allow manual trigger from the Actions tab
|
||||
inputs:
|
||||
tag:
|
||||
description: "TiddlyWiki version tag to publish (e.g. v5.3.6)"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write # needed if also pushing to GitHub Container Registry
|
||||
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name || inputs.tag }}
|
||||
|
||||
- name: Resolve version
|
||||
id: version
|
||||
run: |
|
||||
# Strip leading 'v' from tag (v5.3.6 → 5.3.6)
|
||||
RAW="${{ github.event.release.tag_name || inputs.tag }}"
|
||||
echo "value=${RAW#v}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up QEMU (for multi-platform builds)
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Optional: also push to GitHub Container Registry (ghcr.io)
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata for Docker tags
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
tiddlywiki/tiddlywiki
|
||||
ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=raw,value=${{ steps.version.outputs.value }}
|
||||
type=semver,pattern={{major}}.{{minor}},value=${{ steps.version.outputs.value }}
|
||||
type=semver,pattern={{major}},value=${{ steps.version.outputs.value }}
|
||||
type=raw,value=latest
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
NODE_LTS_VERSION=22
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
47
Dockerfile
Normal file
47
Dockerfile
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
ARG NODE_LTS_VERSION=22
|
||||
|
||||
FROM node:${NODE_LTS_VERSION}-alpine
|
||||
|
||||
# Build arguments (overridable at build time)
|
||||
ARG TIDDLYWIKI_DATA_DIR=/data
|
||||
ARG TIDDLYWIKI_PORT=8080
|
||||
|
||||
# Runtime environment variables
|
||||
ENV TIDDLYWIKI_DATA_DIR=${TIDDLYWIKI_DATA_DIR} \
|
||||
TIDDLYWIKI_PORT=${TIDDLYWIKI_PORT} \
|
||||
TIDDLYWIKI_HOST=0.0.0.0 \
|
||||
TIDDLYWIKI_USERNAME="" \
|
||||
TIDDLYWIKI_PASSWORD="" \
|
||||
TIDDLYWIKI_READERS="(anon)" \
|
||||
TIDDLYWIKI_WRITERS="(authenticated)"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install production dependencies only (no network install of tiddlywiki itself)
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Symlink CLI so 'tiddlywiki' is available on PATH
|
||||
RUN chmod +x tiddlywiki.js && \
|
||||
ln -s /app/tiddlywiki.js /usr/local/bin/tiddlywiki
|
||||
|
||||
# Create unprivileged user with fixed UID/GID 1000 (matches the default first user
|
||||
# on most Linux hosts, so bind-mounted directories work without --user override)
|
||||
RUN addgroup -g 1000 -S tiddlywiki && \
|
||||
adduser -u 1000 -S -G tiddlywiki tiddlywiki && \
|
||||
mkdir -p "${TIDDLYWIKI_DATA_DIR}" && \
|
||||
chown tiddlywiki:tiddlywiki "${TIDDLYWIKI_DATA_DIR}"
|
||||
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
USER tiddlywiki
|
||||
WORKDIR ${TIDDLYWIKI_DATA_DIR}
|
||||
|
||||
EXPOSE ${TIDDLYWIKI_PORT}
|
||||
|
||||
# Use Docker's built-in init process (docker run --init / compose: init: true)
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
31
bin/docker-publish.sh
Executable file
31
bin/docker-publish.sh
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env bash
|
||||
# Publish an official TiddlyWiki Docker image to Docker Hub.
|
||||
#
|
||||
# Usage:
|
||||
# ./bin/docker-publish.sh <tiddlywiki-version> [node-lts-version]
|
||||
#
|
||||
# Example:
|
||||
# ./bin/docker-publish.sh 5.3.6
|
||||
# ./bin/docker-publish.sh 5.3.6 22
|
||||
#
|
||||
# Requires:
|
||||
# - docker buildx with multi-platform support (linux/amd64, linux/arm64)
|
||||
# - docker login to Docker Hub as tiddlywiki org member
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TIDDLYWIKI_VERSION="${1:?Usage: $0 <tiddlywiki-version> [node-lts-version]}"
|
||||
NODE_LTS_VERSION="${2:-22}"
|
||||
REPO="tiddlywiki/tiddlywiki"
|
||||
|
||||
echo "Publishing ${REPO}:${TIDDLYWIKI_VERSION} (Node ${NODE_LTS_VERSION}-alpine) ..."
|
||||
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--build-arg NODE_LTS_VERSION="${NODE_LTS_VERSION}" \
|
||||
--tag "${REPO}:${TIDDLYWIKI_VERSION}" \
|
||||
--tag "${REPO}:latest" \
|
||||
--push \
|
||||
.
|
||||
|
||||
echo "Done. Image available at: https://hub.docker.com/r/${REPO}"
|
||||
38
docker-compose.yml
Normal file
38
docker-compose.yml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
services:
|
||||
tiddlywiki:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
NODE_LTS_VERSION: "22"
|
||||
# Or use the published image:
|
||||
# image: tiddlywiki/tiddlywiki:latest
|
||||
init: true # Docker's built-in init process for proper signal handling
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
volumes:
|
||||
# Named volume (default, Docker manages storage):
|
||||
- tiddlywiki-data:/data
|
||||
# Bind mount (map a host directory):
|
||||
# - ./my-wiki:/data
|
||||
# If using bind mount, the container runs as UID/GID 1000 by default.
|
||||
# On most Linux systems this matches the first non-root user, so no extra
|
||||
# chown is needed. If your host user has a different UID, either:
|
||||
# mkdir -p ./my-wiki && chown 1000:1000 ./my-wiki
|
||||
# or override at runtime:
|
||||
# user: "$(id -u):$(id -g)"
|
||||
environment:
|
||||
TIDDLYWIKI_PORT: "8080"
|
||||
TIDDLYWIKI_HOST: "0.0.0.0"
|
||||
# Authentication — set these (or use a .env file)
|
||||
TIDDLYWIKI_USERNAME: ""
|
||||
TIDDLYWIKI_PASSWORD: ""
|
||||
# Access control:
|
||||
# (anon) — all users including anonymous
|
||||
# (authenticated) — any logged-in user
|
||||
# (admin) — admin users only
|
||||
TIDDLYWIKI_READERS: "(anon)"
|
||||
TIDDLYWIKI_WRITERS: "(authenticated)"
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
tiddlywiki-data:
|
||||
34
docker/entrypoint.sh
Executable file
34
docker/entrypoint.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
WIKI_DIR="${TIDDLYWIKI_DATA_DIR:-/data}"
|
||||
HOST="${TIDDLYWIKI_HOST:-0.0.0.0}"
|
||||
PORT="${TIDDLYWIKI_PORT:-8080}"
|
||||
|
||||
# Initialize wiki on first run
|
||||
if [ ! -f "${WIKI_DIR}/tiddlywiki.info" ]; then
|
||||
echo "Initializing new wiki at ${WIKI_DIR} ..."
|
||||
tiddlywiki "${WIKI_DIR}" --init server
|
||||
fi
|
||||
|
||||
# Build --listen argument list
|
||||
LISTEN_ARGS="host=${HOST} port=${PORT}"
|
||||
|
||||
if [ -n "${TIDDLYWIKI_USERNAME}" ]; then
|
||||
LISTEN_ARGS="${LISTEN_ARGS} username=${TIDDLYWIKI_USERNAME}"
|
||||
fi
|
||||
|
||||
if [ -n "${TIDDLYWIKI_PASSWORD}" ]; then
|
||||
LISTEN_ARGS="${LISTEN_ARGS} password=${TIDDLYWIKI_PASSWORD}"
|
||||
fi
|
||||
|
||||
if [ -n "${TIDDLYWIKI_READERS}" ]; then
|
||||
LISTEN_ARGS="${LISTEN_ARGS} readers=${TIDDLYWIKI_READERS}"
|
||||
fi
|
||||
|
||||
if [ -n "${TIDDLYWIKI_WRITERS}" ]; then
|
||||
LISTEN_ARGS="${LISTEN_ARGS} writers=${TIDDLYWIKI_WRITERS}"
|
||||
fi
|
||||
|
||||
echo "Starting TiddlyWiki on ${HOST}:${PORT} ..."
|
||||
exec tiddlywiki "${WIKI_DIR}" --listen ${LISTEN_ARGS}
|
||||
132
editions/tw5.com/tiddlers/howtos/TiddlyWiki with Docker.tid
Normal file
132
editions/tw5.com/tiddlers/howtos/TiddlyWiki with Docker.tid
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
title: TiddlyWiki with Docker
|
||||
tags: [[TiddlyWiki on Node.js]] Docker
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
This page describes how to run [[TiddlyWiki on Node.js]] using Docker.
|
||||
|
||||
!! Quick Start
|
||||
|
||||
The simplest way to run TiddlyWiki in Docker is with `docker run`:
|
||||
|
||||
```
|
||||
docker run --init -p 127.0.0.1:8080:8080 \
|
||||
-v "$(pwd)/data:/data" \
|
||||
tiddlywiki/tiddlywiki
|
||||
```
|
||||
|
||||
Then open http://localhost:8080 in your browser. Wiki data is persisted in a `data` folder in the current directory.
|
||||
|
||||
!! Mapping a Host Directory
|
||||
|
||||
By default Docker uses a named volume to store wiki data. To use a host directory (bind mount) instead:
|
||||
|
||||
```
|
||||
mkdir -p ./my-wiki
|
||||
docker run --init -p 127.0.0.1:8080:8080 \
|
||||
-v "$(pwd)/my-wiki:/data" \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
tiddlywiki/tiddlywiki
|
||||
```
|
||||
|
||||
The container runs as UID/GID `1000` by default, which matches the first non-root user on most Linux systems. If your host user has a different UID, pass `--user "$(id -u):$(id -g)"` to override.
|
||||
|
||||
With Docker Compose, replace the named volume with a bind mount:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./my-wiki:/data
|
||||
# Only needed if your host UID is not 1000:
|
||||
# user: "${UID}:${GID}"
|
||||
```
|
||||
|
||||
!!! macOS
|
||||
|
||||
On macOS the first user has UID `501`, not `1000`. Always pass `--user` explicitly:
|
||||
|
||||
```
|
||||
mkdir -p ./my-wiki
|
||||
docker run --init -p 127.0.0.1:8080:8080 \
|
||||
-v "$(pwd)/my-wiki:/data" \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
tiddlywiki/tiddlywiki
|
||||
```
|
||||
|
||||
Or in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./my-wiki:/data
|
||||
user: "${UID}:${GID}"
|
||||
```
|
||||
|
||||
Note: Docker Desktop on macOS handles volume permissions through a file-sharing layer (gRPC FUSE or VirtioFS). If you encounter permission errors despite setting `--user`, check that the host directory is included in Docker Desktop → Settings → Resources → File Sharing.
|
||||
|
||||
!! Authentication
|
||||
|
||||
For internet-facing instances, always set a username and password:
|
||||
|
||||
```
|
||||
docker run --init -p 127.0.0.1:8080:8080 \
|
||||
-v "$(pwd)/data:/data" \
|
||||
-e TIDDLYWIKI_USERNAME=admin \
|
||||
-e TIDDLYWIKI_PASSWORD=changeme \
|
||||
tiddlywiki/tiddlywiki
|
||||
```
|
||||
|
||||
!! Using Docker Compose
|
||||
|
||||
Save the following as `docker-compose.yml` and run `docker compose up -d`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
tiddlywiki:
|
||||
image: tiddlywiki/tiddlywiki:latest
|
||||
init: true
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
volumes:
|
||||
- tiddlywiki-data:/data
|
||||
environment:
|
||||
TIDDLYWIKI_USERNAME: admin
|
||||
TIDDLYWIKI_PASSWORD: changeme
|
||||
TIDDLYWIKI_READERS: "(anon)"
|
||||
TIDDLYWIKI_WRITERS: "(authenticated)"
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
tiddlywiki-data:
|
||||
```
|
||||
|
||||
!! Environment Variables
|
||||
|
||||
|!Variable |!Default |!Description |
|
||||
|`TIDDLYWIKI_DATA_DIR` |`/data` |Path inside the container where wiki files are stored |
|
||||
|`TIDDLYWIKI_HOST` |`0.0.0.0` |Host address to bind to |
|
||||
|`TIDDLYWIKI_PORT` |`8080` |Port to listen on |
|
||||
|`TIDDLYWIKI_USERNAME` |''(empty)'' |HTTP Basic Auth username |
|
||||
|`TIDDLYWIKI_PASSWORD` |''(empty)'' |HTTP Basic Auth password |
|
||||
|`TIDDLYWIKI_READERS` |`(anon)` |Who can read: `(anon)`, `(authenticated)`, or a specific username |
|
||||
|`TIDDLYWIKI_WRITERS` |`(authenticated)` |Who can write: `(anon)`, `(authenticated)`, or a specific username |
|
||||
|
||||
!! Building from Source
|
||||
|
||||
To build the image yourself from the TiddlyWiki5 source:
|
||||
|
||||
```
|
||||
git clone https://github.com/TiddlyWiki/TiddlyWiki5.git
|
||||
cd TiddlyWiki5
|
||||
docker build --build-arg NODE_LTS_VERSION=22 -t tiddlywiki .
|
||||
```
|
||||
|
||||
!! Security Notes
|
||||
|
||||
* The container runs as an unprivileged `tiddlywiki` user (not root).
|
||||
* Bind the host port to `127.0.0.1` (as shown above) unless you intend to expose TiddlyWiki directly to a network.
|
||||
* For production use, place a reverse proxy (e.g. nginx or Caddy) with TLS in front of the container.
|
||||
|
||||
!! See Also
|
||||
|
||||
* [[TiddlyWiki on Node.js]]
|
||||
* [[WebServer API: Authenticating with the WebServer]]
|
||||
* [[WebServer Parameter: readers]]
|
||||
* [[WebServer Parameter: writers]]
|
||||
Loading…
Add table
Add a link
Reference in a new issue