Files
openclaw-mission-control/docs/deployment/README.md
2026-02-11 10:08:36 +00:00

4.9 KiB
Raw Blame History

Deployment / Self-hosting (Docker Compose)

This guide covers how to self-host OpenClaw Mission Control using the repositorys compose.yml.

Scope

  • This is a dev-friendly self-host setup intended for local or single-host deployments.
  • For production hardening (TLS, backups, external Postgres, observability), see Production notes below.

What you get

When running Compose, you get:

  • Postgres database (persistent volume)
  • Backend API (FastAPI) on http://localhost:${BACKEND_PORT:-8000}
    • Health check: GET /healthz
  • Frontend UI (Next.js) on http://localhost:${FRONTEND_PORT:-3000}

Auth (Clerk) is required right now. You must configure Clerk keys for the frontend and backend (CLERK_SECRET_KEY).

Requirements

  • Docker Engine
  • Docker Compose v2 (docker compose ...)
  • Recommended: 4GB+ RAM (frontend build can be memory/CPU intensive)

Quick start (self-host)

From repo root:

cp .env.example .env

docker compose -f compose.yml --env-file .env up -d --build

Check containers:

docker compose -f compose.yml ps

Sanity checks

Backend health:

curl -f http://localhost:${BACKEND_PORT:-8000}/healthz

Frontend serving:

curl -I http://localhost:${FRONTEND_PORT:-3000}/

Compose overview

Services

compose.yml defines:

  • db (Postgres 16)
  • backend (FastAPI)
  • frontend (Next.js)

Ports

By default:

  • Postgres: 5432 (POSTGRES_PORT)
  • Backend: 8000 (BACKEND_PORT)
  • Frontend: 3000 (FRONTEND_PORT)

Ports are sourced from .env (passed via --env-file .env) and wired into compose.yml.

Volumes (data persistence)

Compose creates named volumes:

  • postgres_data → Postgres data directory

These persist across docker compose down.

Environment strategy

Root .env (Compose)

  • Copy the template: cp .env.example .env
  • Edit values as needed (ports, Clerk URLs/keys, etc.)

Compose is invoked with:

docker compose -f compose.yml --env-file .env ...

Backend env

The backend container loads ./backend/.env.example via env_file and then overrides the DB URL for container networking.

If you need backend customization, prefer creating a real backend/.env and updating compose to use it (optional improvement).

Frontend env

compose.yml intentionally does not load frontend/.env.example at runtime, because it may contain non-empty placeholders.

Instead, it supports an optional user-managed env file:

  • frontend/.env (not committed)

If present, Compose will load it.

Clerk (auth) notes

Clerk is currently required.

Frontend (Clerk keys)

Create frontend/.env (this file is not committed; compose.yml loads it if present):

# Frontend → Backend
NEXT_PUBLIC_API_URL=http://localhost:8000

# Frontend → Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY
CLERK_SECRET_KEY=YOUR_SECRET_KEY

# Optional (but recommended) redirects
NEXT_PUBLIC_CLERK_SIGN_IN_FORCE_REDIRECT_URL=/boards
NEXT_PUBLIC_CLERK_SIGN_UP_FORCE_REDIRECT_URL=/boards
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/boards
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/boards

Backend (auth)

The backend authenticates requests using the Clerk SDK and CLERK_SECRET_KEY (see backend/app/core/auth.py).

Create backend/.env (this file is not committed) with at least:

CLERK_SECRET_KEY=sk_test_your_real_key

# Optional tuning
CLERK_API_URL=https://api.clerk.com
CLERK_VERIFY_IAT=true
CLERK_LEEWAY=10.0

Then either:

  1. update compose.yml to load backend/.env (recommended), or
  2. pass the values via services.backend.environment.

Security: treat CLERK_SECRET_KEY like a password. Do not commit it.

Troubleshooting

1) Check container status

docker compose -f compose.yml ps

2) Tail logs

docker compose -f compose.yml --env-file .env logs -f --tail=200

3) Common issues

  • Docker permission denied (/var/run/docker.sock)
    • Ensure your user is in the docker group and your session picked it up (re-login), or use a root/sudo-capable host.
  • Frontend build fails because of missing public/
    • If the repo doesnt have frontend/public, the Dockerfile should not COPY public/.
  • Backend build fails looking for uv.lock
    • If backend build context is repo root, Dockerfile must copy backend/uv.lock not uv.lock.

Reset / start fresh

Safe (keeps volumes/data):

docker compose -f compose.yml --env-file .env down

Destructive (removes volumes; deletes Postgres data):

docker compose -f compose.yml --env-file .env down -v

Production notes (future)

If youre running this beyond local dev, consider:

  • Run Postgres as a managed service (or on a separate host)
  • Add TLS termination (reverse proxy)
  • Configure backups for Postgres volume
  • Set explicit resource limits and healthchecks
  • Pin image versions/tags and consider multi-arch builds