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.
Related
Keep reading
Six Posts a Day, and the Scheduler That Learned to Say When
A social pipeline that published one Reel a day and nothing else, because per-format quotas were ceilings and nothing was asking for the other formats.
Seconds of Work, Hours of Residency
My morning briefing started failing. Ollama was up and returned HTTP 500, because a 21-second image render was still holding 6.6 GB of VRAM hours later.
What Deserves Attention Today
My homelab produces one verdict each morning: something needs you, or nothing does. Getting the second half honest was much harder than the first.
Keep going
Where to next?
Browse more technical writing, see the engineering case studies, or reach out directly.