Docs/Deployment/Docker Compose Stack

Docker Compose Stack

The Compose deployment in deploy/compose/: a Lite tier for trying it or single-user use, and a Full tier for self-hosting on one server. Both run the same container images that releases publish to GHCR. This is also the stack the nightly E2E workflow builds and tests.

Rules that apply here too
Treat docker compose down on a shared or production stack as destructive: never run it unless someone explicitly asks for that exact command. To free ports, stop named services (scripts/vegaduta compose stop <service>). scripts/vegaduta down keeps volumes, but a stopped stack is still an outage.
Files
deploy/compose/lite.yml (Lite), docker-compose.yml (Full, with profiles), lite.build.yml and docker-compose.build.yml (build from source), docker-compose.domain.yml (public HTTPS through Caddy), docker-compose.ci.yml and docker-compose.local-llm.yml (CI trims and a mock OpenAI-compatible provider)
Config
Untracked deploy/compose/.env, generated by scripts/vegaduta secrets (random secrets, existing values never overwritten); the tracked template is deploy/compose/.env.example. Values are never reproduced in this documentation.
CLI
scripts/vegaduta (vegaduta.ps1 on Windows): up, down, status, logs, doctor, secrets, upgrade, make-admin, compose
Related
Keycloak Provisioning · Local development · Service Topology

1. Tiers

TierWhat you getContainersDocker memoryCommand
LiteAgents, chat, knowledge (optional RAG sidecar), graph memory5 (+1 with rag)6 GBscripts/vegaduta up --lite / make up-lite
FullLite plus platform-admin console, S3 object storage, PgBouncer and opt-in profiles10 core, up to 36 with all profiles12 GB core set, 24 GB+ with all profilesscripts/vegaduta up --full [--profile …] / make up PROFILE="temporal observability"

2. Service groups

GroupServices
Litepostgres (PostgreSQL 16 with pgvector and Apache AGE), valkey, keycloak (dev-file store), core (profiles security,knowledge,graph-memory,lite, local-disk file storage), web; profile rag adds the sidecar
Full core setpostgres, pgbouncer, valkey, seaweedfs (S3 gateway), keycloak, keycloak-db, sidecar, core, web, web-admin
Profile eventsredpanda (Kafka API; BSL-1.1, see NOTICE)
Profile temporaltemporal, temporal-postgresql, temporal-ui, core-worker (implies events)
Profile jobscore-jobs (implies temporal)
Profile observabilityprometheus, grafana, loki, promtail, alertmanager, valkey-exporter
Profile tracingLangfuse web and worker with their own postgres, clickhouse, valkey and S3
Profile voicelivekit, voice-agent
Other profilesrl (rl-trainer), code-intel (with a private docker-in-docker executor, privileged), builder (app-builder, implies code-intel), sandbox (tool-sandbox, mcp-stdio-runner)

Default local URLs: console http://localhost:3000, API http://localhost:8080, Keycloak http://localhost:8180, platform admin (Full) http://localhost:3001. Profiles need matching core settings (for example temporal sets WORKFLOW_EXECUTION_ENGINE=temporal); the CLI sets them, and with raw docker compose you set them in .env. Resource limits are set on every service and tuned with the *_MEM_LIMIT variables.

3. Domain overlay: what it changes

scripts/vegaduta up --full --domain example.com writes BASE_DOMAIN and the PUBLIC_* URLs into .env and adds docker-compose.domain.yml:

4. Operating it

TaskHow
Check the environmentscripts/vegaduta doctor (docker/compose versions, RAM, disk, ports, secrets, URLs); make doctor
Status and logsscripts/vegaduta status; scripts/vegaduta logs core
Build from sourcescripts/vegaduta up --lite --build, or make images for the Full tier
Upgradescripts/vegaduta upgrade --version X.Y.Z; pin VEGADUTA_VERSION in production
Grant platform adminscripts/vegaduta make-admin you@example.com
Raw composescripts/vegaduta compose <args> (right files and profiles)
BackupsSee Backup & Restore; back up .env with the data
Validate the compose filesmake compose-validate

5. Known failure modes

SymptomCause
Every API call returns 401 after loginToken issuer does not match what core expects. PUBLIC_AUTH_URL must be exactly the URL the browser uses for Keycloak; add other issuers to KEYCLOAK_ADDITIONAL_ISSUERS.
Login redirects to localhost on a serverPUBLIC_* still localhost: re-run scripts/vegaduta secrets --domain example.com, then up. For images built with --build, rebuild web.
"Invalid redirect URI"Realm clients were imported with other URLs; re-run scripts/vegaduta up, whose realm reconcile adds the derived URIs (it keeps entries you added by hand).
Signup succeeds but the console is empty or 500stenant_id attribute dropped: re-run the realm reconcile (scripts/vegaduta up or deploy/keycloak/reconcile-keycloak.sh).
Stored provider keys cannot be decryptedAPP_ENCRYPTION_KEY changed. Restore the original value; there is no other recovery.
core unhealthy on first startFirst boot runs all migrations; allow about 3 minutes, then read scripts/vegaduta logs core and check RAM with doctor.
up fails with "port is already allocated"Change *_HOST_PORT or BIND_ADDR in .env.
Workflows do not runEnable --profile events (or temporal); the workflow Spring profile needs Kafka.
Voice connects but no audioWebRTC media needs the UDP range LIVEKIT_RTC_PORT_RANGE_START-_END (default 50000-50100) reachable and LIVEKIT_BIND_ADDR=0.0.0.0; configure TURN for strict NATs.
Whole host crashes, all containers dieHost disk full. Build cache and old image layers accumulate; docker builder prune -f is safe for build cache only.

Evidence & references