Runbook: Docker Compose stack for ehxlabs.xyz
Short operator guide for the Compose + Caddy layout described in the roadmap (Deployment and public edge). Source compose file: ehx-web/docker-compose.yml (expects ehx-api as a sibling directory at ../ehx-api).
What runs
| Service | Role |
|---|---|
postgres | PostgreSQL 16 for API checkout session persistence (EHX_DATABASE_URL). |
api | FastAPI (uvicorn), port 8000 internal; bind-mount ../ehx-api when using --reload. |
web | Next.js production (standalone), port 3000 internal. |
caddy | TLS termination and reverse proxy to web and api. |
Prerequisites
- DNS A/AAAA for
ehxlabs.xyz(and optionallywww) pointing at the host before relying on ACME HTTP-01. - Repos cloned as siblings:
ehx-web/andehx-api/next to each other (compose build context uses../ehx-api). - Ports 80, 443, and 443/udp (QUIC) available on the host for Caddy.
First start
From ehx-web:
docker compose up -d --build
- Postgres must become healthy before
apistarts. - After code changes: rebuild the affected image, e.g.
docker compose build web && docker compose up -d web.
Networks and URLs
- Browser traffic: https://ehxlabs.xyz (Caddy terminates TLS).
- Next.js is configured with
NEXT_PUBLIC_API_URL=https://ehxlabs.xyzso browser calls use the same origin under/api/*(Caddy routes/api*to the API). - Server-side fetches from Next use
API_INTERNAL_URL=http://api:8000(do not loop through the public hostname from inside Docker unless you intend to).
Secrets and defaults
- Example compose uses development-grade Postgres credentials (
ehx/ehx). Replace with secrets management (env files, Docker secrets, or external secret store) for any shared environment. - Set
EHX_API_CORS_ORIGINSto match public origins (compose example:https://ehxlabs.xyz,https://docs.ehxlabs.xyz). - Docs subdomain (M5.11): DNS
docs.ehxlabs.xyz→ same host; buildehx-kb/website(Docusaurus) and mountwebsite/build→/srv/docusaurusin Caddy. See docs-site-docusaurus.md. No GitHub redirect. - Tune
EHX_CHECKOUT_SIMULATEper environment policy. - Admin edge guard (M5.10.10): set
EHX_ADMIN_ALLOW_CIDRSon thecaddyservice to allowlist operator IPs for/admin/*and admin API routes. See admin-edge-restrict.md.
TLS (ACME)
- Certificates are stored in Docker volumes
caddy_dataandcaddy_config(see compose file). - Use Let’s Encrypt staging while debugging to avoid rate limits; switch to production issuer when DNS and HTTP reachability are verified.
- Apply HSTS only after HTTPS redirects, asset URLs, and upstream paths are verified end-to-end (roadmap guidance).
Rollback
- Config only: fix
Caddyfileor env, thendocker compose up -d(recreates affected containers). - Bad deploy:
docker compose pull/ rebuild previous image tag if you tag releases; otherwisegit checkoutprevious revision in mounted API tree and restartapi, or rebuildwebfrom the previous commit. - Database: take backups before schema migrations; checkout session tables are application-owned—follow your retention and restore procedures.
Operational checks
- API:
GET /healththrough Caddy or directly onapi:8000from another container on the same network. - Web: root and
/checkout,/api/v1/...smoke paths per CI inehx-web/ehx-api. - Postgres:
pg_isready(compose already defines a healthcheck).
Related docs
- Public route map:
ehx-webdocs/ROUTES.md. - Product roadmap:
docs/EHX_Roadmap.md— Deployment and public edge. - Admin IP allowlist: admin-edge-restrict.md.
- Operator pricing, grants, promos: operator-pricing-trials-promos.md.