Portainer, plain Docker and everything else

CapScope is one Go binary, a Dockerfile and a compose file. Any platform that can run a Docker image can run it — nothing platform-specific is required. This page covers Portainer, plain docker compose, docker run, Swarm, Podman and a generic checklist for NAS boxes and homelab panels.

Running CapRover, Coolify, Dokploy or Dokku instead? Those have their own pages — the steps differ in the dashboard, not in CapScope.

Portainer

Add the stack

Stacks → Add stack and paste the contents of deploy/docker-compose.yml.

Set the password

Change AUTH_PASS from change-me to a long random password before you expose the port.

Deploy

Deploy the stack. Portainer's own container shows up in the sidebar — hide it with EXCLUDE=^portainer if it is noisy.

bash — verify from the host
docker ps --filter name=capscope
curl -fsS http://localhost:8080/healthz   # ok

Plain Docker Compose

bash
cd deploy
docker compose up -d --build
# then open http://<host>:8080

AUTH_PASS defaults to change-me in the compose file — change it before exposing the port.

Plain docker run

bash
docker run -d --name capscope -p 8080:8080 \
  -e AUTH_PASS='a long random password' \
  -v capscope-data:/data \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --restart unless-stopped \
  ghcr.io/hacrex/capscope:latest

Swarm / docker stack deploy

bash
docker stack deploy -c deploy/docker-compose.yml capscope
Swarm caveat: CapScope only sees containers on the node its task is scheduled on, because it reads the host socket. Pin it to the node with the most containers using placement constraints if you run several nodes.

Generic checklist

For "my NAS, my homelab panel, my reverse-proxy box" — if it runs Docker images, these six items are the whole deployment:

  • Image. Build from the Dockerfile at the repo root, or run the published ghcr.io/hacrex/capscope:latest.
  • Persistent volume on /data — the SQLite database lives there.
  • Docker API access — mount /var/run/docker.sock, or set DOCKER_HOST=tcp://… to a socket proxy.
  • AUTH_PASS (mandatory), optionally AUTH_USER, LOG_RETENTION, MAX_DB_MB, EXCLUDE.
  • Reverse proxy on port 8080, HTTPS mandatory — Basic auth travels in clear text on HTTP. Health path: /healthz.
  • One instance only. Never run two CapScope containers against the same /data volume.
docker-compose.yml — full reference
services:
  capscope:
    image: ghcr.io/hacrex/capscope:latest
    ports: ["8080:8080"]
    environment:
      AUTH_USER: admin
      AUTH_PASS: "${CAPSCOPE_PASS:?set it}"
      MAX_DB_MB: 2048
      EXCLUDE: "^captain-|^portainer"
    volumes:
      - capscope-data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped

volumes:
  capscope-data:

Podman

Podman's docker alias is a drop-in CLI for the compose and docker run commands above, so the same commands work unchanged with podman-compose or the podman docker-compose shim. Two things differ:

TopicDetail
Socket pathThe Podman-compatible API socket is /run/podman/podman.sock (system service, rootful) or /run/user/$UID/podman/podman.sock (rootless). Mount it, or skip the mount and set DOCKER_HOST=unix:///run/podman/podman.sock — the Go client honours DOCKER_HOST.
Rootless caveatsUnder rootless Podman CapScope sees only that user's containers, and stats/events depend on Podman's Docker-compatible API emulation level. If the sidebar fills but live tail or snapshots stay silent, check that podman system service is running — or use the rootful socket. The scratch image itself runs fine (static binary, no daemon deps).

Not supported

Kubernetes — including TrueNAS SCALE and other k8s-based appliances. CapScope talks to the Docker Engine API (containers, logs, stats, events), not the kubelet. Run it as a Docker container on a Docker node instead; multi-node agent mode is on the roadmap.

Troubleshooting

SymptomLikely cause
Exits at start: AUTH_PASS is requiredSet AUTH_PASS, or ALLOW_NO_AUTH=true for a private test.
Exits at start: cannot reach DockerSocket not mounted, wrong DOCKER_HOST, or a proxy that does not expose CONTAINERS=1.
App list emptyINCLUDE/EXCLUDE filtering everything out, or no containers on this node.
Container shows no logsIts logging driver does not support reading — check whether docker logs fails for it too.
Live view stalls behind a proxyResponse buffering on /api/logs/stream; disable it for that path.
Database grows fastLower LOG_RETENTION, set MAX_DB_MB, or EXCLUDE chatty containers.