networking
When I'd still reach for nginx
When I'd still reach for nginx
nginx sits in front of the backend and frontend containers in production, routing 80/443 to the right internal service. Long-standing default, extremely mature, running on a meaningful fraction of the internet.
nginx:
profiles:
- production
docker compose up in normal dev never starts it — each service is reached directly on its own port during dev, and the proxy only comes into play for a production-style deployment. A reverse proxy is pure friction locally, one more thing to keep in sync and misconfigure while testing a feature, and it only earns its keep once unified routing, TLS termination and a single public entry point are actually needed.
nginx's config is powerful but verbose, and it has no built-in automatic HTTPS — certificates need Certbot wired in by hand, plus a renewal cron kept in sync with the config referencing the cert files. Real, ongoing operational work compared to Caddy, which does that automatically.
Still a completely reasonable choice despite that. Maturity and ubiquity are advantages on their own — nginx's behaviour and failure modes are extensively documented, and almost any ops person has seen a config before, which lowers the bar for whoever has to touch this deployment later. For a straightforward reverse-proxy-plus-TLS job without unusual requirements, the config verbosity is a one-time cost — once written and working, it mostly just runs.
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/ssl:/etc/nginx/ssl
Config and certificates live outside the image, mounted at runtime — so updating routing or rotating a certificate is editing a mounted file and reloading, not rebuilding the image. Worth keeping that pattern for any reverse proxy, regardless of tool.