CFG-05 · Web servers

Reverse proxy config generator

One form, two outputs — a Caddyfile and an nginx server block, side by side, so switching servers doesn't mean relearning the syntax.

Almost always http even when the public side is HTTPS — TLS terminates at the proxy.

Caddyfile


  

Caddy provisions and renews TLS certificates automatically for any domain it can reach over the internet — nginx needs a separate ACME client (certbot, acme.sh) wired in, referenced here but not run for you.

Why the upstream protocol is almost always http, even for an HTTPS site

The reverse proxy is what the public internet talks HTTPS to — TLS terminates there, and the connection from the proxy to your actual application on the same machine or private network is typically plain HTTP. Setting the upstream to https is only correct if the backend app itself is independently serving TLS, which is uncommon behind a proxy.

The one nginx block people forget: WebSocket upgrade headers

nginx doesn't proxy WebSocket connections by default — without the Upgrade/Connection header pass-through, a WebSocket handshake fails silently behind an nginx reverse proxy while plain HTTP works fine, which is a confusing failure mode to debug blind. Caddy handles this automatically for any proxied connection, no extra config needed — one of the more common reasons people switch.

Further reading: Why I Replaced nginx with Caddy on Everything — the reasoning behind defaulting to Caddy for new projects, and where nginx still makes sense.
Do I need to do anything extra for Caddy to get an SSL certificate?

No, as long as the domain's DNS already points at the server and ports 80/443 are reachable from the internet — Caddy requests and renews a Let's Encrypt certificate automatically on first request to the domain, with no config beyond listing the domain name.

Why does my WebSocket connection work with Caddy but not nginx?

nginx requires explicit proxy_set_header Upgrade and Connection "upgrade" directives to pass a WebSocket handshake through to the backend — without them the initial HTTP request proxies fine but the protocol upgrade is dropped. Caddy passes WebSocket upgrades through by default with zero extra configuration.

What's the difference between proxy_pass and reverse_proxy?

proxy_pass is nginx's directive; reverse_proxy is Caddy's equivalent. They do the same job — forward the request to a backend and relay the response — but Caddy's version bundles sane defaults (WebSocket support, header forwarding) that nginx requires you to configure by hand.