Last year, at the recommendation of a work colleague, I grabbed one of my spare Raspberry Pi 4s and installed the DNS proxy and content blocker Pi-Hole. It’s now handling all the DNS queries on my home network. Recently, I upgraded my Pi-Hole server to make its DNS requests over HTTPS.
This technique encrypts DNS queries in the same way that web pages are requested securely. Intermediate parties, like your ISP, can’t track the websites and services you’re accessing as they can with with regular DNS, which sends queries in clear text. You encrypt your wireless network traffic, you encrypt web site requests — through HTTPS — so you should encrypt DNS lookups too.
With DNS-over-HTTPS (DoH) set up at home, the question I next asked was, what about other locations? I can’t take my Pi-Hole with me, and I don’t have access to office networks, so can I do DoH on a client machine? The answer is, yes, as I learned when I tried it on the Mac I use in my office. I have a Raspberry Pi 400 there too — what about that? The same process applies, but there’s an extra hoop to jump through thanks to the way Raspberry Pi OS handles DHCP and DNS lookups.
I use Cloudflare’s cloudflared
to drive DoH because it’s what I use alongside the Pi-Hole. It’s an open source cross-platform DNS proxy that routes DNS queries to wherever you’d like to route them. Cloudflare has the IP address 1.1.1.1 for DNS queries, but supports DoH at 1.1.1.1/dns-query
. Google likewise accepts DoH queries at 8.8.8.8/dns-query
. So ‘all’ you need to do is install cloudflared
, configure it to run at startup, and set it up to route DNS queries from browsers, apps and so forth to a DoH site like those mentioned above.
Installing cloudflared
is straightforward. Grab the installer file from Cloudflare and run it:
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb
sudo dpkg -i *.deb
Note I’ve included the URL for the 64-bit version of cloudflared
.
Update The process for install the 32-bit version is slightly different:
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm sudo cp ./cloudflared-linux-arm /usr/local/bin/cloudflared sudo chmod +x /usr/local/bin/cloudflared
You can check that you’re up to date with cloudflared --version
and subsequently update the proxy with cloudflared update
.
Configuring it is done like this: create a config file which you’ll subsequently tell the system to load into cloudflared
at startup:
sudo nano /etc/default/cloudflared
To this file, add the line:
CLOUDFLARED_OPTS=--upstream https://1.1.1.1/dns-query --upstream https://8.8.8.8/dns-query
Here I’ve set two DNS targets: Cloudflare’s and, as backup, Google’s. Save the file: hit ctrl–c, y and hit Enter.
Now you set up a service to run cloudflared
at startup. First, run this code, to generate the service definition:
sudo tee /etc/systemd/system/cloudflared.service >/dev/null <<EOF [Unit] Description=DNS over HTTPS (DoH) proxy client Wants=network-online.target nss-lookup.target Before=nss-lookup.target After=network-online.target syslog.target [Service] AmbientCapabilities=CAP_NET_BIND_SERVICE CapabilityBoundingSet=CAP_NET_BIND_SERVICE DynamicUser=yes EnvironmentFile=/etc/default/cloudflared ExecStart=/usr/local/bin/cloudflared proxy-dns $CLOUDFLARED_OPTS Restart=on-failure RestartSec=10 KillMode=process [Install] WantedBy=multi-user.target EOF
The following command starts the service:
sudo systemctl enable --now cloudflared
You can test your setup is working at this point with the dig
tool. This won’t be installed on your Pi — you can get it now with:
sudo apt update && sudo apt install dnsutils -y
You can then run the following command to get Cloudflare’s IPv6 IP address. It will come up almost instantaneously. If there’s a long wait, check you started the service and the you entered the config files correctly.
dig +short @127.0.0.1 cloudflare.com AAAA
The DNS proxy is set up and running, but it’s not yet connected to the system. To do so, edit the Pi’s DHCP daemon configuration:
sudo nano /etc/dhcpcd.conf
Scroll to the end of the file and add the following lines:
interface eth0 static domain_name_servers=127.0.0.1 interface wlan0 static domain_name_servers=127.0.0.1
This tells dhcpd
to send DNS requests to localhost, which is where cloudflared
is listening — as the earlier test confirmed. Save the config file and then reboot.
When your Pi is back up, you can check dhcpd
is doing the right thing by looking at the contents of the file /etc/resolv.conf
. It’ll have the line nameserver 127.0.0.1
. Now you can fire up a browser or update apt
and know the server address requests are being encrypted and relayed to a verified server. You can also use dig
:
dig +short cloudflare.com AAAA
Note that this time you don’t tell dig
which DNS server to use (the @127.0.0.1
in the earlier call) so that it’ll use the system-specified one, ie. the one set through your DHCPCD changes.