Skip to main content

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

ServiceRole
postgresPostgreSQL 16 for API checkout session persistence (EHX_DATABASE_URL).
apiFastAPI (uvicorn), port 8000 internal; bind-mount ../ehx-api when using --reload.
webNext.js production (standalone), port 3000 internal.
caddyTLS termination and reverse proxy to web and api.

Prerequisites

  • DNS A/AAAA for ehxlabs.xyz (and optionally www) pointing at the host before relying on ACME HTTP-01.
  • Repos cloned as siblings: ehx-web/ and ehx-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 api starts.
  • 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.xyz so 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_ORIGINS to match public origins (compose example: https://ehxlabs.xyz,https://docs.ehxlabs.xyz).
  • Docs subdomain (M5.11): DNS docs.ehxlabs.xyz → same host; build ehx-kb/website (Docusaurus) and mount website/build/srv/docusaurus in Caddy. See docs-site-docusaurus.md. No GitHub redirect.
  • Tune EHX_CHECKOUT_SIMULATE per environment policy.
  • Admin edge guard (M5.10.10): set EHX_ADMIN_ALLOW_CIDRS on the caddy service to allowlist operator IPs for /admin/* and admin API routes. See admin-edge-restrict.md.

TLS (ACME)

  • Certificates are stored in Docker volumes caddy_data and caddy_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 Caddyfile or env, then docker compose up -d (recreates affected containers).
  • Bad deploy: docker compose pull / rebuild previous image tag if you tag releases; otherwise git checkout previous revision in mounted API tree and restart api, or rebuild web from 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 /health through Caddy or directly on api:8000 from another container on the same network.
  • Web: root and /checkout, /api/v1/... smoke paths per CI in ehx-web / ehx-api.
  • Postgres: pg_isready (compose already defines a healthcheck).