Discopter Pi Guide

Chapter 8: Block Ads and Encrypt DNS Requests Through Pi Hole

When we navigate the internet, we tend to think in terms of domain names. Typing in wikipedia.org takes us to Wikipedia. But for the protocols that make the internet work known as TCP/IP, “wikipedia.org” as a string of characters is actually meaningless. TCP/IP deals with IP addresses, not domain names. Back in the early days of the internet, beginning when it was still called ARPANET, users (mostly military and academia) would keep spreadsheet-like tables handy to match an IP address to something more human readable. By the 1980s, the internet was too big for this kind of system to work. In addition, as IP addresses were reassigned, there was no coordinating process to make sure everyone knew where a particular IP address went.

That's where DNS comes in. The Domain Name System is often referred to as the “phone book of the internet.” It takes a domain name, matches it to an IP address, and then forwards the request to that IP address. When you go to wikipedia.org, your web traffic doesn't go straight to a Wikipedia server. Before it can get there, it must pass through a DNS server that looks up wikipedia.org and returns 198.35.26.96.

From a privacy standpoint, this can be a problem. Whoever controls that particular DNS server will know what website you're trying to access. Many casual home internet users get their routers from their Internet Service Provider, or ISP. Many of these ISPs configure the router to use the ISP's DNS servers by default. Mobile phones typically ship with the service provider's DNS server as the default. Google and Amazon Alexa devices use Google's and Amazon's DNS servers by default (and good luck changing that setting). ISPs have spent millions of dollars lobbying Congress to ensure that they can monetize your DNS requests and lobbying against measures that would enable encrypting these requests. By configuring DNS to a (relatively more) trusted provider, and encrypting the request along the way, you will immediately increase your privacy.

But what does this have to do with ads? Internet ads and pop ups are rarely served by the same domain as the site they are found on. The most obvious cases are ads for products or services that have nothing to do with the website you're on. The webpage you visit dedicates a section in its layout for an ad to appear and that ad gets served from a different server associated with a different domain name. Even when a popup does belong to the website itself (such as a “Please remove your ad blocker” popup), that particular content is almost always being served from a different domain. If your device's DNS server inspects all of the domains before sending them to the device, it can check them against a list of known advertising and spam domains, exactly in the same way it checked wikipedia.org to get an IP address.

That's exactly what we want our Raspberry Pi to do. Any device using the Raspberry Pi as a DNS server will first have the DNS request encrypted in a process known as DNS-over-HTTPS or DoH for short. It will pass through the ISP's gateway with no ability for the ISP to see what site you are visiting. It will arrive at an upstream DNS resolver who will unencrypt the request and forward it to the corresponding IP address of the site you're trying to visit. The site will then send a packet back which will first pass through the Raspberry Pi. The Pi will inspect the domain name associated with the packet. If it appears on one of its Prohibit Lists, the packet is denied. The result is a faster, more private internet for your devices. The way we'll do all of this is through a program called Pi Hole.

This is the first time we'll be using our Pi as a server. Before we go any further, we'll first need to assign a static IP address. If we don't, the local IP address for the Pi could change and any devices using it as a DNS server will no longer point to its location on the network. Dynamic Host Control Protocol, or DHCP, is out of scope for this guide, but a one sentence summary would be it's how a router assigns and reassigns IP addresses to connected devices. What we need to do is reserve an IP address for the Pi on the router, so DHCP doesn't reassign it. The process of doing so varies greatly from router to router, but Step 1 presents a general guide.

