Behind the reference proxy the API runs in trusted-proxy mode, but
compose.proxy.yaml gives those variables to `api` only. The documented
Doctor command runs as `migrate`, so it validated an empty
configuration and reported "Direct client-address mode" for an
installation that trusts its proxy. That is what the first production
installation saw.
Fails today:
- deploy.test.ts: the proxy overlay gives `migrate` no client-address
environment;
- doctor.test.ts: the check does not say whose configuration it read;
- smoke-deploy.sh: Doctor through the proxy overlay does not report
trusted-proxy mode (Docker).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Implement ADR 0044's reference deployment as a base Compose file plus
overlays, so an installation that already runs a proxy can use the base
alone.
- compose.yaml: api, postgres, object-storage, and the operator-only
migrate (profile ops, plan by default). No published port. api and
migrate run init, read-only, tmpfs /tmp, cap_drop ALL,
no-new-privileges. postgres is only on the internal data network.
- TLS everywhere from one installation-private CA: PostgreSQL TLS 1.3
only, with pg_hba rejecting every non-TLS connection, and the API on
verify-full via EKKLESIA_DATABASE_CA (PEM text). SeaweedFS serves S3
over HTTPS (ADR 0030 requires https in production), trusted by the
API through NODE_EXTRA_CA_CERTS. No Core change.
- compose.proxy.yaml + Caddyfile.example: Caddy pinned by digest, ACME
HTTP-01 (DNS-01 documented), routes /, /api/*, /display/*, /assets/*
to api and refuses everything else; the storage hostname preserves
Host. The API trusts exactly the proxy's fixed /32 on an edge network
whose dynamic range excludes the fixed addresses; Caddy overwrites
X-Forwarded-For and strips caller-supplied forwarding headers.
- compose.tunnel.yaml: cloudflared pinned by digest, token from its own
env file; Caddy honors CF-Connecting-IP only from its fixed address.
- Four per-service root-owned env files, examples with no values;
scripts/init-tls.sh (idempotent, never overwrites a key) and
scripts/gen-secrets.sh (prints only).
- CI: pnpm deploy:config in ci:verify for all three combinations, and a
deploy-smoke job (scripts/smoke-deploy.sh) proving readiness, the
Dashboard, signed storage delivery, the client-address chain, initial
owner sign-in/out, verify-full database TLS, and Doctor through the
proxy, against disposable services. tests/deploy.test.ts pins the
structural guarantees.
- ADR 0044 (still Proposed) amended to match: API-to-storage HTTPS,
DNS-01 needs a custom Caddy build and tunnel-only needs DNS-01, the
tunnel's origin TLS settings live in the Cloudflare dashboard, port
80 serves HTTP-01, and secrets are one env file per service.
Co-Authored-By: Claude Opus 5.5 <[email protected]>