Synology, Docker, Pihole and Cloudflare
A while ago, I got really sick and tired of dealing with the hardware that Telus shipped me for my residential gateway, and so a new "internal" router was added. Things were good, but then I wanted to do network-wide ad blocking (to deal with ads on streaming devices...), but found that even if I specified an additional DNS server, the router would still advertise itself as a DNS server, as well as any additional DNS server I added.
Something had to be done!
The Goal
The basis of this idea is that my Synology NAS is "probably" one of the first things I'm going to turn on, and one of the more "foundational" pieces of the network, so running network-wide services on the device is sound.
The software on the Synology isn't terribly feature rich, and certainly doesn't help me with the adblocking function that I'm looking for (as well as defining custom DNS records for the network), but PiHole does. I am also trying avoid "hacking" the Synology, and leaving it as close to factory as possible so that future upgrades don't break everything.
So, the goal is simple: Run Docker on the Synology, and run PiHole as a container.
Wiring up the basics
Synology has a Docker distribution for their devices, which was a great start. Installing this was straightforward using the usual mechanism.
Pihole has a docker image, so it was a matter of configuring this. Marius Hosing has a great walk-through of how to do this through the GUI, so that at least told me it was possible. I got this going easy enough.
The catch was how do I ensure that Pihole was kept up to date? Watchtower was a good choice, and there's no shortage of resources that discuss how to run this on a Synology (including another resource at Marius Hosting).
Issues
This all worked really great, until Watchtower updated Pihole. It downloaded the new image, shut down Pihole, replaced the image and started it back up. Cool, works as designed.. right?
As part of Pihole's startup, the image checks for - and downloads - some binaries from an apt resource.
However, there's no DNS server running on the network at this moment in time, so the container shuts down thinking there's an error. Docker on the Synology starts the container back up, but since nothing has really changed, the same issue occurs again.
This happened at about 11 PM, right when my youngest son was going to read an ebook on the tablet...
A quick fix applied, and a sleep later, it was time to resolve this mess.
Docker-Compose
I really do like Docker Compose. I like the idea of defining what services I want in a configuration file. So, how do I make sure there's a DNS resolver available to the Pihole when it starts up?
This site talks about using DNS over HTTPS from Cloudflare as the upstream DNS resolver for a Pihole, which has the added advantage of hiding your DNS queries from your ISP. This solution proposed is complete with a Docker-compose.yml file that basically solves what I'm looking for.
Add Watchtower, and we're done.
PiHole and Cloudflare DNS docker-compose.yml:
cat pihole/docker-compose.yml
1version: "3"
2
3services:
4 pihole:
5 container_name: pihole
6 image: pihole/pihole:latest
7 environment:
8 TZ: 'America/Edmonton'
9 DNSMASQ_LISTENING: local
10 ServerIP: # IP of my Synology
11 DNS1: '127.0.0.1#5053'
12 DNS2: 'no'
13 WEB_PORT: 8080
14 volumes:
15 - '/volume1/docker/pihole/dnsmasq.d/:/etc/dnsmasq.d/'
16 - '/volume1/docker/pihole/pihole/:/etc/pihole'
17 cap_add:
18 - NET_ADMIN
19 - NET_BIND_SERVICE
20 restart: unless-stopped
21 depends_on:
22 - cloudflared
23 network_mode: host
24
25 cloudflared:
26 image: crazymax/cloudflared
27 container_name: cloudflared
28 ports:
29 - "5053:5053/udp"
30 - "49312:49312/tcp"
31 environment:
32 - "TZ=America/Edmonton"
33 - "TUNNEL_DNS_UPSTREAM=https://1.1.1.1/dns-query,https://1.0.0.1/dns-query"
34 restart: always
Watchtower docker-compose.yml:
cat watchtower/docker-compose.yml
1version: "3"
2
3services:
4 watchtower:
5 container_name: watchtower
6 restart: unless-stopped
7 image: containrrr/watchtower
8 volumes:
9 - /var/run/docker.sock:/var/run/docker.sock
10 environment:
11 - TZ=America/Edmonton
12 - WATCHTOWER_SCHEDULE=0 0 23 * * *
13 - WATCHTOWER_CLEANUP=true
14
15 - WATCHTOWER_NOTIFICATIONS=email
16 - WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG=Hostname
17 - WATCHTOWER_NOTIFICATION_EMAIL_FROM=# Valid sender
18 - WATCHTOWER_NOTIFICATION_EMAIL_TO=# Valid Recipient
19 - WATCHTOWER_NOTIFICATION_EMAIL_SERVER=in-v3.mailjet.com
20 - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587
21 - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=# Mailjet username
22 - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=# Mailjet Password
23 - WATCHTOWER_NOTIFICATION_EMAIL_DELAY=5
In this case, I am using Mailjet as my SMTP host to send me notifications from Watchtower when it does stuff.
Final Gotcha
When testing that I was actually using Secure DNS and DNSSEC from Cloudflare's check tool, I would see inconsistent results. Sometimes I would have secure DNS, sometimes not. This stemmed from an issue within Pihole, where it had Google's DNS selected as the upstream DNS servers even though the DNS servers were defined as part of the environment variables.
Updating the DNS Servers configuration to not select a "stock" upstream DNS server, and instead leaving the local DoH resolver selected seemed to be the fix I needed:
and gave me green results.