Skip to main content

Docker Compose

The Compose stack is the fastest way to run a production-like Manor AI instance on one host.

Core Services

These start on a plain docker compose up:

ServiceRole
webNginx-served React frontend. Listens on 18080 and proxies /api to the API container.
apiFastAPI application.
workerCelery control-plane worker with beat: schedules jobs, dispatches leases, runs ops monitoring. Consumes the default celery queue.
worker-workCelery work-queue worker: runs long agent plan steps on the work queue so long steps cannot stall scheduling.
postgresPostgreSQL 16 with pgvector (pgvector/pgvector:pg16).
redisCache, Celery broker, rate-limit backend, and JuiceFS metadata.
minioS3-compatible object storage.
juicefs-initOne-shot: formats and mounts entity filesystem storage, then exits.
ollama + ollama-initLocal embedding runtime. ollama-init preloads mxbai-embed-large on first boot so document RAG works out of the box; without the model, embedding calls fail and search degrades to text-only.
sandboxIsolated code-execution service managing per-run Docker containers.
sandbox-skill-imageBuilds the base image used by sandbox child containers, so docker compose up --build -d needs no separate prebuild step.
vaultLocal secret-encryption helper (Vault transit) for development-style deployments.

The two-worker split

worker and worker-work share one image and configuration; only the queue and concurrency differ. The control-plane worker (-Q celery, concurrency WORKER_CONTROL_CONCURRENCY, default 2) runs beat, lease dispatch, and monitoring. The work worker (-Q work, concurrency WORKER_WORK_CONCURRENCY, default 4) runs user-facing plan steps and has no beat and no Docker-socket access. They must be deployed together: beat only enqueues work; nothing consumes the work queue until worker-work is up.

Redis database allocation

One Redis instance serves four roles on separate logical databases:

DBUsed for
/0Application cache, rate limits, presence (REDIS_URL)
/1JuiceFS metadata (JUICEFS_META_URL)
/2Celery broker
/3Celery result backend

If you point Manor at an external Redis, keep these separated.

Optional Profiles

Enable extra services with --profile <name>:

ProfileServicesWhat it adds
nangonango-server, nango-postgresSelf-hosted Nango for 200+ SaaS OAuth integrations.
wechatwechat-runnerWeChat channel bridge. After start, open http://localhost:8801/qr.png and scan with WeChat to pair.
observabilityjaegerJaeger all-in-one for OpenTelemetry traces (enable with OTEL_ENABLED=true).
jimengjimeng-apiOptional Jimeng image-generation gateway.
docker compose --profile nango up -d

Common Commands

docker compose up --build -d
docker compose ps
docker compose logs api --tail=100
docker compose logs worker --tail=100
docker compose down

Rebuilding One Service

docker compose build api
docker compose up -d api worker worker-work

The api, worker, and worker-work services share the manor-api image — rebuild once, restart all three.

Health Checks

Use docker compose ps first; every long-running service defines a healthcheck, and dependent services wait for service_healthy. If a service is unhealthy, inspect logs and its dependencies:

docker compose logs postgres --tail=100
docker compose logs redis --tail=100
docker compose logs api --tail=200

The API also exposes GET /health, GET /health/ready, and GET /health/deep (checks database, Redis, and storage). The control-plane worker probes http://api:8000/health/deep from inside the Compose network as part of ops monitoring.

Startup order is enforced through dependencies: juicefs-init and ollama-init must complete before the API and workers start, so a slow first boot (image pulls, model download) is normal.

Persistent Data

Named volumes hold all state:

VolumeContents
pg_dataPostgreSQL data directory
redis_dataRedis persistence
minio_dataObject storage (uploads, JuiceFS data blocks)
ollama_dataDownloaded embedding models
wechat_runner_dataWeChat session state (profile wechat)
nango_pg_dataNango's own database (profile nango)

Do not delete volumes unless you intend to reset the deployment. Create backups before upgrades — see Backup and Restore.

Stopping Cleanly

The workers mount JuiceFS over FUSE and get a 30-second grace period on stop to drain in-flight tasks and flush cache to MinIO. Prefer docker compose stop / docker compose down over killing containers; a SIGKILL mid-flush can leave a wedged FUSE mount that requires manual cleanup.