Step 1: Assign a Static IP Address to Your Pi

  1. Connect to the same network as the Raspberry Pi and navigate to the router's admin page. This will typically be an IP address printed on the router. Below are some typical router IP addresses.
    • 192.168.0.1
    • 192.168.1.1
    • 192.168.8.1
    • 192.168.10.1
    • 192.168.86.1
  2. Login to the admin page. If you've never been to this page before, the default login credentials are also typically printed on the router or easily found online. When in doubt, username “admin” and password “password” will often work. Once you login with default credentials, you should be asked to change at least the password. Make sure you do so.
  3. Look for a navigation pane or navigation menu on the router's admin page. Then look for a section called “Network”, “Networking Options”, “DHCP”, “IP Reservations,” or something that could indicate managing DHCP or specific devices on the network. Once again, if in doubt, just do a search for “DHCP reservation <router make/model>” and you should be able to find specific directions.
  4. In whichever screen or menu option your router uses, assign a DHCP reservation for your Raspberry Pi. Again, this widely varies. Some routers make it easy with a dropdown menu where you can select the Pi and click a checkmark to reserve its IP. Others, you may need to type in the Pi's IP address and then its MAC address to make the reservation.
  5. With a static IP address assigned, we're now ready to use the Pi as a server.

Step 2: Download and Install Pi Hole

  1. Run the following command. This downloads and runs the Pi Hole installer. It updates some packages and ensures system compatibility.
    curl -sSL https://install.pi-hole.net | sudo bash
  2. Continue through the next three screens, informing you of what Pi Hole, asking you to donate, and then informing you that the Pi will need a static IP address, which we dealt with in Step 1.
  3. The installer will ask you to confirm the network settings and warn you that DHCP may reassign the IP address. Having completed Step 1 by making a DHCP reservation on the router, this warning doesn't apply.
  4. Next, it will ask about an upstream DNS provider. Pick anything for now as we'll be changing this in a later step when we enable DNS-over-HTTPS.
  5. It will ask if you want to use the default blocklist. The default one is very good, and you'll often not need anything additional to make use of Pi Hole.
  6. The next two screens will ask about installing a web admin interface. This is the easiest way to monitor and adjust your Pi Hole setup, so we definitely want to say yes to this. The web interface will need to get served by the Pi and Pi Hole comes with a Lighttpd web server to do so. Confirm installation of that. Any adjustments to how we access the Pi Hole web interface will be done through adjustments to the Lighttpd settings.
  7. Next, you will be asked if you want to log the DNS queries. If setting up in your home for personal use, full logging can give you some neat data and make it clear which domains are basically just glorified adware. Obviously, this does create a “paper trail” of the domains (but not specific URLs) passing through your Pi. If maximum privacy and security are the goal, you will likely want to disable all logging.
  8. Installation of the Pi-hole server on your Raspberry Pi has now completed. This screen will tell you how you can gain access to the Pi-hole web interface. You can completely ignore this information as we're going to be changing these values in the next step.

Step 3: Configuring the Lighttpd Server

  1. Open the Lighttpd configuration file as root.
    sudo nano /etc/lighttpd/lighttpd.conf
  2. In the Lighttpd configuration file, locate the section where the server listens for incoming connections on port 80. It should be server.port = 80
  3. Modify the server.port directive to specify the desired port number. Much like when we chose an SSH port, pick something between 1024 and 65535. Choose a port number that is not already in use by another service. Using the 8000 range is a common convention when changing default ports. For example, you can set it to 8090.
  4. Save and exit the file.
  5. Restart the Lighttpd service.
    sudo systemctl restart lighttpd
  6. Add a rule in UFW to allow local network access to the server and to allow DNS requests to pass through on port 53.
    sudo ufw allow from truelocal IP CIDR> to any port <Lighttpd port>
    sudo ufw allow from <local IP CIDR> to any port 53
  7. Reload UFW.
    sudo ufw reload
  8. Change the password on the web interface. Run this command:
    sudo pihole -a -p
  9. Verify Access to the Admin Web Page. Once the Lighttpd service has been restarted and UFW rule set, you should be able to access the Pi-hole admin web page using the new port number. Open a web browser and navigate to its URL:
    http://<your-raspberry-pi-ip>:<new-port-number>/admin
    Replace <your-raspberry-pi-ip> with the IP address of your Raspberry Pi and <new-port-number> with the port number you specified (e.g., 8090). You should see the Pi-hole admin interface load successfully. For example: http://192.168.1.50:8090/admin for a Pi with IP address 192.168.1.50, and Lighttpd port 8090.

