Made the Docker Compose route turn-key for a real self-host, then stood the whole stack up and drove a live chat through it. - First-owner bootstrap (cm-auth::bootstrap_owner): a fresh local-auth install has no users and no signup route, so the initial Owner + workspace are provisioned ONCE from CLAWMATES_BOOTSTRAP_* env on first boot — idempotent, never clobbers an existing install (keys on 'any workspace exists'). Two real-Postgres tests (creates + signs in; second call is a no-op). Wired into server boot, guarded on a non-empty password - deploy/compose/README.md: full production bring-up — services, the security topology, every config knob, Anthropic vs local-LLM, the broker-key backup, ops, and TLS/SSE proxy notes - .env.example fleshed out (bootstrap, LLM, auth mode, OTLP); compose uses optional env_file so only the knobs you set are injected (unset options never override clawmates.toml with empty strings) - volume-init one-shot chowns the broker's named volumes so the non-root scratch broker can write its socket + generated master key Deployed locally and verified end to end: all 5 containers healthy, broker generated its key, server bootstrapped owner@…, login + /api/user/me work, and a real message streamed a live Anthropic response through the gateway. Captured screenshots of login, workspace home, chat, and the Computer panel. 166 Rust tests (+2 bootstrap). Co-Authored-By: Claude Fable 5 <[email protected]>
99 lines
3.7 KiB
Markdown
99 lines
3.7 KiB
Markdown
# Clawmates on Docker Compose
|
|
|
|
A single-node deployment of the whole platform — the same images the
|
|
Kubernetes/Helm path uses, with the same §15 security topology. This is
|
|
the air-gapped appliance route; it is equally usable as a simple self-host.
|
|
|
|
## What runs
|
|
|
|
| Service | Role |
|
|
|---|---|
|
|
| `postgres` | database (named volume `pgdata`) |
|
|
| `broker` | the secret broker — credentials never leave it; reachable only over a private socket volume shared with the server |
|
|
| `socket-proxy` | allow-listed Docker API so the server can spawn agent sandboxes and **nothing else** |
|
|
| `server` | API + streaming gateway + agent runtime + scheduler |
|
|
| `frontend` | the Next.js web app |
|
|
|
|
Networks `core`, `secrets_net`, `sandbox_net`, and `engine_net` are all
|
|
`internal: true`; only `edge` is published. Agent sandboxes run with no
|
|
network at all (egress is the browser container's alone).
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
cd deploy/compose
|
|
cp .env.example .env
|
|
# Edit .env: set POSTGRES_PASSWORD and CLAWMATES_BOOTSTRAP_OWNER_PASSWORD.
|
|
|
|
# Either build the images locally...
|
|
docker compose build
|
|
# ...or load them from a signed release bundle (see deploy/airgapped/install.sh).
|
|
|
|
docker compose up -d
|
|
```
|
|
|
|
The server **self-migrates** on boot and, if `CLAWMATES_BOOTSTRAP_OWNER_PASSWORD`
|
|
is set, provisions the first Owner + workspace once (a no-op on every later
|
|
boot). Then open:
|
|
|
|
- **App** → http://localhost:3000
|
|
- Sign in with `CLAWMATES_BOOTSTRAP_OWNER_EMAIL` / `…_PASSWORD`.
|
|
- API health → http://localhost:8080/healthz
|
|
|
|
## Configuration
|
|
|
|
Host- and secret-specific values come from `.env` (overlaid onto
|
|
`clawmates.toml` at runtime — `CLAWMATES_*` env always wins). The knobs:
|
|
|
|
| Concern | Where | Notes |
|
|
|---|---|---|
|
|
| DB password | `.env` `POSTGRES_PASSWORD` | also forms the server/broker DSN |
|
|
| Image tag | `.env` `CLAWMATES_VERSION` | `latest` after a local build, or a release version |
|
|
| First owner | `.env` `CLAWMATES_BOOTSTRAP_*` | password set = bootstrap on first boot |
|
|
| LLM | `clawmates.toml` `[llm]` | `openai_compat` (default, point `base_url` at vLLM/Ollama/llama.cpp) or `anthropic` (+ `ANTHROPIC_API_KEY` in `.env`) |
|
|
| Auth | `clawmates.toml` `[auth]` + `.env` `AUTH_MODE` | `local` (default) or `clerk` (see [docs/clerk.md](../../docs/clerk.md)) |
|
|
| Tracing | `.env` `CLAWMATES_TELEMETRY__OTLP_ENDPOINT` | unset = logs only, no egress |
|
|
|
|
### Using Anthropic instead of a local model
|
|
|
|
In `clawmates.toml`:
|
|
|
|
```toml
|
|
[llm]
|
|
provider = "anthropic"
|
|
model = "claude-sonnet-4-6"
|
|
```
|
|
|
|
and set `ANTHROPIC_API_KEY` in `.env`.
|
|
|
|
## The broker master key — back it up
|
|
|
|
On first boot the broker generates its encryption key into the `broker_key`
|
|
volume and logs a reminder. **Every stored credential is unrecoverable
|
|
without it.** Back it up:
|
|
|
|
```bash
|
|
docker compose cp broker:/etc/clawmates-broker/broker.key ./broker.key.backup
|
|
```
|
|
|
|
## Operations
|
|
|
|
```bash
|
|
docker compose ps # status
|
|
docker compose logs -f server # follow server logs
|
|
docker compose pull && docker compose up -d # upgrade to a new CLAWMATES_VERSION
|
|
docker compose down # stop (keeps volumes/data)
|
|
docker compose down -v # stop AND delete all data
|
|
```
|
|
|
|
## Production notes
|
|
|
|
- Put a TLS-terminating reverse proxy in front of ports 3000/8080; the SSE
|
|
gateway needs response buffering **off** (the Helm ingress sets this; nginx:
|
|
`proxy_buffering off;` with long read timeouts).
|
|
- `socket-proxy` mounts the Docker socket read-only and exposes only the
|
|
container lifecycle verbs — verified by `crates/cm-sandbox/tests/socket_proxy.rs`.
|
|
- The full bring-up is exercised end to end by `scripts/rehearse-install.sh`
|
|
(verify a signed bundle → `docker load` → `compose up` → assert the login
|
|
page serves), which also runs in the release pipeline.
|