Traefik, pihole, DoH, and some heavy handedness……..

[EDIT] This was recovered due to a massive db crash and losing a couple of years worth of articles. Dates are mismatching. [EDIT]

Hey all..
Lately i have converted my Docker Swarm setup to use Traefik as a proxy due to some complex configurations i wanted to test and implement.

In this article i will give a basic walk through on:
– How i configured Traefik 2.10
– The pi-Hole unbound configuration i went with
– The Cloudflared config i used for DoH
– Also, the Docker Swarm compose files i came up with
Is all of this correct ? : probably not.
Does it work for me and my setup ? : yup.
Will changes be done in the future ? : probably.
Let’s start with the Traefik setup since everything relies on this.


Traefik

Let us start with the compose file used :


version: "3.9"
services:
  traefik:
    image: traefik:v2.10
    deploy:
      placement:
        constraints:
          - node.role == manager
      mode: global
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.dashboard.entrypoints=web"
        - "traefik.http.routers.dashboard.middlewares=dashboard"
        - "traefik.http.routers.dashboard.rule=Host(`traefik.local`,`traefik`)"
        - "traefik.http.routers.dashboard.service=api@internal"
        - "traefik.http.routers.dashboard.tls=false"
        - "traefik.http.services.dashboard.loadbalancer.server.port=8080"
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host
      - 53:53/tcp
      - 53:53/udp
    networks:
      - traefik-public
    environment:
      - TZ=UTC
    volumes:
      - "/traefik/traefik.yaml:/etc/traefik/traefik.yaml"
      - "/traefik/htpasswd:/etc/traefik/htpasswd"
      - "/traefik/conf/:/etc/traefik/conf/"
      - "/traefik/letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "/etc/localtime:/etc/localtime:ro"
networks:
  traefik-public:
    external: true
  default:
    driver: overlay
    attachable: true

Some explanations:
– section (labels:) configures the traefik dashboard to addresses http://traefik.local/ && http://traefik/ (image of the dashboard later in article). For these to work make sure you either add to your hostfile / pihole local dns those addresses and the address of the swarm / traefik host.
– section (ports:) exposes ports 80 && 443 to the host and port 53 on the system.
– section (volumes:) maps where we will keep the Traefik config files (later in the article) locally for mounting to the container. Key file here is the “traefik.yaml” file (later in the article).
Now here is the traefik.yaml file that is critical for traefik to operate as desired (this config is decently self explanatory):


global:
  checkNewVersion: false
  sendAnonymousUsage: false
api:
  dashboard: true
  insecure: false
entrypoints:
  web:
    address: ":80"
    forwardedHeaders:
      insecure: true
  websecure:
    address: ":443"
    forwardedHeaders:
      insecure: true
  dns:
    address: ":53"
  udpdns:
    address: ":53/udp"
log:
  level: INFO
  format: common
accessLog:
  filePath: /log/traefik-access.log
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedbydefault: false
    network: traefik-public
    swarmModeRefreshSeconds: 15
    swarmmode: true
    watch: true
  file:
    directory: /etc/traefik/conf
    watch: true
  providersThrottleDuration: 10
certificatesresolvers:
  leresolver:
    acme:
      caserver: https://acme-v02.api.letsencrypt.org/directory
      email: foo@bar.baz
      keyType: EC384
      preferredChain: 'ISRG Root X1'
      storage: /letsencrypt
      tlschallenge: true

Now the Pi-Hole && Cloudflared bits

For this section we are using the pihole unbound image from here and the Cloudflared image from here.
Below is the compose file with some explanations :