The Raspberry Pi is now set up as an ad blocking DNS server. Unless it has cached the page data, it's still going to need an upstream DNS provider. In other words, until and unless you've visited wikipedia.org, your Pi Hole server is still going to need to forward your DNS request somewhere to get the IP address. We're going to make sure that forwarding is encrypted using the Cloudflared daemon. Despite being developed by Cloudflare, you can use Cloudflared to connect to other DNS-Over-HTTPS providers such as Quad9, which is precisely what we will be doing.

Step 4: Installing Cloudflared

  1. Before we can actually install Cloudflared, we need to first run some other commands. The first one will install a program called lsb_release, or Linux Standard Base. This will print distribution information, which we'll need as Cloudflare puts Cloudflared into its own repository.
    sudo apt install curl lsb-release
  2. Next, we need to get Cloudflare's GPG, or GNU Privacy Guard, key. This will verify that the Cloudflare repository is legitimate.
    curl -L https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-archive-keyring.gpg >/dev/null
    • This keyring needs read permissions. If you've messed with the UMASK settings in Chapter 6, run the following command:
      sudo chmod 755 /usr/share/keyrings/cloudflare-archive-keyring.gpg
  3. Now we add the Cloudflare repository, where the Cloudflared daemon can be downloaded.
    echo "deb [signed-by=/usr/share/keyrings/cloudflare-archive-keyring.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
  4. We've added a new repository, so we need to tell our Raspberry Pi to update its index of available software.
    sudo apt update
  5. Now we can finally install Cloudflared.
    sudo apt install cloudflared

Before continuing, let's pause for a moment to discuss DNS provider options once again, as this is an aspect of internet privacy that few take into consideration. As mentioned at the beginning of this chapter, many hundreds of millions of dollars have been spent ensuring that companies who want to monetize your DNS requests can do so. Monetizing DNS requests means selling your data or otherwise using your data for advertising purposes. While not any kind of official taxonomy, I think it's helpful to place DNS providers into four distinct groups.

Group 1: Sells Your Data

These are your Comcasts, Verizons, T-Mobiles, Cox Internets, etc. These are the most dangerous and invasive as they have far more access to your personal data. Most of the money spent lobbying Congress on this issue comes from these guys, as they claimed it wasn't fair that companies like Google were allowed to sell your data but they couldn't. Devices sourced from them will generally have DNS set to their servers by default. If you use Xfinity and were provided with a modem and router as part of your subscription, the router is definitely passing all DNS requests to Comcast unless you turn that off. Buried in mobile device settings are DNS options with an option usually labelled “Default” auto-selected. If you subscribe to Verizon, I'm sure you can guess what that “default” then represents.

Group 2: Uses Your Data

These are your Googles and Amazons. Like ISPs, they use your DNS requests for advertising. They're at least a little better though in that they run their own advertising so your data likely isn't being sold to a particularly unsavory ad provider, which your ISP might do. Still, they collect a lot of other personal data on you, so why add more? Many IoT devices, like personal assistants, robot vacuums, and doorbells won't let you change the DNS server, and very often they point to Google or Amazon. Never hurts to check though. Google's DNS servers are particularly common to find and easy to spot with an IP address of 8.8.8.8 or 8.8.4.4.

Group 3: Doesn't Use Your Data

Cloudflare comes to mind and is a solid choice. Companies like these have a business model that does not include selling your data, or if they do sell your data, they have a DNS offshoot that does not. Amazon Route 53 is an example of the latter. Your Alexa device is absolutely being used to monetize your DNS requests, but if you host a website on AWS and use Route 53, your data is safe. Your site's visitors though, not so much. If there can be said to be a non-ISP, non-Google default DNS provider, it would be Cloudflare. They even have the very lowest IP address of 1.1.1.1. As commercial companies operating in countries like the United States, they fully cooperate with law enforcement and subpoenas for your data.

Group 4: Can't Use Your Data

