Pihole TCP/UDP Services for port 53 behind Traefik

Hello,
I'm playing with Traefik and wanted to test Pihole both Admin and DNS (Port 53) behind Traefik.

I can access the Admin page just fine. However, DNS queries via Traefik don't seem to be working. Here's my docker-compose file for Pihole

version: '3.8'

networks:
  backend:
    external: true

services:
  pihole:
    image: pihole/pihole:latest
#    user: root
    restart: unless-stopped
    container_name: pihole
    volumes:
      - "$PWD/pihole/etc-pihole/:/etc/pihole/"
      - "$PWD/pihole/etc-dnsmasq/:/etc/dnsmasq.d/"
    networks:
      - backend
    environment:
      WEBPASSWORD: 'pihole'
    dns:
      - 127.0.0.1
      - 1.1.1.1
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=backend"

      ## TCP Routers/Service
      - "traefik.tcp.routers.pihole-rtr.entrypoints=dns-ep"
      - "traefik.tcp.routers.pihole-rtr.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.pihole-rtr.service=pihole-svc"
      - "traefik.tcp.services.pihole-svc.loadbalancer.server.port=53"

      ## UDP Routers/Services
      - "traefik.udp.routers.pihole-udp-rtr.entrypoints=dns-udp-ep"
      - "traefik.udp.routers.pihole-udp-rtr.service=pihole-udp-svc"
      - "traefik.udp.services.pihole-udp-svc.loadbalancer.server.port=53"

      ## TCP Routers/Service
      - "traefik.http.routers.pihole-a-rtr.entrypoints=http-ep"
      - "traefik.http.routers.pihole-a-rtr.rule=Host(`pihole.debian.lan`)"
      - "traefik.http.routers.pihole-a-rtr.service=pihole-a-svc"
      - "traefik.http.services.pihole-a-svc.loadbalancer.server.port=80"

How can I diagnose and fix this issue?

Edit:
If I run "docker exec -ti pihole dig a google.com" I get:

; <<>> DiG 9.10.3-P4-Debian <<>> a google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61350
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;google.com. IN A

;; ANSWER SECTION:
google.com. 293 IN A 216.58.211.174

;; Query time: 11 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Tue Jun 30 19:11:57 UTC 2020
;; MSG SIZE rcvd: 554

Edit: @cakiwi here is the Traefik service:

version: "3.8"

services:
  traefik:
    image: "traefik:latest"
    restart: unless-stopped
    container_name: traefik
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
      - "53:53"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "$PWD/traefik/conf:/etc/traefik/"
      - "$PWD/traefik/logs/:/logs"
      - /etc/localtime:/etc/localtime:ro
    networks:
      - web
      - backend
      - internal
    labels:
      - "traefik.enable=true"
1 Like

