Caddy vs Traefik vs nginx Proxy Manager: reverse proxies for modern stacks
We migrated three production stacks across Caddy 2.8, Traefik v3.1, and nginx Proxy Manager 2.11. Here is where each one earns its keep and where it bites you.
If you run anything in Docker beyond a single container, you eventually need a reverse proxy in front of it. We spent the last month migrating three production stacks across Caddy 2.8, Traefik v3.1, and nginx Proxy Manager 2.11 to see where each one earns its keep — and where it bites you at 2am.
Configuration philosophy: three very different bets
Caddy bets on convention. A working HTTPS site with automatic Let’s Encrypt is roughly four lines of Caddyfile:
example.com { reverse_proxy localhost:3000}That’s it. ACME challenges, certificate renewal, HTTP→HTTPS redirect, sane HSTS defaults — all built in. The JSON API underneath is verbose, but you rarely touch it unless you’re building config programmatically.
Traefik bets on discovery. You don’t write routes by hand — you label containers, and Traefik watches Docker (or Kubernetes, or Consul) and rebuilds its routing table on every change:
labels: - "traefik.http.routers.api.rule=Host(`api.example.com`)" - "traefik.http.routers.api.tls.certresolver=letsencrypt"This feels magical the first time you redeploy a container and the proxy reconfigures itself. It feels less magical the third time you debug a label typo that caused a silent 404 with no log line pointing at the cause.
nginx Proxy Manager (NPM) bets on the GUI. It ships as one Docker image with a SQLite-backed admin UI on port 81. You click “Add Proxy Host”, paste a domain, pick a target, request a certificate. You never see an nginx.conf directly — it’s generated under the hood, and if you outgrow the UI you can extract it.
TLS, performance, and the things that wake you up
All three terminate TLS, but the failure modes differ.
Caddy’s ACME implementation is the strongest of the three. We’ve watched it survive Let’s Encrypt rate-limit slowdowns, DNS-01 hand-offs through Cloudflare, and OCSP stapling outages without intervention. The on-demand TLS feature — issuing certificates the first time a hostname is requested — is genuinely unique and useful if you’re running multi-tenant sites where you don’t know the domain names in advance.
Traefik does ACME well too, but its cert resolver config has more knobs (HTTP-01, TLS-ALPN-01, DNS-01 across roughly 120 providers) and more ways to misconfigure. We’ve seen Traefik deployed with caServer: acme-staging-v02.api.letsencrypt.org left over from a test, silently issuing staging certs for two weeks before a user complained that their browser was warning them.
NPM relies on the certbot binary inside its container. It works, but storage is the gotcha: the SQLite DB and /data/letsencrypt-acme-challenge directory must live on a persistent volume. We’ve seen forum threads from operators who put the container on ephemeral storage and re-issued certs on every redeploy until Let’s Encrypt rate-limited them for a week.
On raw performance, the gap is smaller than synthetic benchmarks suggest. nginx (and therefore NPM) edges out the others on a wrk test at around 85K req/s for a 1KB response on a 4-core box. Caddy lands around 60K req/s in the same test; Traefik around 50K. For 99% of self-hosted workloads this is irrelevant — your upstream app is the bottleneck long before the proxy is — but if you front a CDN origin or a hot internal API, the difference becomes measurable.
Picking one for your stack
The decision falls on three axes: who edits the config, how the upstream services come and go, and whether you want a vendor behind it.
Pick Caddy when: You want one human-readable file checked into Git, you’re running on a VM or bare metal more than ephemeral containers, and you value automatic HTTPS with zero tuning. The Caddyfile is the cleanest reverse proxy config we’ve seen — declarative, hierarchical, and short. The Cloudflare DNS module, S3 storage adapter, and on-demand TLS make it practical for multi-tenant SaaS as well. The plugin ecosystem (xcaddy) lets you build a custom binary with modules baked in, which beats Traefik’s plugin sandbox for performance.
Pick Traefik when: Your services are containerized and ephemeral. Traefik shines when containers come up and down on their own — Docker Swarm, Nomad, Kubernetes Ingress. The label-driven config means you never SSH to the proxy to add a route; you redeploy the service and the route appears. The built-in dashboard at :8080 is a real operational asset for figuring out which router matched which request. Middlewares (auth, rate-limit, headers, redirects) compose cleanly and are reusable across routers.
Pick nginx Proxy Manager when: You have non-technical co-admins, or you’re running a homelab and want to click “renew certificate” rather than write YAML. It’s also the easiest to hand off to a colleague who doesn’t want to learn a new config format. Just budget for the maintenance gap, put the data volume somewhere durable (a named Docker volume or a bind mount with backups), and don’t expose the admin UI on port 81 to the public internet — the default credentials are well-known and brute-forced constantly.
A practical wrinkle: all three have stable Docker images, but only Caddy and Traefik publish signed binaries you can drop onto a Debian or Alpine box without container plumbing. If you’re trying to escape Docker entirely, NPM stops being an option. Caddy’s apt repository is the lowest-friction install we’ve benchmarked — apt install caddy gives you a systemd service, log rotation, and a sample Caddyfile in under a minute.
FAQ
Can I run Caddy and Traefik together? +
Does nginx Proxy Manager work with Cloudflare Tunnel? +
Is the Caddy admin API safe to expose? +
Related tools
Beehiiv
Newsletter platform with built-in ad network and Boost referrals.
Try Beehiiv →
Webflow
Visual site builder with real CSS export and a CMS that scales.
Try Webflow →
Some links above are affiliate links. We may earn a commission if you sign up. See our disclosure for details.
Related reading
2026-05-28
K3s vs MicroK8s vs k0s: lightweight Kubernetes for small teams in 2026
Three lightweight Kubernetes distributions — K3s, MicroK8s, and k0s — compared on memory footprint, default add-ons, HA story, and which team shape each one actually fits. Operational opinions, not synthetic benchmarks.
2026-05-28
Coolify vs Dokku vs CapRover: self-host PaaS compared in 2026
We deployed the same three-service app to Coolify, Dokku, and CapRover on a $12/mo Hetzner box. Here's the architecture, memory footprint, and ops cost of each self-hosted PaaS in 2026.
2026-05-28
Why Block Handed Goose to the Linux Foundation: Agentic AI Goes Open
Block transferred its Goose agentic AI framework to the Linux Foundation. Here's what vendor-neutral governance means for teams choosing between LangChain, AutoGen, and Goose — and the lock-in risk most teams overlook.
2026-05-28
Clerk Auth Review: Authentication That Doesn't Make Developers Miserable
Hands-on Clerk review covering SDK quality, session management, multi-tenancy, webhooks, pricing, and how migration from Auth0 and NextAuth compares in real projects.
2026-05-27
Fly.io Edge Platform Review: Deploy Apps to 37 Regions With WireGuard Networking
We deployed a Go API and Next.js app across Fly.io's edge network, measuring cold starts, regional latency, and DX against Railway, Render, and Heroku — plus WireGuard networking and fly.toml deep-dive.
Get the best tools, weekly
One email every Friday. No spam, unsubscribe anytime.