Docker Deployment

Applies to: ChengOS v0.1.0+ | Last verified: 2026-08-12 | Source: deploy/README.md, deploy/docker/, deploy/.env.example

Docker mode runs every ChengOS service as a container under Docker Compose. It is the recommended production deployment: the release is pinned to exact image tags, the datastores are bound to loopback by default, and updates and rollbacks swap whole images rather than binaries on a host.

Prerequisites

Install and start

From the deploy/ directory:

./chengos.sh install --mode docker --with api,ui,app,cli
./chengos.sh start

The installer writes deploy/.env, generates the secrets that must not be left at their template values, and brings up the Compose project. Use ./chengos.sh stop to bring it down and ./chengos.sh status to inspect containers, ports, and live logs.

Pin the release

All four ChengOS images resolve their tag from one value in deploy/.env:

CHENGOS_VERSION=0.1.0

Because every image reads the same value, a Docker installation can never mix images from unrelated releases. latest is a first-install convenience only — it is not a reproducible production version and is never an update or rollback target. Pin an exact release before the installation carries anything you care about.

Per-service overrides exist for private registries and local development builds:

CHENGOS_API_IMAGE=registry.example.com/chengos/chengos:0.1.0
CHENGOS_UI_IMAGE=registry.example.com/chengos/chengos_ui:0.1.0
CHENGOS_APP_IMAGE=registry.example.com/chengos/chengos_app:0.1.0
CHENGOS_CLI_IMAGE=registry.example.com/chengos/chengos_cli:0.1.0

An override beats CHENGOS_VERSION for that one service. Be aware of the trade-off: while any override is set, coordinated Docker release updates are disabled, and chengos.sh status says so. Remove the overrides before you rely on chengos.sh update.

Connection strings differ from native mode

This is the single most common mistake when moving a .env between modes. Hostnames in DATABASE_URL, REDIS_URL, and QDRANT_URL depend on where the datastores actually run:

DeploymentHostname to use
Native / managed-process127.0.0.1
Dockerpostgres, redis, qdrant (the Compose service names)
DistributedYour external database host

Inside the Compose network, containers reach each other by service name. A DATABASE_URL pointing at 127.0.0.1 inside the API container resolves to the container itself, not to the database.

Networking and exposure

Compose already binds the API, PostgreSQL, Valkey, and Qdrant host ports to 127.0.0.1, so they are not reachable from outside the machine. Publish only your reverse proxy's 443 to the network and terminate TLS there.

One trap deserves its own warning: do not set BIND_ADDRESS=127.0.0.1 inside the API container. Loopback inside a container means that container only, so the UI container would no longer be able to reach the API over the Compose network. The correct value inside Docker is 0.0.0.0; isolation comes from the host port binding, not from the process bind address.

Public read-only demo mode

To expose an installation publicly as a read-only demo, set CHENG_DEMO_MODE=true. This is a fail-closed allowlist: only health checks, login/refresh/validate, workspace discovery, and workflow and node-definition reads stay available. Workflow saves and deletes, execution over REST and WebSocket, registration, password changes, credentials, files, documents, channels, MCP, and the scheduler all return 403 DEMO_MODE_RESTRICTED.

Demo mode cannot bootstrap itself, because creating the demo user is one of the operations it blocks. Initialize first, then switch:

# 1. Start normally on a trusted network
#    deploy/.env: CHENG_DEMO_MODE=false
./chengos.sh start
#    Create the fixed demo user and its default workspace through the UI
./chengos.sh stop

# 2. Set CHENG_DEMO_MODE=true in deploy/.env, then start again
./chengos.sh start

While demo mode is on, RUN_MIGRATIONS is ignored and the background workers do not start — scheduler, MCP recovery, channel polling and streaming, OAuth token refresh, code indexing, the file watcher, and cleanup jobs are all suppressed. To migrate, reset, or update demo data, remove the instance from public access, disable demo mode, do the maintenance, and re-enable it.

Updating and rolling back

chengos.sh update is upgrade-only and verifies before it touches a running system: it checks the SHA-256 checksum and signature, matches the archive's embedded VERSION against the selected release, stops the services, and swaps the images. The version record is written only after a post-update health check passes; a failure restores the previous package automatically.

chengos.sh rollback restores the most recent backed-up release and re-runs start plus health validation. It refuses when the installed release declares an irreversible database migration — one that drops or rewrites data the previous release cannot read — and prints the manual recovery procedure instead.

Next steps