Choosing a reverse proxy is one of the first big decisions when self-hosting. It sits in front of all your services, handles SSL certificates, and routes traffic to the right container. Pick the wrong one and you’ll waste hours fighting configuration files.
This guide compares the three most popular options — Nginx Proxy Manager, Caddy, and Traefik — from a beginner’s perspective. By the end, you’ll know exactly which one to start with.
What Is a Reverse Proxy?
A reverse proxy accepts incoming web requests and forwards them to the correct backend service. Instead of exposing each service on a different port (like server:8080, server:3000), you access everything through clean URLs like photos.yourdomain.com or cloud.yourdomain.com.
Key benefits:
- Single entry point — only ports 80 and 443 need to be open
- Automatic SSL — free HTTPS certificates from Let’s Encrypt
- Clean URLs — subdomain or path-based routing
- Security — hide internal service ports from the internet
The Three Contenders
| Feature | Nginx Proxy Manager | Caddy | Traefik |
|---|---|---|---|
| Config style | Web GUI | Caddyfile (text) | Labels + YAML |
| SSL automation | ✅ Built-in | ✅ Built-in (best) | ✅ Built-in |
| Learning curve | Very low | Low | Medium |
| Docker integration | Manual setup | Manual setup | Native (labels) |
| Performance | Excellent | Excellent | Excellent |
| Advanced features | Limited | Moderate | Extensive |
| Community size | Large | Growing fast | Large |
Option 1: Nginx Proxy Manager (NPM)
Best for: Complete beginners who want a GUI.
Nginx Proxy Manager wraps the battle-tested Nginx web server in a friendly web interface. You click buttons instead of editing config files.
Setup with Docker Compose
services:
npm:
image: jc21/nginx-proxy-manager:latest
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "81:81" # Admin panel
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
Start it up:
docker compose up -d
Visit http://your-server-ip:81 and log in with the default credentials ([email protected] / changeme). You’ll be prompted to change them immediately.
Adding a Service
- Click Proxy Hosts → Add Proxy Host
- Enter your domain:
jellyfin.yourdomain.com - Set the forward hostname to the container name or IP
- Set the forward port (e.g.,
8096) - Click the SSL tab → select Request a new SSL Certificate
- Enable Force SSL and HTTP/2 Support
- Save
That’s it. Your service is now accessible over HTTPS.
Pros
- Zero config files — everything through the web UI
- Visual feedback — see all your proxy hosts at a glance
- Access lists — basic IP-based access control built in
- Stream support — can proxy TCP/UDP streams (for game servers, etc.)
Cons
- Manual setup — you add each service by hand
- No auto-discovery — won’t detect new Docker containers
- Limited customization — advanced Nginx configs require workarounds
- Extra port — the admin panel needs port 81
Option 2: Caddy
Best for: People comfortable with a text editor who want the simplest config files.
Caddy’s killer feature is automatic HTTPS by default. Just put a domain name in the config and Caddy handles certificates, renewals, redirects — everything. No extra configuration needed.
Setup with Docker Compose
services:
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./caddy_data:/data
- ./caddy_config:/config
The Caddyfile
Create a Caddyfile in the same directory:
That’s the entire configuration. Three lines per service. Caddy automatically:
- Obtains Let’s Encrypt certificates
- Redirects HTTP to HTTPS
- Renews certificates before they expire
- Enables HTTP/2 and HTTP/3
Adding Middleware
Need basic auth, rate limiting, or header manipulation? Caddy makes it clean:
Pros
- Simplest config syntax — readable by anyone
- HTTPS just works — no SSL tab, no checkboxes, no DNS challenge setup
- HTTP/3 support — modern protocol support out of the box
- Lightweight — single binary, small memory footprint
- Great documentation — clear, well-organized docs
Cons
- No web GUI — you edit a text file (though some third-party UIs exist)
- No auto-discovery — you manually add services to the Caddyfile
- Reload required — need to restart or reload after config changes
- Smaller plugin ecosystem — fewer extensions than Nginx or Traefik
Option 3: Traefik
Best for: Docker power users who want automatic service discovery.
Traefik’s superpower is Docker integration. Add labels to your containers and Traefik automatically creates routes — no config file changes needed. Spin up a new service and it’s instantly accessible.
Setup with Docker Compose
services:
traefik:
image: traefik:v3
container_name: traefik
restart: unless-stopped
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "[email protected]"
- "--certificatesresolvers.letsencrypt.acme.storage=/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
Adding a Service
Instead of editing Traefik’s config, you add labels to the service itself:
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
labels:
- "traefik.enable=true"
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.yourdomain.com`)"
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
When this container starts, Traefik automatically detects it and creates the route. When it stops, the route disappears. No manual intervention.
The Dashboard
Traefik includes a built-in dashboard showing all routers, services, and middleware. It’s read-only but incredibly useful for debugging.
Pros
- Auto-discovery — detects Docker containers automatically
- No config changes — labels on containers handle everything
- Built-in dashboard — visualize your routing setup
- Middleware system — powerful chain of request/response processing
- Kubernetes support — scales from homelab to production
Cons
- Steeper learning curve — label syntax is verbose and easy to get wrong
- Docker socket access — requires mounting the Docker socket (security concern)
- Verbose configuration — initial setup has more moving parts
- Debugging — when labels are wrong, errors can be cryptic
- Overkill for simple setups — lots of power you may not need
Head-to-Head Comparison
Ease of Setup
- Nginx Proxy Manager — deploy, open browser, click buttons
- Caddy — write 3 lines per service, deploy
- Traefik — longer initial config, but adding services is effortless after
SSL Experience
- Caddy — literally automatic, zero configuration
- Nginx Proxy Manager — checkbox in the GUI
- Traefik — requires certificate resolver setup
Adding New Services
- Traefik — add labels to docker-compose, done
- Caddy — add 3 lines to Caddyfile, reload
- Nginx Proxy Manager — open GUI, fill out form, save
Resource Usage
All three are lightweight. In typical homelab usage:
- Caddy: ~15-30MB RAM
- Traefik: ~30-50MB RAM
- Nginx Proxy Manager: ~50-100MB RAM (includes the GUI)
When Things Break
- Caddy: clear error messages, excellent docs
- Nginx Proxy Manager: GUI shows status, Nginx logs available
- Traefik: dashboard helps, but label typos can be silent failures
Which Should You Choose?
Choose Nginx Proxy Manager if:
- You’re brand new to self-hosting
- You prefer clicking over typing
- You want the fastest path to “it works”
- You don’t mind manually adding each service
Choose Caddy if:
- You’re comfortable editing text files
- You want the cleanest, most maintainable config
- You value simplicity and reliability
- You want HTTP/3 and modern TLS defaults
Choose Traefik if:
- You run many Docker containers and add new ones often
- You want zero-touch service discovery
- You plan to scale beyond a single server
- You’re comfortable with a steeper initial learning curve
My Recommendation for Beginners
Start with Caddy.
Here’s why: Nginx Proxy Manager is easier on day one, but Caddy is easier on day thirty. The Caddyfile is so simple that you’ll understand your entire setup at a glance. When something breaks, you’ll know exactly where to look.
If you’re running 10+ containers and constantly spinning up new ones, switch to Traefik later. The auto-discovery is genuinely magical once it’s set up.
And if you truly want zero command line, Nginx Proxy Manager will serve you well. There’s no shame in a GUI — it works great.
Migration Tips
Already using one and want to switch? The process is straightforward:
- Document your current routes — list every domain → service mapping
- Set up the new proxy alongside the old one (on different ports)
- Test each route using the new proxy
- Switch ports — stop the old proxy, change the new one to 80/443
- Verify SSL — certificates may need to be re-issued
All three use Let’s Encrypt, so certificate migration isn’t necessary — just let the new proxy request fresh ones.
Conclusion
There’s no wrong choice here. All three reverse proxies are reliable, well-maintained, and capable of handling a homelab. The “best” one is whichever matches your comfort level and workflow.
Start simple. You can always switch later. The important thing is getting your services behind HTTPS and accessible from clean URLs — any of these three will get you there.