← Dev log

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.