> ## Documentation Index
> Fetch the complete documentation index at: https://docs.airmux.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Separate services and scale gateways

> Run the webapp, control plane, and multiple data planes independently with distinct persistent state.

<Warning>
  This split deployment example is experimental.
</Warning>

The `docker-compose.split.yml` example runs Postgres, one control plane, the webapp proxy, and two gateways on one Docker host.

```bash theme={null}
docker build -t airmux:local .
docker compose -p airmux-split -f docker-compose.split.yml up -d --wait
airmux quickstart --url http://localhost:8080
```

Every service and short-lived startup job references `AIRMUX_IMAGE`, so pin that variable to one published digest for
coordinated deployments. The split stack follows the same [database and catalog startup sequence](/docs/deployment/docker#startup-and-database-changes)
as the default stack. Both gateways start after the control plane becomes healthy. The webapp proxy distributes `/inf/`
requests between them.

Install the [`airmux` CLI](/docs/reference/cli#installation) on the machine you use to manage the instance.

## Volume ownership

| Volume                   | Owner                                                  |
| ------------------------ | ------------------------------------------------------ |
| `split-pgdata`           | Postgres                                               |
| `runtime-credentials`    | Control plane writes; gateways read                    |
| `provider-secrets`       | Control plane writes; gateways read                    |
| `gateway-1`, `gateway-2` | One gateway each; identity, bundle cache, usage outbox |

Every additional gateway needs a new persistent state volume. Sharing one SQLite outbox or cloning a running gateway identity is invalid.

## Multi-host requirements

The checked-in split file demonstrates service boundaries, not a multi-host production topology. Across hosts, provide:

* Reachable Postgres for the control plane
* One secret store accessible to both planes, with the control plane able to write and data planes able to read
* A private authenticated control-plane URL for bundle polling, event ingestion, and heartbeat
* One persistent cache and outbox directory per gateway
* A streaming-capable load balancer with response buffering disabled

Set `AIRMUX_DATAPLANE_CONTROL_PLANE_URL` to the private control-plane address. Protect this path and its data-plane management key.

Keep one control-plane replica. Multiple control-plane replicas remain unsupported until initialization, asynchronous
bundle publication, and replica behavior are proven.

Do not use `docker compose --scale` for gateways. Each gateway needs an explicit service and its own identity, bundle
cache, and usage outbox volume.

## Move from `airmux` to split

The default and split Compose files use different named volumes. Migration requires a database dump plus a stopped copy
of `/state/runtime`, `/state/secrets`, and one gateway's `/state/data-plane`. Restore each into the corresponding split
volume before the first split startup.

<Warning>
  Do not start the split stack against a partial copy. Database metadata and provider secrets must move together.
</Warning>