Even better though is an entity that exists solely to protect user's privacy. These are servers that undergo third party audits and do not log user data. Many are located in countries with very strong privacy laws like Switzerland and Sweden, where police have very little right to demand data, none of which is being kept by them to begin with. Quad9 is an example of a DNS provider in this group. It is a not-for-profit founded in the United States but moved to Switzerland to benefit from some of the world's strongest data privacy laws. Appropriately to their name, their main DNS server is reached at 9.9.9.9 with a secondary server at 149.112.112.112. This is the option we will go with for our encrypted DNS requests.

Step 5: Configuring Cloudflared

  1. We need to create a user account on our Pi associated with the Cloudflared daemon. Run the following command:
    sudo useradd -s /usr/sbin/nologin -r -M cloudflared
  2. The specifics of the command:
    • The -s flag specifies what a user's default shell should be. Normally, it would be something like `/bin/bash` for a user to default to bash when they login. In this case, we pass `/usr/sbin/nologin` which means that this user has no shell and cannot run bash commands.
    • The -r flag tells the OS that this is a system account. No human user is ever going to actually use this account. You will never SSH into the Pi with the username “cloudflared”.
    • The -M flag tells the OS not to create a home directory. Again, no one is using this account except the deamon, so no need to clutter our file system with a pointless home directory.
    • Finally, we assign the username, which will be (but doesn't have to be) the same name as the daemon: cloudflared.
  3. Next, we need to create a service that will run the Cloudflared daemon. To do so, we need to create a configuration file. By placing the file in the /etc/systemd/system directory, giving the file the same name as the daemon and user account, and ending with the .service file extension, we create a service that will be run by the OS and to which we can pass instructions all using the same name: cloudflared. Run the following command to create this service configuration file:
    sudo nano /etc/systemd/system/cloudflared.service
  4. Enter the below text into the file. Note where we specify 9.9.9.9 and 149.112.112.112 as the upstream providers. This is what will send our requests to Quad9. We also specify port 5053.
    [Unit]
    Description=cloudflared DNS over HTTPS proxy
    After=syslog.target network-online.target

    [Service]
    Type=simple
    User=cloudflared
    ExecStart=/usr/local/bin/cloudflared proxy-dns --port 5053 --upstream https://9.9.9.9/dns-query --upstream https://149.112.112.112/dns-query
    Restart=on-failure
    RestartSec=10
    KillMode=process

    [Install]
    WantedBy=multi-user.target
  5. Save and exit the file.
  6. With our .service file created for Cloudflared, we can now tell the OS to create and start the service we just specified.
    sudo systemctl enable cloudflared
    sudo systemctl start cloudflared

Cloudflared is now running, ready to act as a proxy to send our DNS-over-HTTPS (DoH) requests to Quad9. To actually use it, we have to actually point Pi Hole to this proxy. We're essentially performing a handoff, passing a request from our device to Pi Hole to Cloudflared and finally to Quad9.

Step 6: Configuring Pi Hole to use DoH

  1. Navigate and log in to the Pi Hole admin web interface.
  2. Click on “Settings” in the lefthand navigation pane.
  3. On the Settings page, click on the “DNS” tab.
  4. Uncheck all of the upstream providers on the left. This is why whatever we picked in Step 2.4 didn't matter.
  5. On the right side of the screen, check the box for a custom option and enter the following:
    127.0.0.1#5053
  6. This is a loopback IP address on the Pi itself and the port being used by Cloudflared.
  7. Click “Save” to save these settings and go back to your SSH session.

You now have an ad blocking, privacy-enhancing DNS server running on your Raspberry Pi. For whole home coverage, change your router's DNS settings to point to your Pi's local IP address. Just bear in mind this can negatively affect certain device behaviors. iPhones, in particular, don't like it when you do this as it interferes with Apple's DNS relays.

The other option is to set device-by-device. Steps on configuring DNS settings are out of scope for this guide, but it should be relatively simple to lookup guides for particular devices and operating systems.