Inkress ADRsarchitecture decisions
Overview / Infrastructure / networking
ADR 0018

centraprox is the single Caddy front proxy for all *.inkress.com hosts

AcceptedInfrastructure / networking

Context

The public brand lives on inkress.com and many subdomains — api, risk, auditor, hooks, checkout, dev, and more — but the apps behind them run as Coolify applications spread across different servers. Coolify ships its own per-server Traefik, but it runs in a mode where per-container labels/middleware are regenerated on every deploy (so custom edge config does not stick), and it cannot by itself present one coherent front for hostnames whose backends live on different servers. We needed a single, stable public edge for the brand domain, decoupled from which Coolify server/app currently backs each hostname.

Decision

Front every *.inkress.com hostname with one Caddy reverse proxy, centraprox, that terminates TLS and routes each hostname to its backing Coolify app.

  • Single edge for the brand domain. All inkress.com A records point at centraprox; it reverse-proxies each hostname to the appropriate upstream Coolify app (e.g. risk.inkress.com → the risk app's Coolify host), across whichever server the app runs on.
  • TLS at the edge. centraprox obtains and serves certificates (ACME via HTTP-01, fronted by Cloudflare in "full" mode) and stores them centrally, so certificate management for the brand domain is in one place rather than per app/server.
  • The proxy config is the routing source of truth. Which subdomain maps to which upstream is defined in centraprox's Caddy configuration, not in each app — so re-pointing a hostname to a different server/app is an edge config change, transparent to the apps.

Consequences

  • Positive: one place to add a hostname, manage certificates, and re-point traffic; app backends can move between Coolify servers without changing DNS, and Coolify's non-sticky per-container edge config is sidestepped.
  • Neutral / to revisit — the config is fragile. The running config is baked into the container image, and the operator's on-host config file is not bind-mounted, so a plain docker restart silently reverts to the image-baked config. This has caused outages twice (a restart dropped risk/auditor routes → Cloudflare 525; another restart silently completed a renderer cutover). Config changes must be applied by copying the file into the container and reloading, and the live config — not the operator's file — must be read before assuming what the proxy is doing.
  • Neutral / to revisit: centraprox is a single front-door dependency for the whole brand domain; the config file also carries secrets, so it is handled carefully and never printed.
  • Follow-ups: bind-mount the Caddy config so it survives restarts (the standing fix for the fragility above).

Alternatives considered

  • Rely on Coolify's per-app Traefik directly (DNS straight to each app): rejected — Coolify runs in readonly-labels mode so custom edge config (auth, rewrites) does not persist across deploys, and it cannot present one front for hostnames whose backends span servers; a central proxy gives a stable, server-independent edge.
  • A managed load balancer / Cloudflare-only routing: not adopted — Cloudflare already fronts DNS/TLS in "full" mode, but the origin still needs a single router that knows the per-hostname upstreams and can be re-pointed without touching each app; centraprox is that origin router.
← 0017 Commerce Postgres is VPC-only, split into a MAIN and a JOBS database 0019 The commerce platform is split into services by responsibility and trust zone →