Skip to Content

Docker Deployment

TL;DR

Self-host CMDOP with the open-source deploy/compose.oss.yml Docker Compose file. It brings up the full stack on a clean box: PostgreSQL 16, Redis 7, a one-shot migrate step, the api_server (REST control plane) on :8000, the grpc_server (relay) on :50051, and a background worker. Configure two required secrets in .env, then terminate TLS at a reverse proxy (Caddy / Traefik / Nginx) in front. This is the recommended self-host path.

Docker Compose is the recommended way to run CMDOP yourself. The open-source server is a multi-process Python stack, and the shipped Compose file wires it all together.

How do I get started with Docker?

# Clone the open-source server git clone https://github.com/cmdop/cmdop-server cd cmdop-server # Copy the env template and set the two required secrets cp .env.example .env # Bring the stack up docker compose -f deploy/compose.oss.yml up --build

This starts: postgres, redis, migrate (one-shot, runs alembic upgrade head), api on :8000, grpc on :50051, and worker.

What does the Compose stack contain?

The shipped deploy/compose.oss.yml is intentionally minimal — no Traefik, no observability stack. Operators front it with their own gateway for TLS and metrics scraping. Its services:

services: postgres: # postgres:16-alpine — shared state, RLS-enforced redis: # redis:7-alpine — token cache, arq queue, output buffers migrate: # one-shot: alembic upgrade head, then exits api: # api_server — REST control plane on :8000 grpc: # grpc_server — the relay (agent bidi stream) on :50051 worker: # arq worker — cleanup crons + schedule executor # optional: jarvis (server-side AI), coturn (NAT traversal for tunnels)

api, grpc, and worker all share the same environment block and wait for migrate to complete successfully before starting.

What environment variables are needed?

Set these in .env. Only two are strictly required:

# Required — pick strong values POSTGRES_PASSWORD=$(openssl rand -hex 16) INTERNAL_SECRET=$(openssl rand -hex 32) # Optional — override published host ports (defaults shown) API_PORT=8000 GRPC_PORT=50051

POSTGRES_PASSWORD and INTERNAL_SECRET are docker-compose substitutions — Compose refuses to start without them. The server processes themselves read CMDOP_* variables (already set in the Compose env block): CMDOP_DATABASE_URL, CMDOP_ADMIN_DATABASE_URL, CMDOP_REDIS_URL, CMDOP_DB_MODE=standalone, CMDOP_INTERNAL_SECRET, CMDOP_ENVIRONMENT=oss. See the self-hosted guide and the server’s docs/configuration.md for the full set.

How do I create the first user?

Once api_server.bind appears in the logs:

docker compose -f deploy/compose.oss.yml exec api \ cmdop-admin user create --email [email protected]

It prints a bootstrap API key, shown only once. Save it.

How do I set up TLS with Traefik?

The OSS Compose ships plain HTTP / h2c by design. Put Traefik in front to terminate TLS — api_server over HTTP and grpc_server over h2c on the upstream:

http: routers: api: rule: "Host(`api.example.com`)" service: api tls: {certResolver: letsencrypt} grpc: rule: "Host(`grpc.example.com`)" service: grpc tls: {certResolver: letsencrypt} services: api: loadBalancer: servers: - url: "http://api:8000" grpc: loadBalancer: servers: - url: "h2c://grpc:50051" passHostHeader: true

gRPC needs h2c:// (HTTP/2 cleartext) on the upstream; Traefik handles the public-side TLS. Don’t expose the unauthenticated /metrics route on :8000 to the open internet.

How do I view logs?

# All services docker compose -f deploy/compose.oss.yml logs -f # A specific service docker compose -f deploy/compose.oss.yml logs -f grpc

Configure log rotation on the daemon or per-service logging: options as needed.

How do I check health?

# REST liveness / readiness curl http://localhost:8000/healthz/live curl http://localhost:8000/healthz/ready # → {"ok":true,"db":true,"redis":true} # gRPC reflection is enabled; health protocol is registered grpcurl -plaintext localhost:50051 grpc.health.v1.Health/Check

How do I back up the database?

# Dump docker compose -f deploy/compose.oss.yml exec postgres \ pg_dump -U cmdop_admin cmdop > backup.sql # Restore cat backup.sql | docker compose -f deploy/compose.oss.yml exec -T postgres \ psql -U cmdop_admin cmdop

How do I upgrade CMDOP?

# Pull / rebuild images docker compose -f deploy/compose.oss.yml pull docker compose -f deploy/compose.oss.yml build # Apply migrations (the migrate sidecar runs on every up) docker compose -f deploy/compose.oss.yml up -d migrate docker compose -f deploy/compose.oss.yml up -d # Verify RLS coverage just audit-rls

How do I troubleshoot Docker issues?

What if a container won’t start?

# Status + logs docker compose -f deploy/compose.oss.yml ps docker compose -f deploy/compose.oss.yml logs api # Validate the merged config docker compose -f deploy/compose.oss.yml config

How do I debug database connection issues?

# Postgres readiness from inside the network docker compose -f deploy/compose.oss.yml exec postgres \ pg_isready -U cmdop_admin -d cmdop
  • Self-Hosted — the open-source stack, config, and TLS in depth
  • Kubernetes — cluster deployment for scale
Last updated on