Homelab Notes: Running Services Behind Traefik
My current homelab setup, why I moved off nginx-proxy, and what broke along the way.
Spent the weekend migrating my homelab reverse proxy from nginx-proxy to Traefik v3. Here's what I ended up with.
The stack
- Mini PC, Debian 12, Docker Compose
- Traefik v3 as the single entrypoint on 80/443
- Cloudflare origin certificates for public services
- Step-CA for internal
*.labcerts - ~18 services, from Home Assistant to a self-hosted Postgres
Why I moved
nginx-proxy was fine until I wanted per-service middleware (rate limiting, auth forwarding, compression). Adding it to nginx-proxy means templating; Traefik treats middleware as first-class labels.
The compose pattern I settled on
services:
paperless:
image: ghcr.io/paperless-ngx/paperless-ngx
labels:
- traefik.enable=true
- traefik.http.routers.paperless.rule=Host(\`paperless.lab\`)
- traefik.http.routers.paperless.entrypoints=websecure
- traefik.http.routers.paperless.tls=true
- traefik.http.routers.paperless.middlewares=forward-auth@file
- traefik.http.services.paperless.loadbalancer.server.port=8000
networks: [edge]
Every service gets those six labels. Middleware chains live in a shared dynamic.yml.
What broke
- Websockets needed explicit
passHostHeader=trueon the router. - One service shipped a healthcheck that returned 301. Traefik marked it unhealthy. Added
--providers.docker.useBindPortIP=falseand overrode the service port. - Cloudflare tunnel + Traefik is a footgun: double TLS termination works but you want
insecureSkipVerifyoff the internal hop.
Next
Wire Authentik as the forward-auth provider for everything internal. Kill the last plaintext basic-auth config.
Written by
Adrian Romo
Senior Backend Engineer building scalable Python APIs, AWS Lambda architectures, voice systems, and enterprise integrations.
Keep going
Where to next?
Browse more technical writing, see the engineering case studies, or reach out directly.