# 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.

```bash
./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`.

```bash
./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](/docs/deploy-docker).

## 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-api` binary.

On VPS A:

```bash
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:

```bash
./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](/docs/deploy-hardening) walks through each route;
`./chengos.sh doctor` verifies the result.

## Next steps

- [Docker deployment](/docs/deploy-docker) — the production path in detail.
- [Upgrades and rollback](/docs/deploy-upgrade-rollback) — how versions move.
- [Hardening a Public Deployment](/docs/deploy-hardening) — before exposing any mode.
- [Environment variable reference](/docs/config-env-reference) — every setting.
