Deploying CapScope on Dokku

Dokku builds the repository's Dockerfile on git push — no buildpack needed. The CHECKS file at the repo root makes Dokku wait for /healthz before it routes any traffic.

1. Create the app

bash — app + persistent storage
dokku apps:create capscope

# persistent storage — the SQLite database survives redeploys
dokku storage:ensure-directory capscope --chown-on-add
dokku storage:mount capscope /var/lib/dokku/data/storage/capscope:/data

# Docker socket access
dokku storage:mount capscope /var/run/docker.sock:/var/run/docker.sock

The storage:mount commands take effect on the next deploy, so mount them before your first push.

Mounting docker.sock is root equivalent. Skip the second mount and use the socket proxy in step 5 if you want CapScope to have read-only access.

2. Configure it

bash — environment
dokku config:set capscope AUTH_USER=admin AUTH_PASS='a long random password'
dokku config:set capscope MAX_DB_MB=2048              # optional size cap
dokku config:set capscope EXCLUDE='^nginx|traefik'       # hide Dokku's own proxies

Worth excluding: the per-app nginx sidecars Dokku adds and the traefik/caddy ingress containers — they are noisy. Excluded containers are still followed for access logs only, so your Access dashboard keeps working.

KeyValue
AUTH_USER / AUTH_PASSMandatory password — the server refuses to start without it.
MAX_DB_MBHard cap on database size; oldest data dropped first.
EXCLUDERegex over container and app names.
LOG_RETENTIONDefault 7d — raise it if disk allows.

3. Deploy

bash
git remote add dokku dokku@<your-dokku-host>:capscope
git push dokku main

The first build downloads Go modules, so the Dokku host needs outbound internet during the build.

HTTPS

bash — letsencrypt plugin
dokku domains:set capscope capscope.example.com
dokku letsencrypt:set --global email you@example.com
dokku letsencrypt capscope
Do not expose CapScope on plain HTTP — Basic auth credentials travel in clear text. Also re-run dokku letsencrypt capscope before the certificate expires.

Scaling

Keep it at 1 process. The Dockerfile build already defaults to a single web process; do not run dokku ps:scale capscope web=2 or higher — instances would write the same SQLite file.

4. Socket proxy (recommended)

Run the proxy

Start tecnativa/docker-socket-proxy with CONTAINERS=1, EVENTS=1, PING=1, POST=0, no public port, on the same Docker network as CapScope.

Remove the socket mount

Instead of mounting the socket, point CapScope at the proxy:

bash
dokku config:set capscope DOCKER_HOST=tcp://<proxy-container-name>:2375

Re-deploy

git push dokku main again. CapScope only issues GET requests, so the proxy can stay fully read-only.

5. Notes

TopicDetail
PortsThe Dockerfile exposes 8080 and Dokku maps the first exposed port automatically, so no ports:set is needed. If you skip the web proxy: dokku ports:set capscope http:80:8080.
Live tail (SSE)CapScope sends X-Accel-Buffering: no, which Dokku's default Nginx proxy respects. Behind another reverse proxy, disable response buffering for /api/logs/stream.
Health check/healthz — auth-free by design; the CHECKS file already uses it.
Container userRuns as root on purpose — docker.sock needs it.
Crash catch-upDeaths that happened while CapScope was down are replayed from the persisted event cursor on startup (up to 24 h back).

6. Verify

Open the app

Visit https://capscope.example.com and log in. The header chip should show a container count above zero.

Check the sidebar

Your apps appear on the left; containers matched by EXCLUDE stay out but still feed the Access dashboard.

Trigger a test crash

Run a container that exits with code 1 and confirm a snapshot appears under Crashes with an exit code and log tail.

Rollback safety: because /data lives outside the container, redeploys, rebuilds and rollbacks never touch your log history, snapshots or alert rules.