Traefik vs Nginx Proxy Manager: Reverse Proxies for the Rest of Us
One puts everything in labels, the other in a tidy web UI

Sooner or later, every homelab outgrows the colon. You start with 192.168.1.40:8989 for Sonarr, :3000 for Grafana, :8080 for the thing you can no longer remember, and you keep a sticky note of port numbers like it’s 2003. Then you want HTTPS, because typing passwords over plain HTTP makes your skin crawl, and suddenly you need a reverse proxy: one thing on ports 80 and 443 that looks at the hostname and routes the request to the right backend, terminating TLS on the way through.
Two tools dominate the self-hosting world for this job, and they could not be more different in temperament. Traefik wants you to describe your routing in code and labels. Nginx Proxy Manager (NPM) wants you to click a few buttons and be done. Picking between them is mostly a question of what kind of person you are.
1 What a reverse proxy actually does
The mechanics are simple. A request for grafana.example.com arrives on port 443. The proxy reads the SNI hostname, matches it against a rule, decrypts the TLS, and forwards the plain request to http://grafana:3000 on your internal network. The response goes back the same way. You get one public entry point, automatic Let’s Encrypt certificates, and clean URLs with no ports in sight.
The differences are entirely in how you tell the proxy about your services.
2 Nginx Proxy Manager: the friendly front door
NPM is exactly what it says: a web UI bolted onto nginx, with a database tracking your “proxy hosts.” You spin it up, log in, click Add Proxy Host, type the domain, type the internal address and port, tick the SSL box, and request a certificate. It works, and for a lot of people that’s the whole story.
services:
npm:
image: jc21/nginx-proxy-manager:latest
ports:
- "80:80"
- "443:443"
- "81:81" # admin UI
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencryptThe appeal is obvious. There’s nothing to learn, the certificate management is point-and-click, and you can hand it to someone who has never seen an nginx config and they’ll be fine. The cost is that your routing lives in a SQLite database inside a container. It’s not in Git, it’s not reproducible, and the day that volume corrupts you’re recreating every host by hand from memory. The custom-config escape hatch exists but is fiddly, and NPM has historically been slow to ship newer nginx and security patches.
3 Traefik: routing as configuration
Traefik takes the opposite stance: it discovers your services automatically from Docker labels, so adding a route means adding labels to the container you’re already deploying. No separate step, no UI, no database.
services:
grafana:
image: grafana/grafana:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.example.com`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls.certresolver=le"The router watches the Docker socket, sees that label, and the route exists the moment the container starts. Bring the container down and the route vanishes. Your entire edge configuration lives in the same compose files as your apps, which means it’s in version control alongside everything else.
The price is a steeper start. Traefik’s static-versus-dynamic config split confuses everyone at first, the v1-to-v2 migration broke a lot of old tutorials, and a stray backtick in a Host() rule will have you staring at a 404 wondering what you broke. The dashboard shows you routers and services but you don’t configure through it. When it clicks, though, it’s genuinely elegant — middlewares for auth, rate limiting and headers chain together cleanly, and adding a new service is a four-line copy-paste.
4 The honest trade-offs
- Learning curve: NPM is approachable in five minutes; Traefik takes an afternoon and a few swear words.
- Reproducibility: Traefik config is in your compose files and Git. NPM hides it in a database.
- Dynamic routing: Traefik picks up new containers automatically. NPM needs a manual entry each time.
- Middleware: Traefik chains auth, rate limits and redirects natively. NPM does basics, then you’re hand-editing nginx snippets.
- Maintenance: NPM has lagged on updates; Traefik moves fast, occasionally fast enough to break your config on a major bump.
5 The verdict
If you spin up a service or two a month, want HTTPS without a tutorial, and would rather click than read documentation, Nginx Proxy Manager is the right call and there’s no shame in it. It does the job and gets out of the way.
If your homelab is Docker Compose all the way down, you keep your stack in Git, and you want adding a service to mean adding four labels rather than visiting a UI, Traefik is the better long-term home. I run it precisely because routes appear and disappear with the containers themselves, and my edge configuration is something I can git diff rather than something I have to remember.
Pick the one that matches how you already work. The request still ends up at the right backend either way — the only question is whether you’d rather describe that in a database or in code.




