Traefik and AdGuard Homelab Setup
Running Traefik v3 as the reverse proxy for all homelab Docker services alongside AdGuard Home for DNS. How the two connect and why this combo works well.
Status
live
Difficulty
intermediate
Time Required
40m
Last Tested
2026-06-01
Why This Combo
AdGuard Home handles DNS for my local network — ad and tracker blocking, custom local DNS records, and upstream resolver config. Traefik handles reverse proxying for all Docker services — subdomain routing, SSL termination, cert renewal.
They work together like this: AdGuard has a wildcard DNS rewrite pointing *.internal.yourdomain.com to the Traefik host IP. Traefik picks up the request and routes it to the right container based on Docker labels.
Every homelab service ends up at a clean https://service.internal.yourdomain.com with valid SSL. No messing with /etc/hosts, no self-signed cert warnings.
AdGuard Home Setup
Running AdGuard in Docker:
services:
adguard:
image: adguard/adguardhome
container_name: adguardhome
volumes:
- ./adguard/work:/opt/adguardhome/work
- ./adguard/conf:/opt/adguardhome/conf
ports:
- "53:53/udp"
- "53:53/tcp"
- "3000:3000"
restart: unless-stopped
After setup, go to Filters → DNS rewrites and add:
*.internal.yourdomain.com → 192.168.1.x
Replace 192.168.1.x with the IP of the server running Traefik. All subdomains on that pattern now resolve to Traefik.
Point your router's DNS at the AdGuard IP so all devices on the network use it.
Traefik Static Config
traefik.yml for the homelab internal setup:
api:
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
websecure:
address: ":443"
certificatesResolvers:
cloudflare:
acme:
email: your@email.com
storage: /letsencrypt/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
providers:
docker:
exposedByDefault: false
network: proxy
Using Cloudflare DNS challenge here means Traefik can issue wildcard certs for *.internal.yourdomain.com even though the domain isn't publicly accessible — the challenge is validated via DNS, not HTTP.
Traefik Compose
networks:
proxy:
external: true
services:
traefik:
image: traefik:v3
container_name: traefik
ports:
- "80:80"
- "443:443"
volumes:
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
restart: unless-stopped
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`traefik.internal.yourdomain.com`)
- traefik.http.routers.traefik.tls.certresolver=cloudflare
- traefik.http.routers.traefik.service=api@internal
Labelling Other Services
Any service on the proxy network gets a route with labels:
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.myapp.rule=Host(`myapp.internal.yourdomain.com`)
- traefik.http.routers.myapp.tls.certresolver=cloudflare
- traefik.http.services.myapp.loadbalancer.server.port=8080
Deploy the container and it shows up in the Traefik dashboard immediately.
The Full Flow
- Device queries DNS → AdGuard resolves
service.internal.yourdomain.com→ Traefik IP - Request hits Traefik on 443
- Traefik matches hostname to container via Docker labels
- SSL terminates with a valid wildcard cert (issued via Cloudflare DNS-01 challenge)
- Container receives the proxied request on its internal port
Clean local HTTPS for every service, no cert warnings, no manual DNS entries per service. Add a container with labels and it just works.