| title | Docker Compose |
|---|---|
| description | Run Codex Pooler with Docker Compose for a small self-hosted install. |
Docker Compose is the quickest self-host path for a laptop, lab server, or small single-node install. It runs the Codex Pooler release image with a local Postgres database and writes the release secrets into a private .env file.
Use it when you want a simple first install before moving to Kubernetes.
You need:
- Docker with Compose
- Git, if you are cloning the repository
openssl- A checked-out Codex Pooler repository
git clone https://github.com/icoretech/codex-pooler.git
cd codex-poolerFor every self-hosted install, choose a tagged stable release before creating
.env. Find the latest tagged stable release on GitHub Releases. The latest tag follows the most recently published release, but a version tag keeps the installation reproducible.
{/* x-release-please-start-version */}
export CODEX_POOLER_IMAGE=ghcr.io/icoretech/codex-pooler
export CODEX_POOLER_IMAGE_TAG=0.7.9
scripts/self-host/generate-env.sh{/* x-release-please-end */}
The generated .env contains release secrets, encryption roots, database settings, and image settings such as CODEX_POOLER_IMAGE and CODEX_POOLER_IMAGE_TAG. Keep it private. Don't commit it, paste it into tickets, or reuse values between public installs.
If you already generated .env, set CODEX_POOLER_IMAGE_TAG to the target
tagged stable release before docker compose pull. The latest tag follows the
most recently published release, but pinning a version tag makes the install
reproducible. If port 4000 is already in use, set CODEX_POOLER_HTTP_PORT
before generation or edit it in .env before starting the stack.
Pull and start the stack:
docker compose pull
docker compose up -dThe first run pulls the app and Postgres images, waits for Postgres health, runs the migration container, then starts the web app.
Open the local site:
http://localhost:4000
On the first visit, create the owner account at /bootstrap. After sign-in, start with /admin/pools.
To verify the first-run redirect from the shell:
curl -sS -D - -o /dev/null http://localhost:4000/ | grep -i '^location: /bootstrap'
curl -fsS http://localhost:4000/bootstrap/statusThe status endpoint should return {"status":"ok","bootstrap":"pending"} on a
fresh database. Use http://localhost:4000 for the default Compose stack even
if the Phoenix startup banner prints an endpoint URL such as
https://localhost; the Compose port mapping is the local URL to open. A
release image includes the OS timezone database used for operator timezone
display.
After the owner account exists:
- Create a Pool in
/admin/pools - Import or connect upstream accounts in
/admin/upstreams - Create a Pool API key in
/admin/api-keys - Point clients at one of the runtime base URLs
Codex backend compatibility route:
http://localhost:4000/backend-api/codex
OpenAI-compatible /v1 surface:
http://localhost:4000/v1
Operator MCP endpoint:
http://localhost:4000/mcp
Use a Pool API key for /backend-api and /v1. Use an operator MCP token for /mcp.
For a deployed host, replace http://localhost:4000 with https://codex-pooler.example.com.
Check that the web process responds before handing traffic to clients:
curl -fsS http://localhost:4000/healthz
curl -fsS http://localhost:4000/readyz/healthz confirms the endpoint is alive. /readyz is the safer check for accepting runtime traffic.
You can inspect the Compose stack with:
docker compose ps
docker compose logs -f appFor an existing Compose install, update the release image first: set
CODEX_POOLER_IMAGE_TAG in .env to the target tagged stable release. Keep a
versioned tag to make the selected upgrade reproducible. Then pull and restart
the stack:
docker compose pull
docker compose up -dThe Compose file includes a one-shot migrate service. It waits for Postgres,
runs the release migrations, imports the bundled pricing snapshot, and exits
before the app service starts. Normal app boot does not run migrations by
itself, so keep upgrades on this Compose path instead of starting only the app
container with docker run.
If you need to run migrations manually after fixing an environment or database issue, start the database and run the migration service once:
docker compose up -d db
docker compose run --rm migrate
docker compose up -d appWhen a migration fails, inspect the migration container logs before restarting traffic:
docker compose logs migrateStop the stack while keeping the database volume:
docker compose downStop the stack and remove the local database volume:
docker compose down -vOnly use down -v when you intentionally want to remove local Codex Pooler data.
Docker Compose is a simple self-host flow, not a high-availability topology. It is best for a single web process and local Postgres.
Backend websocket sessions keep live upstream websocket state inside the web app process. Don't scale Compose web replicas unless you also design clustering and owner-forwarding for that environment. If you need multiple web replicas, use the Helm chart and review the current chart requirements in that deployment plan.