Install with Docker
This is the shortest path to a running CapacityLens instance: one Docker Compose stack with the web app, the API and an automatic internal certificate, backed by SQLite on persistent volumes. It takes about ten minutes on a host that already has Docker installed, most of it waiting for the first build.
Prerequisites
- A host that can run Docker and Docker Compose. See Docker's install instructions for your OS.
- Read Before you start if you haven't already.
- Architecture: the packaged images are built from multi-architecture base images (
node,alpine,nginx-unprivileged), which publish bothlinux/amd64andlinux/arm64. CapacityLens itself is tested on x86-64; arm64 (including Apple Silicon and AWS Graviton hosts) should work but isn't independently tested — open an issue if you hit something arm64-specific. - Resources: this is a small Node API and a static file server backed by SQLite, not a heavy stack. As rough guidance: 1 CPU core, 1 GB RAM and a few GB of disk (more if you keep a lot of backup snapshots) is enough for a single small team.
Steps
Clone the repository and copy the example environment file:
bashgit clone https://github.com/Kevinjohn/capacitylens.git cd capacitylens cp .env.example .envGenerate two secrets — one for signing sessions, one for the first-owner setup token:
bashopenssl rand -base64 48Run it twice and keep both values; you'll paste one into each of the two secret fields in the next step.
Open
.envand set at least these values:dotenvSMALLSASS_ACCOUNT_DEPLOYMENT_PROFILE=self-hosted-password SMALLSASS_ACCOUNT_MODE=password SMALLSASS_ACCOUNT_SECRET=<first generated value> SMALLSASS_ACCOUNT_PUBLIC_URL=https://capacity.example.com SMALLSASS_ACCOUNT_SETUP_TOKEN=<second generated value> CAPACITYLENS_HTTPS=1 CAPACITYLENS_RATE_LIMIT=300SMALLSASS_ACCOUNT_PUBLIC_URLmust be the exact browser-facing origin. See Configuration for what every other variable does.Build and start the stack:
bashdocker compose up --build -dThis also builds the
internal-tlsone-off service, which creates a private certificate authority and API certificate before the API or web service starts.Watch the API come up:
bashdocker compose logs -f apiPress
Ctrl-Cto stop following once the log settles — the API doesn't print a single "ready" line, so a quiet log with no restart is what you're looking for.Check the app is serving and the API is healthy:
bashdocker compose ps curl -fsS http://127.0.0.1:8080/api/healthExpected output is a JSON object starting
{"ok":true,...}. With the packaged defaults, deep health is on, so you'll also seedb,audit,auditPending,backupandinternalTlsfields — see Monitoring and health checks for what each one means.In the
docker compose psoutput,internal-tlsshowingExited (0)is expected — it's a one-shot job that creates the internal certificate and then exits successfully; it isn't meant to keep running. See Monitoring and health checks for how to check the certificate it created.Put a TLS-terminating reverse proxy in front of port 8080 and finish sign-in setup. See TLS and networking for the proxy, then enter
SMALLSASS_ACCOUNT_SETUP_TOKENas the first owner when you open the app through your domain.
TIP
Compose binds port 8080 to 127.0.0.1 by default — nothing outside the host can reach it until you add the reverse proxy in the next page.
A demo-only, no-backend image
If you just want to try the interface with no database and no sign-in, build the client-only image instead:
VITE_CAPACITYLENS_DEMO=1 docker compose up --build -d web-client
curl -fsS http://127.0.0.1:8080/Naming web-client explicitly is what matters — it starts only that service, with no API dependency and no certificate volume. Data resets on every page refresh; this mode is not a persistent installation.
WARNING
web-client binds the same 127.0.0.1:8080 port as the real web service from the steps above. Don't run both on the same host at once — the second one to start will fail to bind the port, or worse, you'll end up unsure which one you're looking at. Give the demo its own port with WEB_PORT:
WEB_PORT=8081 VITE_CAPACITYLENS_DEMO=1 docker compose up --build -d web-client
curl -fsS http://127.0.0.1:8081/What's next
- Configuration to understand every environment variable you just set, plus the ones you didn't.
- TLS and networking to put a real domain and certificate in front of the stack.