Traefik vs Caddy vs Nginx Proxy Manager

Traefik vs Caddy vs Nginx Proxy Manager

Traefik vs Caddy vs Nginx Proxy Manager: Which Reverse Proxy Should You Use?

If you're running a homelab, you've probably hit that point where you have a dozen services running and you're tired of remembering port numbers. Is Jellyfin on 8096? Or was it 8920? And which one is Radarr again?

Enter the reverse proxy. Instead of accessing 192.168.1.50:8096, you can just go to jellyfin.home.lab. Throw in automatic SSL certificates and you've got yourself a proper setup.

But here's the thing: there are three major players in the homelab reverse proxy game, and they're all genuinely good. Traefik, Caddy, and Nginx Proxy Manager each have their own philosophy and sweet spots. Let's break down which one actually makes sense for your setup.

The Quick Comparison

Before we dive deep, here's the TL;DR:

  • Traefik: Best for Docker-heavy setups with lots of containers. Automatic discovery is magic.
  • Caddy: Best for simplicity and when you want things to "just work." Insanely easy SSL.
  • Nginx Proxy Manager: Best for beginners who want a GUI and don't want to touch config files.

Now let's actually dig into each one.

Traefik: The Docker Whisperer

Traefik was built with containers in mind. Its killer feature is automatic service discovery. You spin up a new Docker container with the right labels, and Traefik automatically creates routes for it. No config file editing. No restarts. It just works.

Basic Traefik Setup

Here's a minimal docker-compose setup to get Traefik running:

version: "3.8"
services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.dashboard.service=api@internal"

Then for any service you want to expose, just add labels:

services:
  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"

Traefik Pros

  • Automatic service discovery from Docker labels
  • No config reloads needed when adding services
  • Built-in dashboard for monitoring
  • Supports multiple backends (Docker, Kubernetes, file-based)
  • Middleware system for authentication, rate limiting, etc.
  • Active development and great documentation

Traefik Cons

  • Steeper learning curve than the others
  • Label syntax can get verbose and confusing
  • Overkill if you're not using Docker heavily
  • Debugging routing issues can be frustrating
  • Config via command flags or YAML or TOML... pick your poison

Caddy: The "It Just Works" Option

Caddy's whole pitch is simplicity. It automatically handles HTTPS with zero configuration. Seriously, zero. You point it at a domain and it figures out the certificates. The Caddyfile format is also refreshingly readable compared to nginx configs.

Basic Caddy Setup

Here's Caddy with Docker Compose:

version: "3.8"
services:
  caddy:
    image: caddy:2
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./data:/data
      - ./config:/config

And here's what a Caddyfile looks like:

# That's it. That's the whole config.
jellyfin.example.com {
    reverse_proxy jellyfin:8096
}

radarr.example.com {
    reverse_proxy radarr:7878
}

sonarr.example.com {
    reverse_proxy sonarr:8989
}

# Want basic auth? Easy.
private.example.com {
    basicauth {
        admin $2a$14$hashedpasswordhere
    }
    reverse_proxy internal-service:8080
}

That's genuinely it. Caddy handles SSL automatically. No certificate resolvers to configure. No ACME challenges to think about. It just does it.

Caddy Pros

  • Automatic HTTPS with zero config
  • Incredibly simple, readable config format
  • Single static binary (easy to deploy anywhere)
  • Great for non-Docker setups too
  • Built-in file server if you need it
  • Automatic certificate renewal

Caddy Cons

  • No automatic Docker discovery (need to edit Caddyfile for new services)
  • Less flexible middleware compared to Traefik
  • Smaller ecosystem and fewer tutorials
  • Config reload required when adding services
  • Less battle-tested than Nginx in production

Nginx Proxy Manager: The GUI Lover's Dream

Nginx Proxy Manager (NPM) wraps the venerable Nginx in a friendly web interface. If the thought of editing config files makes you uncomfortable, this is your answer. Point, click, SSL. Done.

Basic NPM Setup

version: "3.8"
services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    ports:
      - "80:80"
      - "443:443"
      - "81:81"  # Admin panel
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - DB_SQLITE_FILE=/data/database.sqlite

After starting it up, go to http://your-server:81 and log in with the default credentials (admin@example.com / changeme). From there, you click "Add Proxy Host" and fill in a form:

  • Domain: jellyfin.example.com
  • Forward hostname: jellyfin (or the IP)
  • Forward port: 8096
  • Toggle "SSL" and select "Request new certificate"

Click save. You're done. No YAML, no Caddyfile, no labels. Just a form.

NPM Pros

  • Full GUI, no config files needed
  • Perfect for beginners
  • Built on battle-tested Nginx
  • Easy SSL certificate management
  • Access lists and basic auth through the UI
  • Can still use custom Nginx configs if needed

NPM Cons

  • No automatic service discovery
  • GUI can feel clunky with many services
  • Less "infrastructure as code" friendly
  • Harder to version control your config
  • Another service to maintain and keep updated
  • Database dependency (even if just SQLite)

Performance: Does It Actually Matter?

Let's be real: for a homelab with maybe a few dozen users (probably just you), performance differences between these three are irrelevant. They can all handle way more traffic than your home internet connection can deliver.

That said, if you're curious: raw Nginx is the fastest, Caddy is close behind, and Traefik adds a tiny bit of overhead for its dynamic features. But we're talking microseconds. Don't pick based on performance unless you're running a serious production workload.

So Which One Should You Actually Use?

Here's my honest take based on different scenarios:

Use Traefik If:

  • You run lots of Docker containers and add/remove them frequently
  • You want to define routing alongside your services in docker-compose
  • You're comfortable with a learning curve for long-term gains
  • You want to learn skills that transfer to Kubernetes later
  • You like the idea of "infrastructure as code"

Use Caddy If:

  • You value simplicity above all else
  • You're running a mix of Docker and non-Docker services
  • You want the easiest possible SSL setup
  • You don't mind editing a config file occasionally
  • You want something lightweight that stays out of your way

Use Nginx Proxy Manager If:

  • You're new to reverse proxies and want training wheels
  • You hate config files and just want to click buttons
  • Your setup is relatively static (not constantly adding services)
  • You want to share admin access with someone less technical
  • You're migrating from a traditional Nginx setup

My Personal Pick

I've used all three extensively, and here's where I've landed: Traefik for my main homelab because I'm constantly spinning up containers to test things, and the automatic discovery is genuinely life-changing once you get it working.

But when I set up a simple VPS with just a few services? Caddy every time. The Caddyfile is so clean it almost feels like cheating.

And I still recommend Nginx Proxy Manager to friends who are just getting started. There's something to be said for being able to see everything in a nice GUI when you're learning.

Final Thoughts

The good news is you can't really go wrong here. All three are actively maintained, well-documented, and used by thousands of homelabbers. The "best" choice depends entirely on how you like to work.

My suggestion? Try the one that sounds most appealing. If it frustrates you, switch. The concepts are the same, and migrating between them isn't that painful.

Whatever you pick, you'll wonder how you ever lived without a reverse proxy. No more port numbers. No more browser SSL warnings. Just clean URLs and green padlocks.

Happy proxying!