# Coolify

> Deploy AI Gateway on Coolify with Docker Compose.

URL: https://boelabs.com/en/docs/ai-gateway/deploy-coolify
Language: English

[Coolify](https://coolify.io) deploys the repository's `docker/compose.yaml` directly.

## Deploy the Compose stack (recommended)

1. **New Resource → Docker Compose**, and point it at this repository (or paste the
   `docker/compose.yaml`).
2. Set the secrets as environment variables in the Coolify UI:
	- `MASTER_KEY` — `openssl rand -base64 48`
	- `ENCRYPTION_KEYRING` — e.g. `{"primary":"<openssl rand -hex 32>"}`
	- `ACTIVE_ENCRYPTION_KEY_ID` — `primary`
3. Deploy. The bundled `postgres` and `redis` run inside the stack's private network, and the
   gateway applies pending migrations at boot before coming up on internal port `4000`.
4. Configure domains only for long-running HTTP services:
   - **gateway** — for example `https://api.example.com:4000`
   - **dashboard** (optional) — its **own** domain: `https://dash.example.com:3001`

The dashboard is a separate product on a separate domain, so Coolify treats it like any other
service: a hostname, a container port, done. There is no path prefix to preserve.

It needs one setting: `GATEWAY_URL`, pointing at the gateway. Inside a Coolify stack that is the
service name — `http://gateway:4000` — which means the gateway needs no domain at all unless you
want the API published. [Operator dashboard → Check it](https://boelabs.com/docs/ai-gateway/dashboard#check-it) has a curl that
tells you whether the dashboard can reach it.

The port suffix in a Coolify domain selects the internal container port; TLS still uses the normal
public HTTPS port. Postgres and Redis must remain internal.

The base Compose file uses `expose`, not `ports`, so none of these services bypass Coolify's proxy or
publish a raw host port.

Because Postgres/Redis live on the Compose network and the gateway connects over plaintext
(`postgres://gateway:gateway@postgres:5432/ai_gateway`, `redis://redis:6379`), there is no TLS and
therefore no [Bun TLS issue](https://boelabs.com/docs/ai-gateway/troubleshooting).

## Deployments and downtime

Coolify does not perform rolling updates for Docker Compose resources — `docker compose up`
reconciles the services itself, stopping and starting each changed one. The gateway drains on
`SIGTERM` rather than dropping in-flight requests, but that only works if Coolify waits for it:
raise **Stop Grace Period** above `DRAIN_DELAY_MS + SHUTDOWN_TIMEOUT_MS`.

Compose is the right choice when you want the whole thing deployed as one unit. For rolling updates,
run each app as its own **Docker Image** resource and keep only Postgres and Redis in a stack —
[Rollouts](https://boelabs.com/docs/ai-gateway/rollouts) covers both topologies and the settings each one needs.

## Using Coolify's standalone database / Redis services

If you instead create Coolify's **standalone** Postgres and Redis services and connect the gateway to
them, Coolify exposes them with **self-signed** certificates, which Bun's TLS may reject (see
[Troubleshooting](https://boelabs.com/docs/ai-gateway/troubleshooting)). The simplest setup is to run both without TLS on the private
network:

- **Disable SSL on both services** — uncheck **Enable SSL** on the Postgres and Redis services.
- Connect via the **internal** hostname with `postgres://…` and `redis://…` (no `sslmode`, not
  `rediss://`). On Coolify's private network the link is protected by network isolation, not TLS.

<Callout>

Postgres also offers an `allow` SSL mode if you prefer to keep TLS available for other clients;
disabling SSL is the simplest path for the gateway.

</Callout>

Do not expose the database publicly in plaintext — see the
[security note](https://boelabs.com/docs/ai-gateway/troubleshooting#security-note). For an off-network database, prefer a
[managed provider with a public-CA certificate](https://boelabs.com/docs/ai-gateway/setup#managed-database-and-redis).

