What Is Traefik? Reverse Proxies Explained for Homelabs

What a reverse proxy does, why every homelab needs one, and how Traefik gives your self-hosted services clean HTTPS URLs with automatic certificates instead of a mess of IP addresses and ports.

On this page
  1. The problem a reverse proxy solves
  2. Why Traefik for a homelab
  3. The three pieces you need
  4. Static vs dynamic config: the one idea that clears up the confusion
  5. Routing services that don’t run in Docker
  6. The gotchas that actually bite
  7. Put Traefik in front

By the time your homelab is running a handful of services, you’re juggling a spreadsheet of IP addresses and port numbers: 10.0.0.20:3000 for Grafana, 10.0.0.21:8080 for something else, none of them on HTTPS. A reverse proxy fixes all of that. This post explains what a reverse proxy is, why Traefik is a great fit for homelabs, and how the pieces fit together. When you’re ready to build it, How to Set Up Traefik with Let’s Encrypt is the hands-on next post in this series.


The problem a reverse proxy solves

Without a reverse proxy, every service is a different IP:port, each with its own untrusted certificate warning (or no HTTPS at all). You memorise ports, browsers nag, and nothing has a real name.

Your browserhttps://*.homelab.lanTraefik:443 HTTPSone entry pointgrafana.homelab.lan10.0.0.20:3000wiki.homelab.lan10.0.0.21:3000vault.homelab.lan10.0.0.22:8080peira.dev

With a reverse proxy, everything lives behind one HTTPS endpoint and gets routed by name.


Why Traefik for a homelab

There are three common choices — all good, with different strengths:

  • Traefikdiscovers services automatically. Add a Docker container with a few labels and Traefik starts routing to it instantly, no config reload. Perfect when you add services often.
  • Nginx Proxy Manager — a friendly web GUI for people who’d rather click than edit YAML.
  • Caddy — the simplest static config file, HTTPS on by default.

Still deciding between them? Traefik vs Nginx Proxy Manager vs Caddy puts all three side by side.

Traefik’s edge is that dynamic discovery. Because your Docker apps declare their own routing via labels, the proxy config effectively maintains itself. That pairs naturally with a Docker host, which is why it’s the reverse proxy this series sets up.

Traefik Nginx Proxy Manager Caddy
How you configure it Docker labels + a small static file Web GUI (click through) One plain text Caddyfile
Auto-discovers services Yes — the standout feature No (add each in the UI) No (edit the file)
Automatic HTTPS Yes Yes Yes, on by default
Learning curve Steepest of the three Gentlest Gentle
Best when You add/remove services often You want zero YAML You want the simplest single file

None of these is wrong. If you rarely change your stack, Caddy or NPM will feel simpler. Traefik earns its slightly steeper start the day you realise you haven’t touched the proxy config in months despite adding five new services — each one wired itself up on first boot.

How auto-discovery looks

You don’t write a route for each app — the app describes itself. A container just adds labels like these and Traefik does the rest:

Traefik router labels on a Docker service

labels:
- "traefik.enable=true"
- "traefik.http.routers.wiki.rule=Host(`wiki.homelab.lan`)"
- "traefik.http.routers.wiki.tls.certresolver=letsencrypt"

The three pieces you need

To go from “IP and port” to https://service.homelab.lan, three things work together:

1Local DNS — resolve the names

Your devices need to know that wiki.homelab.lan points at the proxy. That’s exactly what Pi-hole local DNS records provide — point every service hostname at the Traefik host’s IP.

2Traefik — route the names

Traefik receives every request on port 443 and forwards it to the correct backend based on the Host() rule — the routing layer in the diagram above.

3Let's Encrypt — trust the certificates

Let’s Encrypt issues free, browser-trusted certificates so there are no more security warnings. Traefik requests and renews them automatically via its ACME/Let’s Encrypt integration.


Static vs dynamic config: the one idea that clears up the confusion

