networking
Caddy, because a lapsed cert is a solo problem
Caddy, because a lapsed cert is a solo problem
Several services need to be reachable through one server on 80/443 — the API, the web app, the admin panel, the operations console — but each runs as its own container on its own internal port. A reverse proxy terminates the incoming connection and routes each request to the right service by domain or path.
nginx is the long-standing default, extremely capable, and its config is verbose with HTTPS as a separate manual concern — traditionally Certbot plus a hand-wired renewal cron. Caddy's defining feature is automatic HTTPS: point it at a domain and it gets and renews a Let's Encrypt certificate on its own.
api.example.com {
reverse_proxy backend:2000
}
admin.example.com {
reverse_proxy admin:5002
}
That's close to the whole config for HTTPS-terminated routing to two services — genuinely shorter than the nginx-plus-Certbot equivalent.
Why it matters for one person
Every piece of infrastructure that needs periodic manual attention — renewing certs, remembering a cron job, debugging a lapsed one — is an ongoing cost, not a one-time setup. Automatic renewal removes a whole category of "something quietly expires and breaks production because nobody was watching," which matters most exactly when there's no team to catch it.
Internet → Cloudflare (CDN/DDoS/DNS) → Caddy (reverse proxy, TLS, routing) → Docker containers
Caddy knows which container handles which domain. Cloudflare sits further out — DNS, CDN caching, DDoS protection — before traffic reaches the server at all.
Caddy handles routing and TLS termination. It isn't rate limiting, isn't a WAF, isn't DDoS protection on its own — those live at the Cloudflare layer, or need adding explicitly. It's also where I moved a maintenance-mode check that had been living in client-side JS: a control that depends on the controlled client successfully making a network call to learn it should block itself is not a control.