0004 — Single-VPS Docker Compose + Caddy edge¶
Status: accepted (2026-07-23)
Context¶
Early-stage product, small team, modest traffic. Five hostnames need TLS, and the data stores must be unreachable from the public network. The sister Karat repository already runs exactly this shape in production and has proven it operable by one person.
Decision¶
Mirror the proven Karat topology on this platform's own VPS
(200.141.2.84): everything under Docker Compose
(deploy/docker-compose.yml), with Caddy 2 as the only container publishing
ports (80/443), terminating TLS via automatic Let's Encrypt and routing by
hostname (deploy/Caddyfile). Named networks separate concerns:
aim_edge (Caddy ↔ aim_api/aim_website/aim_admin_portal/
aim_docs; monitoring joins only for Grafana routing and scraping) and
aim_data (apps ↔ aim_postgres/aim_mongo/aim_redis, internal).
Uploaded static files live on the host at /opt/aim-store/static,
bind-mounted into aim_api, so they survive image replacement.
Consequences¶
- Zero-config TLS; adding a vhost is a Caddyfile block + DNS record.
- Single point of failure and a small-box ceiling; images are therefore built in CI, never on the server (ADR 0005).
- Compose files in git are the source of truth — deploy workflows overwrite the server copies on every run.
- Operational knowledge transfers 1:1 between Karat and Hub — same layout,
same commands, different
/optprefix.