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