Quickstart
From zero to a fused worker in about ten minutes. Get the master running, register the admin, take a quick UI tour, then add your first worker host. By the end Portainer is managing containers on the worker through the encrypted mesh.
1. Prerequisites
ContextBay runs everywhere Docker runs. For the master:
- Docker Engine 20.10+ on Linux amd64/arm64, macOS, or Windows via WSL2.
- ~512 MB free RAM and ~1 GB disk for the master plus the cb-* sub-container fleet.
- Ports
7480(HTTP/UI) and7481(gRPC) reachable from your worker LAN.
For each worker host:
- Docker Engine + ability to run a container with
--privileged=falseand a docker.sock bind mount. - Outbound HTTP to the master's LAN IP on
7480(used only for the one-time enroll), and outbound TCP to the Headscale public port for the steady-state mesh. - Port
9100free for the worker's local/metricsendpoint (commonly conflicts withnode-exporter— stop or relocate it).
2. Clone and deploy the master
The repo ships an opinionated make deploy target that builds the image, recreates the contextbay container with the right volume mounts, and waits for /api/health to come back green.
git clone https://github.com/contextbay/contextbay.git
cd contextbay
make deployOn the very first run the master:
- Creates the three CB volumes (
contextbay-data,contextbay-portainer-data,cb-n8n_contextbay-n8n-data). - Joins the
contextbay-internalDocker network and starts cb-portainer on its socket. - Deploys the cb-* sub-container fleet (cb-headscale, cb-prometheus, cb-alertmanager, cb-grafana, cb-loki, cb-tempo, cb-pyroscope, cb-n8n, cb-wazuh, cb-ollama) as Portainer stacks.
- Auto-generates a JWT signing secret + n8n encryption key and persists them in the database — never overwritten on subsequent deploys.
Verify the master is healthy:
curl -s http://localhost:7480/api/health
# {"status":"ok","version":"...","uptime_seconds":...}If the call fails, tail the logs and look for the bootstrap banner:
docker logs -f contextbay3. Register the admin user
Open http://localhost:7480 in your browser. The first-run flow shows a setup screen — enter a username and a password (8+ characters). The form posts to POST /api/auth/setup, which is permanently disabled after the first admin is created.
Do not call /api/auth/setup directly during scripted verification. That endpoint is meant for the UI bootstrap flow — once consumed, it returns 409 forever and you cannot create more admins through it. Use the Users page instead (/admin/users) to add additional admins or operators.
You should now see the Dashboard with green health pills for the master, Portainer, and the cb-* fleet.
4. UI tour
Spend two minutes clicking through the main pages so the rest of this guide makes sense:
- /dashboard — fleet health, alert digest, latest activity, embedded Grafana iframes for the most-used dashboards.
- /hosts — pending and enrolled hosts. This is where you add a worker and grab the install snippet.
- /containers — every container on every endpoint Portainer knows about, with stats, logs, and exec-into-shell.
- /workflows — the embedded n8n with the 36 seeded workflows. CB delegates workflow authoring to n8n; this page is the n8n iframe.
- /grafana, /planner, /brain — observability, project planner, knowledge vault. All auto-provisioned.
5. Add your first worker host
On the master UI, go to Hosts → Add Host. Pick a hostname (e.g. <worker-1>) and submit. The master:
- Mints a one-time enroll token (~24h TTL) and stores a pending host record.
- Renders the install snippet pre-filled with
CONTEXTBAY_MASTER_URL,CONTEXTBAY_MASTER_ADDR,CONTEXTBAY_NODE_NAME,CONTEXTBAY_ENROLL_TOKENandCONTEXTBAY_SHARED_SECRET.
Copy the snippet and paste it on the worker host. It looks like this:
docker run -d \
--name contextbay-worker \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-v contextbay-worker-data:/var/lib/contextbay \
-e CONTEXTBAY_MASTER_URL=http://<MASTER_LAN_IP>:7480 \
-e CONTEXTBAY_MASTER_ADDR=<MASTER_MESH_IP>:7481 \
-e CONTEXTBAY_NODE_NAME=<worker-1> \
-e CONTEXTBAY_ENROLL_TOKEN=<one-time-token-from-ui> \
-e CONTEXTBAY_SHARED_SECRET=<shared-secret-from-ui> \
ghcr.io/contextbay/contextbay-worker:latest<MASTER_MESH_IP> is the master's address on the Headscale mesh, in the 100.64.0.0/10 CGNAT range — the master is always assigned 100.64.0.1, so the shape is the same on every install.
See Worker Onboarding for what every variable means and why two master addresses exist.
6. Watch enrollment happen
Within a few seconds the worker boots, reads the env, and:
- Calls
POST /api/enrollonCONTEXTBAY_MASTER_URL— the only call that ever uses the LAN URL. - The master mints a Headscale pre-auth key and consumes the enroll token atomically.
- The worker's embedded tsnet client redeems the key against the Headscale control plane, joins the mesh, and starts a gRPC stream to
CONTEXTBAY_MASTER_ADDR.
On the worker you should see:
docker logs -f contextbay-worker
# ...
# msg="enroll: posting bootstrap" url=http://<MASTER_LAN_IP>:7480
# msg="enroll: redeemed authkey, joining mesh"
# msg="worker enrolled" node_name=<worker-1> mesh_addr=<MASTER_MESH_IP>:7481
# msg="grpc heartbeat ok"On the master's Hosts page, the host flips from pending to monitoring. The host detail page shows recent enroll attempts (and any rejected attempts with their reason codes — see Troubleshooting).
7. Fuse the host
Enrollment gets you monitoring (heartbeats, metrics, Docker events). To do container CRUD on the worker — start, stop, restart, redeploy — you fuse the host. Click Fuse on the host card. The master:
- Pushes a Portainer Edge agent stack to the worker via the worker agent.
- Waits for the Edge agent to register a new endpoint with the master's Portainer.
- Records the endpoint id on the host record and flips state to fused.
From now on every container action on this host routes through Portainer (no fallback to direct gRPC container CRUD exists). The fuse watchdog gives up after a deadline — failures show up in the Hosts page with a reason code.
What's next
- Architecture — the three-circle model, sub-container fleet, and database schema.
- Worker Onboarding — what every install env var means, the bootstrap call, fuse handshake, and persistence model.
- Operations — make targets, volume protocol, auth recovery, log locations.
- Observability — Prometheus, Grafana, Loki, Tempo, Pyroscope, and the host-onboarding counters.
- Configuration — every TOML option and
CONTEXTBAY_*env override.

