Deploy
capsol is one Node 22 process plus a filesystem volume. No database, queue, or worker is required.
Environment
Section titled “Environment”| Variable | Default | Notes |
|---|---|---|
CAPSOL_SECRET_KEY | ephemeral in dev | Required for hosted deployments. Keep it outside the data directory. |
CAPSOL_SECRET_KEY_FILE | unset | Load the signing/session secret from an external secret file. |
CAPSOL_ADMIN_KEY | generated on first run | Bootstrap dashboard unlock key. Set only if you need deterministic first setup. |
CAPSOL_DATA_DIR | ./registry-data | Capsule storage. Mount this as a volume. |
PORT | 4000 from source, 8080 in Docker | HTTP port for dashboard, REST, and MCP. |
PUBLIC_URL | request origin | Overrides generated MCP connection URLs behind proxies. |
CAPSOL_TRUST_PROXY | 1 | Number of proxy hops Express should trust. |
CAPSOL_SCHEMES | built-ins only | JSON array of custom URI scheme definitions. |
CAPSOL_RATELIMIT_ENABLED | unset / off | Set true to enable built-in token buckets. The dashboard Settings page can also toggle this at runtime. |
CAPSOL_RATELIMIT_DISABLED | unset | Set true to force limits off even if enabled elsewhere. |
NODE_ENV | development | Use production behind HTTPS for secure cookies. |
Docker
Section titled “Docker”docker run -d --name capsol \ --restart unless-stopped \ -p 4000:8080 \ -v capsol-data:/data \ -e CAPSOL_SECRET_KEY="$(openssl rand -hex 32)" \ -e CAPSOL_DATA_DIR=/data \ -e NODE_ENV=production \ ghcr.io/arcadeai-labs/capsol-v2:latestPre-provision the bootstrap admin key only when you need deterministic first setup:
docker run -d --name capsol \ --restart unless-stopped \ -p 4000:8080 \ -v capsol-data:/data \ -e CAPSOL_SECRET_KEY="$(openssl rand -hex 32)" \ -e CAPSOL_DATA_DIR=/data \ -e NODE_ENV=production \ -e CAPSOL_ADMIN_KEY="$(openssl rand -base64 32)" \ ghcr.io/arcadeai-labs/capsol-v2:latestservices: capsol: image: ghcr.io/arcadeai-labs/capsol-v2:latest restart: unless-stopped ports: ["4000:8080"] environment: CAPSOL_SECRET_KEY: ${CAPSOL_SECRET_KEY} CAPSOL_ADMIN_KEY: ${CAPSOL_ADMIN_KEY} CAPSOL_DATA_DIR: /data NODE_ENV: production volumes: ["capsol-data:/data"]volumes: capsol-data:Fly.io
Section titled “Fly.io”The repo ships a fly.toml and Dockerfile. The container listens on internal port 8080; Fly exposes 80/443.
fly launch --copy-config --no-deployfly secrets set CAPSOL_SECRET_KEY="$(openssl rand -hex 32)"fly volumes create capsol_data --size 1 --region sjcfly deployVerify:
curl https://your-app.fly.dev/healthsystemd
Section titled “systemd”git clone https://github.com/arcadeai-labs/capsol-v2.git /opt/capsolcd /opt/capsolnpm cinpm --prefix registry cinpm run build[Unit]Description=capsol registryAfter=network.target
[Service]Type=simpleUser=capsolWorkingDirectory=/opt/capsolEnvironment=NODE_ENV=productionEnvironment=PORT=4000Environment=CAPSOL_DATA_DIR=/var/lib/capsolEnvironmentFile=/etc/capsol/envExecStart=/usr/bin/node dist/registry/server.jsRestart=on-failureRestartSec=5ProtectSystem=strictReadWritePaths=/var/lib/capsolNoNewPrivileges=true
[Install]WantedBy=multi-user.target/etc/capsol/env:
CAPSOL_SECRET_KEY=<paste-generated-secret-here>CAPSOL_ADMIN_KEY=<paste-generated-key-here>PUBLIC_URL=https://capsol.example.comReverse proxy
Section titled “Reverse proxy”capsol does not terminate TLS. Put nginx, Caddy, Cloudflare, Fly, or another TLS terminator in front.
server { listen 443 ssl; server_name capsol.example.com;
location / { proxy_pass http://127.0.0.1:4000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; }}Set PUBLIC_URL=https://capsol.example.com or save the same value in Settings → Hosted URLs so dashboard/API responses return public MCP URLs.
For OAuth MCP clients, the public URL must match the tunnel URL exactly. Start ngrok and copy its HTTPS forwarding URL:
ngrok http 4000Then either paste that URL into Settings → Hosted URLs → Public URL, or start capsol with PUBLIC_URL=https://your-subdomain.ngrok-free.app. The dashboard setting takes effect immediately for OAuth discovery and generated MCP URLs.
Verify discovery before adding the MCP server to Cursor or ChatGPT:
curl -s https://your-subdomain.ngrok-free.app/.well-known/oauth-authorization-server | jq .issuercurl -s https://your-subdomain.ngrok-free.app/.well-known/oauth-protected-resource | jq .resourceBoth values must use the https://...ngrok... origin, never 127.0.0.1. If you already connected a client while PUBLIC_URL was local, remove and re-add that MCP server so it performs DCR again.
Backups
Section titled “Backups”Everything durable is under CAPSOL_DATA_DIR.
tar -C /var/lib/capsol -czf /backups/capsol-$(date +%F).tar.gz .Restore by stopping capsol, extracting the archive back into CAPSOL_DATA_DIR, and starting capsol again.
Health
Section titled “Health”| Endpoint | Auth | Purpose |
|---|---|---|
GET /health | none | Liveness probe. |
GET /api/agents | admin cookie/key | Active MCP clients snapshot. |
GET /api/agents/stream | admin cookie/key | Dashboard activity SSE. |
/ | admin cookie/key after login | Dashboard. |
Reference
Section titled “Reference”registry/server.ts— Express 5 registry wrapper.registry/auth.ts— admin cookie and owner-token auth.registry/store.ts— boxes, shares, and activity persistence.- Access — credential model.
- Architecture — server factory and storage layout.