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 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).
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.
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:
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://184.108.40.206/dns-query,https://220.127.116.11/dns-query" 34 restart: always
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.
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.