Pi-hole Setup
Background
I recently decided that I would actually do something with the Raspberry Pi I’ve had sitting around neglected. It’s been hanging out on my network for months plugged in, with SSH configured, but not actually accomplishing anything. Every few weeks I would SSH to it and install some updates. I had thought I might use it as something I could SSH to in order to do some light coding from my iPad, but that’s not a use case that ever materialized for me; when I want to write code, I’m just reaching for my laptop.
My main thought was that I would use Pi-hole to see if I could sinkhole the advertisements for Hulu in order to watch my ad-supported subscription that I get included via my cellular carrier without any ads. As it stands, I typically use Hulu exclusively for movies since they’ll play a few minutes of ads at the beginning and then nothing else for the duration of the movie. While that’s fine, I get fed up far too quickly with 4–6 ad breaks happening over the course of a 60 minute TV episode.
I had also originally thought to do this with NextDNS, but if that worked it would likely necessitate yet another subscription since custom filtering in NextDNS is only good for 300,000 queries per month. If you go beyond 300,000 queries, name resolution still works but custom filtering will not. I figured there was no need to pay a few extra dollars a month when I could achieve the same for free with a device that’s literally sitting around waiting for something to do.
Spoiler alert: Blocking Hulu ads in this fashion doesn’t work, so if that’s your only reason for reading the post I can save you a bit of time. On both my Roku and Fire TV, the Hulu app will time out when it can’t play the ads. I had been hoping it would give up on the ads and just move on to the main content, but instead it just won’t play anything. Bummer.
Setup
Getting Pi-hole installed is extremely simple. I’m running Raspbian (or Raspberry Pi OS, I guess they’re calling it now) Bullseye, which is in Pi-hole’s clearly defined prerequisites documentation. Installation is as simple as executing the project’s shell script for it, available in their GitHub repository. If you hate the idea of curl
ing straight to bash
, you can always just wget
the script to save it, review it, and then decide if you'd like to run it or not.
The script has a fairly nice CLI UI, something I’m always a fan of, that will walk through the configuration, which only takes a few minutes. It will even configure the device with a static IP for you if it doesn’t already have one, though in my case I opted to not have it do that since I’m handling that via a reservation on my DHCP server already.
Within just a few minutes, I was able to dig
against the Pi successfully and with the default block-list configured.
Screw-up
Now I just needed to tell all of my devices that they needed to use the Pi as their DNS server. This should have been a simple thing to accomplish, but I managed to cause a bit of chaos with it. To be honest, I still don’t fully understand why things broke in the manner they did, but at least fixing it was relatively simple once I realized my mistake.
The easiest way to get my devices to use the Pi for DNS is to configure it on my router. After logging in to my router to do so, I almost immediately lost the ability to open websites. A little troubleshooting got me to the point of realizing:
- I could still reach things via IP, e.g.
ping 1.1.1.1
- I could resolve hostnames when manually specifying the IP of my DNS server.
- I couldn’t ping the Pi’s local IP.
- I couldn’t ping the router’s local IP.
My router clearly uses name resolution as a validation for whether or not it’s connected to the Internet, as the LED on it also immediately switched from green to red, despite the fact that Internet connectivity was still functioning. It seems like a bit of a half-assed check, but things got even weirder before I could worry about it too much.
Being very confused as to how changing my DNS server would impact the local IPs for my devices, I did a little further digging (no pun intended.) I eventually noticed that my local IP had switched from a 192.168.0.1/24 address to a 192.168.1.1/24 address. Similarly, my gateway was suddenly 192.168.1.1 instead of 192.168.0.1. Weird. I tried hitting the web interface for 192.168.1.1 and received this:
Suffice to say, I had no idea why there would be a conflict now, but whatever. I allowed it to use the new 192.168.1.1 address and went to log in… only my credentials no longer worked. I know for a fact that the credentials themselves are fine since they’re stored in a password manager. So somehow the device believing it can’t reach the Internet because name resolution is broken also causes it to somehow reject my local administrator password? The plot thickens.
With more or less everything broken and no ability to fix it since the router was inaccessible, I resorted to holding in the tiny button on the back of the device to factory reset it. Since my router is simple, walking through the configuration to set it up from scratch is a process that takes literally less than 5 minutes. Waiting for the device to reboot during the factory reset takes longer than the configuration steps. After reconfiguring my wireless networks and my DHCP reservation for the Pi, I went to give updating my DNS settings another shot. This is when I realized my mistake…
I had mindlessly changed the DNS servers of the router rather than the DNS servers being handed out with DHCP leases. So the WAN interface of my router was attempting to reach back into the local network to the Pi for name resolution, which is never going to work. Why does that cause the router to switch IP addresses? Why does that cause the router to reject my local administrator credentials? I have no idea, but at least I knew what I screwed up.
I updated my settings to hand out the Pi’s IP address with new DHCP leases, and sure enough everything started working smoothly.
The Pi
With things finally working after my colossal screw-up, I checked out the local web interface for Pi-hole. After logging in, I saw that I had an alert. The content was unsurprising:
I removed the public IP for my network from the screenshot, but suffice to say it’s the WAN address of my router. Derp.
Other than looking at the hard proof of the fact that I wasn’t thinking properly, the interface for Pi-hole is pretty slick.
I really didn’t do much in the way of configuration, though I was surprised to see just how insanely frequently my Roku attempts to phone home, which is why the number of blocked domains is so high in the screenshot above.
Caveats
With everything working properly, the one item — which isn’t really even a caveat, but I couldn’t think of a better word for this section — that I hadn’t expected was that iCloud Private Relay stopped working across my iPhone and iPad. I eventually got messages on each that the network didn’t support Private Relay. This makes sense, as Private Relay is going to nullify every aspect of Pi-hole given that the devices will use Apple’s infrastructure for DNS queries rather than the local DNS server. Ultimately, I decided I actually prefer this setup and have left things as-is. However, I did confirm that there was a way to override this behavior, as specified in the Pi-hole documentation.
The tl;dr is that you create a file at /etc/pihole/pihole-FTL.conf
and add the following line to it:
BLOCK_ICLOUD_PR=false
As I said, I’ve not opted in to using this since I think I’d rather take advantage of Pi-hole’s DNS capabilities more than Private Relay’s public IP hiding capabilities, but I like knowing the option exists if I’d like to switch to that in the future. I also confirmed that trying to use ProtonVPN is successful; Pi-hole doesn’t stop it from connecting. I don’t typically use my VPN while at home — it’s mostly something I use for public WiFi — but again, I like knowing that I can should the need arise.
Originally published at https://borked.sh on April 24, 2022.