> ## Content Index
> Fetch the complete content index at: https://notes.d4rkcyber.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Traefik and AdGuard Homelab Setup
- URL: https://notes.d4rkcyber.com/traefik-and-adguard-homelab-setup/
- Published: 2026-06-02T00:00:00.000Z
- Updated: 2026-10-28T16:57:45.000Z
- Description: 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.
- Author: David Dami
- Tags: Infrastructure, traefik, adguard, dns, homelab, docker

## 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:

```yaml
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
    networks:
      - proxy

```

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:

```yaml
api:
  dashboard: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
  websecure:
    address: ":443"

certificatesResolvers:
  cloudflare:
    acme:
      email: you@yourdomain.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

```yaml
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:

```yaml
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

1. Device queries DNS → AdGuard resolves `service.internal.yourdomain.com` → Traefik IP
2. Request hits Traefik on 443
3. Traefik matches hostname to container via Docker labels
4. SSL terminates with a valid wildcard cert (issued via Cloudflare DNS-01 challenge)
5. 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.