DEV Community

pickuma
pickuma

Posted on • Originally published at pickuma.com

Caddy vs Nginx in 2026: When Automatic HTTPS Is Worth the Switch

You already know how to run Nginx. You wrote the server block, you pointed certbot at it, you added the cron renewal, and it has worked for years. So the honest question for 2026 is not "which web server is better" — it is whether Caddy removes enough of the annoying parts of running a reverse proxy to justify changing something that already works.

We ran both as the front door for a handful of small Go and Node services to find where the difference actually shows up. The short version: the gap is almost entirely about who manages your TLS certificates, not about raw speed. If you serve high static-file volume and have an existing certbot setup, Nginx is fine — leave it alone. If you spin up new subdomains often, run a homelab, or you keep forgetting to check why a cert expired, Caddy's automatic HTTPS is the feature that changes your week.

The real difference: who manages your certificates

Nginx does not manage certificates. You bolt that on. The common path is certbot, which obtains a Let's Encrypt cert, drops it on disk, and installs a renewal timer. Let's Encrypt certs last 90 days, so the timer matters — and when it silently breaks, you find out from a browser warning, not a log line you were watching.

Caddy treats TLS as part of the server, not an add-on. Point it at a domain that resolves to your box, and on first request it completes the ACME challenge, provisions a certificate (Let's Encrypt by default, ZeroSSL as fallback), serves it, and renews it well before expiry — Caddy starts renewal roughly a third of the way through the cert's lifetime rather than waiting until the last week. There is no certbot, no renewal cron, no separate fullchain.pem path to get wrong.

The config difference is just as stark. Here is a working HTTPS reverse proxy in Caddy:

example.com {
  reverse_proxy localhost:8080
}
Enter fullscreen mode Exit fullscreen mode

That is the whole Caddyfile. It obtains the cert, redirects HTTP to HTTPS, sets reasonable security headers, and enables HTTP/2 — none of which you spelled out. The equivalent Nginx config is a server block for port 80, a second block for port 443, explicit ssl_certificate and ssl_certificate_key paths, a location block with proxy_pass and the usual proxy_set_header lines, plus the certbot run that created the files those paths point to.

Caddy's default config is also HTTP/3-ready: it serves HTTP/3 (QUIC) out of the box once the cert is in place, with no extra directive. Nginx added HTTP/3 support in mainline 1.25, but you have to build with the QUIC module and enable it explicitly. For most small deployments this is a non-issue, but it is one more thing Caddy does without being asked.

Performance and config, measured honestly

The folklore is that Nginx is dramatically faster. In 2026, for the workloads most solo developers run, that framing is misleading.

Nginx is written in C and has spent two decades being optimized for serving static files and fanning out connections. For raw static throughput and the lowest possible memory footprint under tens of thousands of concurrent connections, it still leads, and that lead is real if you are running a CDN edge or a high-traffic static site. Caddy is written in Go, which means a garbage collector and a somewhat larger idle memory footprint — you will notice it on a 512MB VPS, not on anything bigger.

But most of us are not bottlenecked at the proxy. If Caddy or Nginx is sitting in front of an application server, your latency is dominated by the app, the database, and the network — not by which process terminated TLS. We saw no difference that mattered for proxied dynamic workloads; both servers added negligible overhead next to the application's own response time. The place Nginx wins decisively is when it is the workload: serving large volumes of static assets directly.

The config ergonomics cut the other way from performance. A Caddyfile is short enough to hold in your head; an Nginx config is a more powerful but less forgiving language, and most people copy-paste blocks they do not fully understand. That copy-paste habit is exactly where stale ssl_protocols lines and missing security headers creep in. Whichever server you pick, version-control the config and edit it in a real editor rather than nano-over-SSH — small syntax mistakes in either format take a site down.

When to switch (and when not to)

Switch to Caddy if you create new subdomains or services often, run a homelab or internal tooling where certificate management is pure overhead, or you have ever been burned by an expired cert. The automatic HTTPS removes an entire category of 2am incidents. It is also the better default for a brand-new project — there is no reason to hand-wire certbot in 2026 for a fresh deployment.

Stay on Nginx if it already works and you are not feeling the pain. "It runs and I never think about it" is a legitimate reason to change nothing. Stay also if you depend on a specific Nginx module, a third-party config generator, or you serve enough static traffic that the throughput and memory differences are load-bearing.

Caddy's automatic HTTPS depends on the domain resolving to your server and ports 80 and 443 being reachable from the public internet for the ACME challenge. On a locked-down network, behind a NAT you do not control, or before DNS has propagated, that first provisioning will fail. For internal-only services, use Caddy's internal CA or the DNS-01 challenge instead of expecting the default HTTP challenge to work.

You do not have to pick one globally, either. Plenty of setups run Caddy as the public-facing TLS terminator and reverse proxy, then hand traffic to Nginx or directly to app servers behind it. That lets you adopt automatic HTTPS without rewriting working internal config.


Originally published at pickuma.com. Subscribe to the RSS or follow @pickuma.bsky.social for new reviews.

Top comments (0)