Deployment Modes
Applies to: ChengOS v0.2.0+ | Last verified: 2026-09-25 | Source:
deploy/README.md,deploy/hybrid/,deploy/docker/,deploy/distributed/README.md,deploy/HARDENING.md
ChengOS supports three deployment shapes. They all read the same deploy/.env and are all driven
by chengos.sh, so the choice is about where processes run — not about learning three different
systems.
Choosing
| Native (hybrid) | Docker | Distributed | |
|---|---|---|---|
| Runs where | One host | One host, in containers | Two or more hosts |
| Needs Docker | No | Yes | No |
| Needs root | No, with managed-process | For Docker itself | For database install |
| Reproducible | Version-pinned archive | Version-pinned images | Version-pinned archive |
| Overhead | Lowest | Container layer | Lowest |
| Best for | Evaluation, single-machine, no-root hosts | Production, reproducible installs | Performance-sensitive, separated datastores |
If you are unsure: native to try it, Docker to run it. Reach for distributed only when you have a specific reason to separate the database host.
None of these is the single-user desktop app. ChengFlow Desktop (Windows .msi, Linux .deb
on the release page) embeds the engine and a database in one window, needs no chengos.sh, and
serves only the machine it runs on.
Native (hybrid)
The compiled cheng-api binary runs directly on the host and serves the web assets from the same
package. No image pull, no container runtime.
./chengos.sh install --mode native --db-install-mode managed-process --with api,ui,app,cli
./chengos.sh start
./chengos.sh status
The --db-install-mode choice is the one that matters:
| Mode | Databases run as | Needs sudo |
|---|---|---|
managed-process (default) | Unprivileged user processes inside the install directory | No |
system-service | apt-get-installed systemd services | Yes |
managed-process is what lets you install ChengOS on a host where you have no administrative
rights at all. system-service is the better choice when you want the databases managed by the
OS, restarting on boot with everything else.
Mode scripts live in deploy/hybrid/ (start.sh, stop.sh, status.sh, generate-env.sh).
Docker
Every service runs as a Compose container, with all four images pinned by a single
CHENGOS_VERSION.
./chengos.sh install --mode docker --with api,ui,app,cli
./chengos.sh start
Compose files in deploy/docker/:
| File | Purpose |
|---|---|
docker-compose.yml | The default full deployment |
docker-compose.binds.yml | Optional host-editable backend mounts |
docker-compose.remote.yml | Remote/VPS override for reverse-proxy use |
Remember that datastore hostnames change in this mode — postgres, redis, qdrant instead of
127.0.0.1. Full details in Docker deployment.
Distributed
Datastores on one host, the application on another, both native — Docker removed from the picture entirely to minimise runtime overhead.
- VPS A (database server): native PostgreSQL 18, Redis, and Qdrant.
- VPS B (app server): the compiled
cheng-apibinary.
On VPS A:
bash distributed/install_db.sh
The script prompts for VPS B's IP address, installs the databases natively, configures UFW, and
generates secure passwords. It writes vps_b_env.txt containing the exact .env configuration
VPS B needs.
On VPS B, unpack the release, copy vps_b_env.txt across, and start. The generated file is the
authoritative handoff between the two hosts — do not hand-transcribe connection strings, since a
mismatch between DATABASE_URL and the discrete DB_* variables produces failures that look
unrelated to configuration.
Shared resources (.env.example, skills/, bin/, runtime/, logs/) stay at the deploy/
root and are shared by all three modes.
Selecting modules
--with takes any subset of api,ui,app,cli:
| Selection | Result |
|---|---|
api,ui,app,cli | Everything |
api,ui | Editor only — no chat gateway, no terminal client |
api | Headless backend, driven by API or CLI from elsewhere |
cli | Just the terminal client, pointed at a remote server |
Operating an installation
The same commands work in every mode:
./chengos.sh start # start
./chengos.sh stop # stop (optionally including databases)
./chengos.sh restart # reload config and restart
./chengos.sh status # PIDs/containers, ports, version, health, live logs
./chengos.sh update # verified upgrade
./chengos.sh rollback # restore the previous release
./chengos.sh doctor # read-only check of what the host actually exposes
./chengos.sh uninstall # tear down, keeping or erasing data
Run ./chengos.sh with no arguments for the interactive bilingual menu.
Exposing an installation
In every mode the API listens on loopback and only the frontends are meant to be reached:
natively through BIND_ADDRESS=127.0.0.1, in Docker because Compose publishes every host port to
127.0.0.1. Nothing should face the internet except 80/443, held by one of:
| Edge | Inbound ports on the host | Notes |
|---|---|---|
| Cloudflare Tunnel | None | cloudflared connects out; recommended |
| Reverse proxy on the same host | 443 | The proxy reaches the frontends over loopback |
| Reverse proxy on another host | 443 on the proxy | The proxy-to-origin hop must be private or encrypted |
Native installs also need UI_BIND / APP_BIND narrowed, because they default to every
interface. Hardening a Public Deployment walks through each route;
./chengos.sh doctor verifies the result.
Next steps
- Docker deployment — the production path in detail.
- Upgrades and rollback — how versions move.
- Hardening a Public Deployment — before exposing any mode.
- Environment variable reference — every setting.