The single thing that trips up Traefik newcomers is that it reads two kinds of configuration, and they do different jobs:

  • Static config is read once, at startup (from traefik.yml or command-line flags). It defines the things that can’t change while Traefik runs: the entrypoints (the ports it listens on — :80 and :443), the providers it should watch (Docker, a config file, etc.), and the certificate resolvers (your Let’s Encrypt/ACME settings). Change any of these and Traefik must restart.
  • Dynamic config is read continuously, while Traefik runs: the routers (which hostname goes where), services (the backends), and middlewares (auth, redirects, rate limits). This is what the Docker labels produce, and Traefik applies changes here with no restart.

Once that clicks, everything else makes sense: you set up entrypoints and your Let’s Encrypt resolver once in the static file, then every new app just adds a router in the dynamic layer via labels.

http://homelab.lan:8080/dashboard/
The dashboard overview: your static entrypoints (the ports Traefik listens on) up top, and live counts of the dynamic routers, services, and middlewares below — the two halves of the config, side by side.
Always redirect HTTP to HTTPS at the entrypoint

Define the :443 HTTPS entrypoint and the :80 HTTP one in static config, then have the HTTP entrypoint permanently redirect to HTTPS. Do it once at the entrypoint and every current and future service is covered — you never think about plain-HTTP again.


Routing services that don’t run in Docker

On a Proxmox homelab, plenty of things you want a clean URL for aren’t Docker containers — a service in its own LXC, an appliance, a box on another host. Traefik’s label discovery only sees Docker, so for everything else you use the file provider: a small dynamic config file where you write the router and point it at an explicit backend address.

A file-provider route for a non-Docker service (dynamic/services.yml)

http:
routers:
  proxmox:
    rule: "Host(`pve.homelab.lan`)"
    service: proxmox
    tls:
      certResolver: letsencrypt
services:
  proxmox:
    loadBalancer:
      servers:
        - url: "https://10.0.0.10:8006"

Point the file provider at this file in static config and Traefik watches it live, just like it watches Docker. This is the piece most “Traefik is only for Docker” write-ups leave out — and it’s what lets one proxy front your entire lab, containers and LXCs alike.


The gotchas that actually bite

A short list of the things that cost people an evening:

  • Traefik and the app must share a Docker network. Auto-discovery only routes to containers Traefik can actually reach. A container on a different network is invisible — put them on a shared proxy network (or set traefik.docker.network on the service).
  • The Docker socket is a root-equivalent door. Traefik reads /var/run/docker.sock to discover containers — anything with that socket effectively controls the host. Mount it read-only, and for anything internet-facing put a socket proxy in front of it rather than handing Traefik the raw socket.
  • Internal-only names need the DNS challenge, not HTTP. Let’s Encrypt’s HTTP-01 challenge needs a publicly reachable port 80; a purely internal homelab.lan service can’t answer it. Use the DNS-01 challenge instead (and it’s the only way to get a wildcard cert like *.homelab.lan).
  • Secure the dashboard. Traefik’s dashboard is handy but must never be exposed with api.insecure=true on anything reachable from outside — put it behind the same HTTPS + auth as everything else.
  • A label typo fails silently. A malformed router label doesn’t error loudly — the route just never appears. When a service 404s, check the Traefik dashboard (it lists every router it loaded) and the container logs before touching anything else.
http://homelab.lan:8080/dashboard/#/http/routers
The Traefik dashboard's HTTP Routers view — every route Traefik has loaded, with its Host rule and status. This is the first place to look when a service won't resolve: if its router isn't here, the problem is your labels, not the app.

Put Traefik in front

Now that you understand the why, How to Set Up Traefik with Let’s Encrypt puts it into practice: deploying Traefik, wiring up automatic certificates, and routing your first service to a clean HTTPS URL. The official Traefik documentation is the best deeper reference.


Related posts:

Sources: Traefik documentation, Let’s Encrypt.

Comments

Comments are powered by GitHub Discussions — sign in with a GitHub account to join the conversation.