What the reference stack is not
Every item below is indocker-compose.yaml or apps/api/app/main.py today:
Build real images
Drop the bind-mounts and the reload flag. Build tagged images, push them to a registry, and deploy those:--reload:
Reverse proxy and TLS
Put a proxy in front of both the API and the runtime. The runtime carries WebSocket audio, so the upgrade headers are mandatory:VOICE_SERVER_BASE_URL=https://voice.example.com before creating telephony agents — see Public voice URLs.
Tighten CORS
allow_origins=["*"] with credentials is the reference default. Restrict it to the origins that actually call the API, in apps/api/app/main.py, and rebuild.
Externalise the stores
The in-stackpostgres, redis, and minio are conveniences. In production prefer managed or dedicated instances with their own backups, monitoring, and upgrade path:
Scaling
Sizing
Start here and measure:
With cloud providers the runtime is mostly waiting on network, so it is rarely CPU-bound. Self-hosted models change the picture entirely — see Running on GPUs.
Secrets
Keep them out of.env on disk. Use your platform’s secret manager and inject at runtime.
Every variable the stack reads, with defaults and which service consumes it, is in Environment variables.
Backups
Back up all three durable stores together — a database restored without its recordings is inconsistent:PROVIDER_AUTH_ENCRYPTION_KEY with the backup — the credentials are useless without it. See Daily operations.
Upgrades
- Back up all three stores.
- Pull and build the new images.
- Restart the API first —
initialize_database()reconciles collections and indexes idempotently on startup. - Restart workers and the orchestrator.
- Drain and restart runtimes last, so live calls finish.
Checklist
- Images built and tagged; no bind-mounts, no
--reloadonapi - TLS on both the API and the runtime, with WebSocket upgrade
-
VOICE_SERVER_BASE_URLset to the public host before creating agents - CORS restricted
- All default passwords changed
- MinIO console not publicly reachable
-
SECRET_KEYidentical across API replicas -
PROVIDER_AUTH_ENCRYPTION_KEYbacked up - Exactly one campaign orchestrator
- Runtime behind session affinity
- Backups scheduled and a restore tested