Shumoku

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 | sh

For 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 sh

Knobs: 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.

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 -d

Open 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 -d

Or 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 demo

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.4

See 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 -d

If 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 --build

The --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:latest

Inspect 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

# Make bun available system-wide (the service does not see ~/.bun)
sudo cp "$(command -v bun)" /usr/local/bin/bun

sudo cp scripts/shumoku.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now shumoku

No user or data-directory preparation is needed — the unit manages a dedicated user and /var/lib/shumoku itself via DynamicUser= and StateDirectory=.

Configuration

Don't edit the unit; put environment variables in /etc/default/shumoku (KEY=value lines, picked up automatically):

# /etc/default/shumoku
PORT=8080
#POLL_INTERVAL=60000
sudo systemctl restart shumoku

Manage

sudo systemctl status shumoku      # Status
sudo journalctl -u shumoku -f      # Logs
sudo systemctl restart shumoku     # Restart

Update

cd /opt/shumoku
git pull
cd apps/server
make setup
sudo systemctl restart shumoku

Manual

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 make start

Without DATA_DIR, data is stored in apps/server/data.

Update

cd shumoku
git pull
cd apps/server
make setup
make start

Reverse Proxy & HTTPS

Shumoku Server itself speaks plain HTTP only. When exposing it on a domain, always terminate TLS at a reverse proxy — don't send the admin password and session cookie over plain HTTP.

This is all it takes, including automatic certificate issuance and renewal (Let's Encrypt). WebSocket, SSE and long-running requests work without extra configuration:

shumoku.example.com {
    reverse_proxy 127.0.0.1:8080
}

nginx

Obtain TLS separately (e.g. certbot --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;
        # Syncs that run SNMP scans stay quiet for minutes (default 60s cuts them off)
        proxy_read_timeout 300s;
    }
}

WebSocket (/ws) requires the Upgrade and Connection headers shown above, and long-running requests such as SNMP syncs need the raised proxy_read_timeout. Shared-dashboard SSE needs no extra configuration — the server sends X-Accel-Buffering: no.

Environment Variables

VariableDescriptionDefault
PORTServer port8080
HOSTBind address0.0.0.0
DATA_DIRData directory (SQLite)Docker: /data, systemd: /var/lib/shumoku, from source: apps/server/data
SHUMOKU_PORTExternal port (Docker Compose)8080
DEMO_MODELoad sample network on empty DBfalse

Backup & Restore

All data lives in a SQLite database (shumoku.db) in the data directory (DATA_DIR above — /data on Docker). 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 start

Systemd — 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 shumoku

Always take a backup before an update that includes schema changes.

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.com

Restore 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.db

Using MinIO? The MinIO image requires a fairly modern CPU (the x86-64-v2 instruction set). On older or minimal VMs it may fail to start with Fatal 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.

On this page