What does the traefik service look like(I'm assuming you run it in docker too).

@tam481 You need to publish 53 udp on the traefik container too. No protocol on the services port defaults to tcp only. https://docs.docker.com/compose/compose-file/#ports

You can query just using tcp to test your current setup. Dig has the +tcp flag for this.

That worked beautifully both TCP and UDP now. Thank you so much

Sorry to revive this thread, but I'm having exactly the same issue, but the proposed solution doesn't seem to be working for me. I can query DNS successfully from the Docker host, but not anywhere on the local network. I can also access the Admin page as expected.

Pi-Hole Docker Config:

  pihole:
     container_name: pihole
     domainname: domain.com
     image: pihole/pihole:latest
     dns:
      - 127.0.0.1
      - 1.1.1.1
     ports:
      - "5353:53/tcp"
      - "5453:53/udp"
      - "67:67/udp"
      - "8053:80/tcp"
      - "8443:443/tcp"
     volumes:
      - ./pihole/pihole:/etc/pihole/
      - ./pihole/dnsmasqd/:/etc/dnsmasq.d/
     environment:
      ServerIP: {SERVER-IP}
      PROXY_LOCATION: pihole
      VIRTUAL_HOST: pihole.domain.com
      VIRTUAL_PORT: 80
      TZ: 'America/Toronto'
      WEBPASSWORD: test
      DNSMASQ_LISTENING: all
     restart: unless-stopped
     labels:
      - "traefik.enable=true"
      - "traefik.http.routers.pihole.rule=Host(`pihole.domain.com`)"
      - "traefik.http.routers.pihole.entrypoints=websecure"
      - "traefik.http.routers.pihole.tls.certresolver=cloudflare"
      - "traefik.http.services.pihole.loadbalancer.server.port=80"
      - "traefik.tcp.routers.pihole-rtr.entrypoints=dns-ep"
      - "traefik.tcp.routers.pihole-rtr.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.pihole-rtr.service=pihole-svc"
      - "traefik.tcp.services.pihole-svc.loadbalancer.server.port=53"
      - "traefik.udp.routers.pihole-udp-rtr.entrypoints=dns-udp-ep"
      - "traefik.udp.routers.pihole-udp-rtr.service=pihole-udp-svc"
      - "traefik.udp.services.pihole-udp-svc.loadbalancer.server.port=53"

Traefik Docker Config:

  traefik:
    image: traefik:v2.2
    container_name: traefik
    restart: unless-stopped
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.dns-ep.address=:53/tcp"
      - "--entrypoints.dns-udp-ep.address=:53/udp"
      - "--certificatesresolvers.cloudflare.acme.dnschallenge=true"
      - "--certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare"
      #- "--certificatesresolvers.mydnschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.cloudflare.acme.email=*********@*************.com"
      - "--certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json"
    ports:
      - 80:80
      - 443:443
      - 53:53/udp
      - 53:53/tcp
      - 8080:8080
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.rule=Host(`domain.com`)"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - traefik.http.routers.http_catchall.rule=HostRegexp(`{any:.+}`)
      - traefik.http.routers.http_catchall.entrypoints=web
      - traefik.http.routers.http_catchall.middlewares=traefik-https-redirect
      - "traefik.http.routers.traefik-secure.entrypoints=websecure"
      - "traefik.http.routers.traefik-secure.rule=Host(`domain.com`)"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=domain.com"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.domain.com"
      - "traefik.http.routers.traefik-secure.service=api@internal"


If anyone has any ideas, I would appreciate any help!

You only have one router on your pihole service. If you look at @tam481 you will see they have 3 routers defined.

Thanks for your response!

I've added the additional entry points for port 53 TCP and UDP. Not sure if that is the recommended way of doing it, but I've modified my original post to reflect the changes. I've also added the additional lines that I missed in my pihole config, but have the same end result, can't query :53 anywhere else besides the docker host.

Edit Seems like it was a configuration issue. Figured it out, this is the working configuration for anyone who experiences the same issue:

Pihole Config:

  pihole:
     container_name: pihole
     domainname: domain.com
     image: pihole/pihole:latest
     dns:
      - 127.0.0.1
      - 1.1.1.1
     ports:
      - "5353:53/tcp"
      - "5453:53/udp"
      - "67:67/udp"
      - "8053:80/tcp"
      - "8443:443/tcp"
     volumes:
      - ./pihole/pihole:/etc/pihole/
      - ./pihole/dnsmasqd/:/etc/dnsmasq.d/
     environment:
      ServerIP: {SERVER IP}
      PROXY_LOCATION: pihole
      VIRTUAL_HOST: pihole.domain.com
      VIRTUAL_PORT: 80
      TZ: 'America/Toronto'
      WEBPASSWORD: test
     restart: unless-stopped
     labels:
      - "traefik.enable=true"
      - "traefik.http.routers.pihole.rule=Host(`pihole.domain.com`)"
      - "traefik.http.routers.pihole.entrypoints=websecure"
      - "traefik.http.routers.pihole.tls.certresolver=cloudflare"
      - "traefik.http.services.pihole.loadbalancer.server.port=80"
      - "traefik.tcp.routers.dns.entrypoints=dns"
      - "traefik.tcp.routers.dns.rule=HostSNI(`pihole.domain.com`)"
      - "traefik.tcp.routers.dns.service=pihole"
      - "traefik.tcp.services.pihole.loadbalancer.server.port=53"
      - "traefik.udp.routers.dns-udp.entrypoints=dns-udp"
      - "traefik.udp.routers.dns-udp.service=pihole"
      - "traefik.udp.services.pihole.loadbalancer.server.port=53"

Traefik Config:

  traefik:
    image: traefik:v2.2
    container_name: traefik
    restart: unless-stopped
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.dns.address=:53/tcp"
      - "--entrypoints.dns-udp.address=:53/udp"
      - "--certificatesresolvers.cloudflare.acme.dnschallenge=true"
      - "--certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare"
      #- "--certificatesresolvers.mydnschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.cloudflare.acme.email=*********@*************.com"
      - "--certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json"
    ports:
      - 80:80
      - 443:443
      - 53:53/udp
      - 53:53/tcp
      - 8080:8080
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.rule=Host(`domain.com`)"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - traefik.http.routers.http_catchall.rule=HostRegexp(`{any:.+}`)
      - traefik.http.routers.http_catchall.entrypoints=web
      - traefik.http.routers.http_catchall.middlewares=traefik-https-redirect
      - "traefik.http.routers.traefik-secure.entrypoints=websecure"
      - "traefik.http.routers.traefik-secure.rule=Host(`domain.com`)"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=domain.com"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.domain.com"
      - "traefik.http.routers.traefik-secure.service=api@internal"