version: "3.9"
services:
  pihole:
    hostname: "{{.Node.Hostname}}"
    image: ghcr.io/mariomare22/docker-pihole-unbound:latest
    ##image: cbcrowe/pihole-unbound:latest
    deploy:
      placement:
        constraints:
          - node.role == manager
      mode: replicated
      replicas: 1
      labels:
        - "traefik.enable=true"
        # dashboard
        - "traefik.http.middlewares.piholeweb.addprefix.prefix=/admin"
        - "traefik.http.routers.piholeweb.entrypoints=web"
        - "traefik.http.routers.piholeweb.rule=Host(`pihole.local`,`pihole`)"
        - "traefik.http.routers.piholeweb.service=piholeweb"
        - "traefik.http.services.piholeweb.loadbalancer.server.port=80"
        # 53/udp
        - "traefik.udp.routers.pihole-dns-udp.entrypoints=udpdns"
        - "traefik.udp.routers.pihole-dns-udp.service=pihole-dns-udp"
        - "traefik.udp.services.pihole-dns-udp.loadbalancer.server.port=53"
        # 53/tcp
        - "traefik.tcp.routers.pihole-dns-tcp.entrypoints=dns"
        - "traefik.tcp.routers.pihole-dns-tcp.rule=HostSNI(`*`)"
        - "traefik.tcp.routers.pihole-dns-tcp.service=pihole-dns-tcp"
        - "traefik.tcp.services.pihole-dns-tcp.loadbalancer.server.port=53"
    ports:
      - 0.0.0.0:853:853
    networks:
      - traefik-public
    dns:
      - 127.0.0.1
      - 4.2.2.6
    environment:
      - DNSMASQ_LISTENING=all
      - DNSSEC=true
      - DNS_BOGUS_PRIV=true
      - DNS_FQDN_REQUIRED=true
      - FTLCONF_LOCAL_IPV4=192.168.100.41
      - FTLCONF_RATE_LIMIT=3000/60
      - FTLCONF_REPLY_ADDR4=192.168.100.41
      - FTLCONF_REPLY_ADDR6=fd01:470:88f9:100::41
      - FTL_CMD=debug
      - PGID=1000
      #- PIHOLE_DNS_=127.0.0.1#5335;::1#5335;192.168.100.41#5335;fd01:470:88f9:100::41#5335
      - PIHOLE_DNS_=192.168.100.41#5054;127.0.0.1#5335
      - PUID=1000
      - REV_SERVER=true
      - REV_SERVER_CIDR=192.168.0.0/16
      - REV_SERVER_TARGET=192.168.100.11
      - SKIPGRAVITYONBOOT=true
      - TEMPERATUREUNIT=f
      - TZ=UTC
      - VIRTUAL_HOST=pihole.local
      - WEBPASSWORD_FILE=/run/secrets/pihole_webpw
      - WEBTHEME=default-darker
      - WEBUIBOXEDLAYOUT=boxed
    volumes:
      - "/docker-swarm/appdata/pihole/unbound:/etc/pihole:rw"
      - "/docker-swarm/appdata/pihole/dnsmasq:/etc/dnsmasq.d:rw"
      - "/etc/localtime:/etc/localtime:ro"
  cloudflared:
    image: visibilityspots/cloudflared:latest
    deploy:
      placement:
        constraints:
          - node.role == manager
      mode: replicated
      replicas: 1
      resources:
        limits:
          cpus: "1"
          memory: 512M
        reservations:
          memory: 64M
      update_config:
        parallelism: 1
        delay: 2m
        order: start-first
        failure_action: rollback
      rollback_config:
        parallelism: 1
        delay: 2m
        order: start-first
        failure_action: pause
    ports:
      - target: 5054
        published: 5054
        protocol: tcp
      - target: 5054
        published: 5054
        protocol: udp
    networks:
      - traefik-public
networks:
  traefik-public:
    external: true
  default:
    driver: overlay
    attachable: true
secrets:
  pihole_webpw:
    external: true

Code for pihole and cloudflared compose above
– section in pihole service (labels:) enables the pihole dashboard to http://pihole.local && http://pihole/ . For these to work make sure you either add to your hostfile / pihole local dns those addresses and the address of the swarm / traefik host. It also routes port 53 through the proxy (traefik).
– section in pihole service (environment:) “- PIHOLE_DNS_=CHANGE TO TRAEFIK HOST IP#5054;127.0.0.1#5335” routes internal queries to unbound while also routing DoH to the cloudflared container (port 5054) which is exposed to the host in the cloudflared service section (ports:).


Now to test

Now if we start up Traefik and go to the dashboard address we should get a dashboard similar to this:

Click to enlarge
Which means we can start the pihole service which will also start the cloudflared service.

To test if its receiving requests you can test with :

dig +short @IP_OF_TRAEFIK_HOST -p 5054 disney.com

and also to test the pihole itself :

dig +short @IP_OF_TRAEFIK_HOST disney.com

If this worked you should see something similar to this in the pihole dashboard:

Click to enlarge
If all of this worked you can go here to verify which should look something like this :

Click to enlarge
As you can see on that screenshot the section “Using DNS over HTTPS (DoH)” is now “Yes”.
et voil
!


Misc notes and errata

As you can see in the pihole dashboard screenshot the client shows up as both local && as the traefik container so you will NOT get detailed client information but rather everything coming from the same host.
Future article will go through adding DoT which will be a bit more complicated. Also at some point i will try to figure out how to get individual clients to show up in the pihole dashboard while proxied through traefik.

«
»

    Leave a Reply

    Your email address will not be published. Required fields are marked *