Installation
Deploy Shumoku Server with Docker, systemd, or manually
One-command install (fresh Linux host)
For a bare VM you just SSH'd into. Installs Docker (if missing), drops a
compose.yaml + .env into ./shumoku, and starts the service:
curl -fsSL https://raw.githubusercontent.com/konoe-akitoshi/shumoku/main/apps/server/scripts/install.sh | shFor production, pin a version and publish on port 80:
curl -fsSL https://raw.githubusercontent.com/konoe-akitoshi/shumoku/main/apps/server/scripts/install.sh \
| SHUMOKU_VERSION=0.1.4 SHUMOKU_PORT=80 shKnobs: SHUMOKU_VERSION (default latest), SHUMOKU_PORT (default 8080),
DEMO_MODE (default false), INSTALL_DIR (default ./shumoku). Prefer to read
before you pipe? See apps/server/scripts/install.sh.
Docker (Recommended)
The quickest way — pull the published image, no clone required:
docker run -d -p 8080:8080 -v shumoku-data:/data ghcr.io/konoe-akitoshi/shumoku:latest
# → http://localhost:8080 (add `-e DEMO_MODE=true` to preload a sample network)Images are published only on server-v* release tags (nothing is pushed from main). Available tags: X.Y.Z / X.Y.Z-beta.N (exact versions), latest (latest stable release), beta (latest beta release), and edge (most recent release, stable or beta) — see the container package.
Or build from source with Compose:
git clone https://github.com/konoe-akitoshi/shumoku.git
cd shumoku/apps/server
docker compose up -dOpen http://localhost:8080, set an admin password, and you're ready to go.
Docker Compose Options
compose.yaml stays unedited — set the knobs in a .env file beside it
(docker compose loads it automatically). Copy the template and adjust:
cp .env.example .env # SHUMOKU_VERSION / SHUMOKU_PORT / DEMO_MODE
docker compose up -dOr pass them inline for a one-off:
SHUMOKU_PORT=80 docker compose up -d # Custom port
DEMO_MODE=true docker compose up -d # Load sample network for demoPinning a version (recommended for production)
latest is a moving tag that follows the newest stable release. Its
contents match the newest stable release at pull time, but a later up -d
will silently upgrade once a new release ships. For reproducibility and
rollback, pin an exact version in .env:
# .env
SHUMOKU_VERSION=0.1.4See the "Docker" section above for available tags.
Update
Published image (Compose / one-command install) — bump SHUMOKU_VERSION
in .env, then recreate:
cd ~/shumoku # directory holding compose.yaml and .env
# edit SHUMOKU_VERSION in .env to the new version
docker compose pull
docker compose up -dIf you track latest, no edit is needed — just pull then up -d. Data is
preserved in the shumoku-data volume, and DB migrations run automatically on
startup.
Building from source — update the repo and rebuild:
cd shumoku/apps/server
git pull
docker compose up -d --buildThe --build flag rebuilds the image with the latest source.
Verifying the image (signature & SBOM)
Published images carry a keyless Cosign signature (via GitHub Actions OIDC) and an attached SBOM and SLSA provenance as OCI attestations (for releases built after this feature landed). Verify an image came from the official CI before pulling it:
cosign verify \
--certificate-identity-regexp '^https://github.com/konoe-akitoshi/shumoku/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/konoe-akitoshi/shumoku:latestInspect the SBOM / provenance:
# SBOM (packages included in the image)
cosign download sbom ghcr.io/konoe-akitoshi/shumoku:latest
# provenance (how/where it was built)
docker buildx imagetools inspect ghcr.io/konoe-akitoshi/shumoku:latest \
--format '{{ json .Provenance }}'Images are published multi-arch (linux/amd64 and linux/arm64), so the same tags run on ARM VPSes and Apple Silicon.
Systemd (Linux)
Prerequisites
- Bun runtime
- Git
Install
git clone https://github.com/konoe-akitoshi/shumoku.git /opt/shumoku
cd /opt/shumoku/apps/server
make setup
sudo mkdir -p /var/lib/shumoku
sudo chown shumoku:shumoku /var/lib/shumoku
sudo cp scripts/shumoku.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable shumoku
sudo systemctl start shumokuManage
sudo systemctl status shumoku # Status
sudo journalctl -u shumoku -f # Logs
sudo systemctl restart shumoku # RestartUpdate
cd /opt/shumoku
git pull
cd apps/server
make setup
sudo systemctl restart shumokuManual
Install
git clone https://github.com/konoe-akitoshi/shumoku.git
cd shumoku/apps/server
make setup
make start
# Or with custom settings
DATA_DIR=/path/to/data PORT=8080 bun dist/index.jsUpdate
cd shumoku
git pull
cd apps/server
make setup
make startReverse Proxy (nginx)
server {
listen 80;
server_name shumoku.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}WebSocket (/ws) requires the Upgrade and Connection headers shown above.
Environment Variables
| Variable | Description | Default |
|---|---|---|
PORT | Server port | 8080 |
HOST | Bind address | 0.0.0.0 |
DATA_DIR | Data directory (SQLite) | /data |
SHUMOKU_PORT | External port (Docker Compose) | 8080 |
DEMO_MODE | Load sample network on empty DB | false |
Backup & Restore
All data lives in a SQLite database (shumoku.db) under /data. It runs in
WAL mode, so the most recent writes sit in shumoku.db-wal until SQLite's
automatic checkpoint folds them into the main file — and stopping the server
does not force that checkpoint. Copying shumoku.db on its own can be
incomplete (sometimes nearly empty). Back up shumoku.db, shumoku.db-wal,
and shumoku.db-shm together, or copy the whole /data directory.
Docker — stopping briefly and archiving the whole /data volume is the
most reliable approach:
# Backup
docker compose stop
docker run --rm -v shumoku-data:/data -v "$PWD":/backup alpine \
tar czf /backup/shumoku-backup.tgz -C /data .
docker compose start
# Restore
docker compose stop
docker run --rm -v shumoku-data:/data -v "$PWD":/backup alpine \
sh -c 'rm -rf /data/* && tar xzf /backup/shumoku-backup.tgz -C /data'
docker compose startSystemd — copy the three DB files together (shumoku.db*):
sudo systemctl stop shumoku
cp /var/lib/shumoku/shumoku.db* ./backup/
sudo systemctl start shumoku
# Restore
sudo systemctl stop shumoku
cp ./backup/shumoku.db* /var/lib/shumoku/
sudo systemctl start shumokuAlways take a backup before an update that includes schema changes.
Continuous backups in production (recommended)
The manual backup above is a minimal "occasionally, to local disk" setup. In
production, pair it with Litestream, which
continuously replicates SQLite off-site without stopping it. It subscribes to
the WAL and streams changes to S3 / MinIO / Azure Blob in near-real-time, with
point-in-time restore. Because it works through SQLite's own mechanism rather
than copying raw files, it never pauses the app and never corrupts the DB. Add
one sidecar to compose.yaml:
services:
# shumoku service unchanged (shares the same shumoku-data volume)
litestream:
image: litestream/litestream:0.5.9
restart: unless-stopped
depends_on: [shumoku]
volumes:
- shumoku-data:/data
- ./litestream.yml:/etc/litestream.yml:ro
command: replicate
environment:
- LITESTREAM_ACCESS_KEY_ID=${S3_ACCESS_KEY}
- LITESTREAM_SECRET_ACCESS_KEY=${S3_SECRET_KEY}litestream.yml:
dbs:
- path: /data/shumoku.db
replica:
url: s3://my-backups/shumoku
# only for non-AWS (e.g. MinIO):
# endpoint: https://minio.example.comRestore from a separate container:
docker run --rm \
-v shumoku-data:/data \
-v "$PWD/litestream.yml":/etc/litestream.yml:ro \
-e LITESTREAM_ACCESS_KEY_ID=... -e LITESTREAM_SECRET_ACCESS_KEY=... \
litestream/litestream:0.5.9 restore /data/shumoku.dbUsing MinIO? The MinIO image requires a fairly modern CPU (the
x86-64-v2instruction set). On older or minimal VMs it may fail to start withFatal glibc error: CPU does not support x86-64-v2— point the replica at a real S3-compatible service or a lightweight S3 proxy (e.g.gaul/s3proxy) instead. Litestream itself (replicate/restore) is unaffected.
To automate scheduled backups without touching the app, an alternative is offen/docker-volume-backup as a sidecar — it stops the labeled container, archives the volume, and supports cron, encryption, S3, and retention.
Whichever you choose, the thing that matters most is testing restores regularly — a backup only counts once you've restored from it.