Docker Compose
This deployment runs several Gateway replicas behind one TLS edge, sharing one Postgres that you operate. It is the production topology expressed in Compose: the same shape as the ECS and Kubernetes deployments, on a single host.
Overview
By the end you’ll have:
- Two or more Gateway containers, any of which can be restarted without downtime.
- A database you control, holding all state.
- One edge round-robining across the replicas, with no session affinity.
Choose this when you want production behaviour on one host - a staging environment, an on-premises box, or a deployment small enough not to need an orchestrator. If you already run ECS or Kubernetes, use those guides instead.
Before You Begin
You need:
- Docker with Compose.
- A Postgres 14+ database the containers can reach. Managed or your own - not the throwaway one from the quickstart.
- A Britive tenant and pool token. The token decides which gateway pool - and so which settings - the replicas run with.
Deploy
Download the Compose file
Download docker-compose.replicas.yaml - scalable Gateway replicas behind one TLS edge.
Save it as docker-compose.yaml in an empty directory.
Configure the container
Create a .env file beside the Compose file:
TENANT=acme
GATEWAY_POOL_TOKEN=<your-pool-token>
DATABASE_URL=postgresql://gateway:<password>@your-db-host:5432/gatewayThree values, and every replica gets the same three. There is no master secret to generate: the key that protects stored tokens and sessions is minted by the platform for the gateway pool and arrives with the pool’s settings, so replicas are guaranteed to agree on it.
Set the public base URL on the pool
In the Britive tenant portal, open the gateway pool your token belongs to and set Public base URL to the address clients actually use:
https://mcp-gateway.example.internalIf you are putting your own TLS terminator in front of this stack, that is its URL - not the edge inside the Compose file.
Start the replicas
docker compose up -d --scale gateway=3Compose’s DNS resolves gateway to every replica, and the edge load-balances across
all of them - adding or removing replicas needs no edge change.
Confirm they are healthy
docker compose ps
curl -sk https://localhost:8443/healthzVerify the Replicas Share State
This is the check that proves the deployment is actually shared-state rather than three independent Gateways.
Sign in
Open https://localhost:8443/ and sign in with Britive.
Restart a different replica
docker compose restart gatewayConfirm you are still signed in
Reload the console. You should remain signed in, and the audit history should be unchanged.
If you are signed out, the replicas are not sharing state. Check that every replica
carries the same GATEWAY_POOL_TOKEN and the same DATABASE_URL - a token belonging
to a different pool means a different encryption key, and a different database means
no shared sessions at all.
Rolling Restarts
Because every replica is stateless and shares one database, restarting them one at a time keeps the service up:
docker compose up -d --no-deps --scale gateway=3 gatewaySchema migrations run on startup, so a new image needs no separate migration step.
Wait for /healthz to pass before moving on.
Changing Settings
Everything beyond those three environment variables - audit sinks, rate limits, inspection, backend policy - is set on the gateway pool in the Britive tenant portal. There is no file to mount and nothing to redeploy: every replica picks a change up on its next sync, within five minutes by default.
The Gateway’s admin console has a read-only Settings tab showing what each container is actually running, which is where to look when a change does not appear to have landed. See Configuration.
Troubleshoot
| Symptom | Cause | Fix |
|---|---|---|
| A replica exits at startup | The tenant is unreachable, or the pool token was rejected | Fetching settings is fatal at startup by design. The log line names both causes; make doctor tells them apart. |
| Signed out when reloading | Replicas are not sharing state | Same GATEWAY_POOL_TOKEN and same DATABASE_URL on every replica. |
DATABASE_URL is required | Not set, or unreachable from the container | Check the value and that the host is routable from Docker. |
| Only one replica gets traffic | Scaled after the edge started | docker compose up -d again; the edge re-resolves the replicas. |
| OAuth fails at the callback | The pool’s Public base URL doesn’t match the browser’s address | Set it to the URL people actually open. |
| A settings change hasn’t taken effect | The next sync hasn’t run, or the last one failed | Check the console’s Settings tab: it flags stale settings and shows the values in force. |