Skip to content

Raspberry Pi Gatekeeper

Go to | #1 | #2 | #3 | #4 | #5 | #6

Advertisements! I hate them, you hate them, we all hate them. What if I told you there was a way to block ad traffic from ever entering your network? Actually, this happened to me a few days ago by a coworker. I learned about a software called Pi-hole specifically designed for Raspberry Pi's that blocks all ad traffic. Sounds good, right? Now, how are you supposed to set it up?

Fresh OS Install

I first wanted to upgrade my Ubuntu version to 24.04, the latest version. (It was only released a few days ago!) I looked up some tutorials which made it seem easy to update from 22.04, which is what I thought I had. Turns out, I was still running 20.04 on my Pi! So I would need to step through the major versions, and I figured that I would prefer a clean install anyway. This shouldn't be a big deal, since I don't store any data directly on the Pi.

I downloaded the official Ubuntu Server ARM64 image and created a startup disk on a 64GB MicroSD card, but unfortunately I would get no signal when plugging in the Pi to my monitor. After a few tries, I decided to go the easy route and install the official Raspberry Pi imager. After a single try with using that utility, it worked perfectly.

Warning: If you create a startup disk, you will lose all existing data on that drive!

First-time Setup

Wifi

There were a few tricky things to set up for the first time: internet access (over wifi) and SSH access. To set up my wifi configuration, I needed to make changes to the netplan configuration file. I think the file could have slightly different names, but every time I've set it up, it was called 50-cloud-init.yaml.

Bash
sudo nano /etc/netplan/50-cloud-init.yaml

While editing the file, I added the lines under wifis:

YAML
network:
    ethernets:
        eth0:
            dhcp4: true
            optional: true
    wifis:
        wlan0:
            dhcp4: true
            access-points:
                "my-wifi-name":
                    password: "my-password"
    version: 2

After the file was saved, I ran the following commands. I'm not sure if generate is required, but I did it anyway.

Bash
sudo netplan generate
sudo netplan apply

To make sure of a successful internet connection, I simply pinged my website:

Bash
ping nicfv.com

Now that I had an internet connection running, I checked for any software updates, but surprisingly there were none. Seems like Ubuntu 24.04 ships with all the latest software. Cool!

Bash
sudo apt update

SSH

To update my SSH configuration, I edited the sshd_config file:

Bash
sudo nano /etc/ssh/sshd_config

There were 2 lines I needed to change in the file:

Text Only
PasswordAuthentication yes
KbdInteractiveAuthentication yes

Basically, these lines allow various forms of keyboard interaction for authentication, and specifically allow password authentication. After saving the changes, I needed to restart the SSH service:

Bash
sudo service ssh restart

At this point, if you are following along, it would be a good idea to make a note of your Pi's IP address using the command:

Bash
ip a # make note of the inet address under wlan0
I didn't need to do this, since I have configured a static IP in my router settings, and I have a subdomain that points directly to that IP.

At this point, I no longer need to have my keyboard or monitor plugged into the Pi, since I can now do everything from my PC through an SSH connection. I did reboot and re-test everything first since I made a lot of changes and wanted to make sure that nothing got corrupted.

Bash
sudo reboot 0

Authorize Key

Now I'm back on my PC. I had already generated an SSH key pair a long time ago with...

Bash
ssh-keygen -t rsa

...so I didn't need to redo it. However, I had to remove my Pi's old known host, so I lazily deleted the entire known_hosts file. If I don't do this, then I'll get network security errors and it won't allow me to connect.

Bash
rm ~/.ssh/known_hosts

The reprecussions of this is that whenever I connect to a "new" SSH server, I will get a warning saying that the authenticity of the host cannot be established. If you know what you're doing, just answer "yes" to that message and it goes away after that.

I need to copy over my public key to the Pi using this command. It will ask for the server password, since I enabled PasswordAuthentication earlier.

Bash
ssh-copy-id ubuntu@192.168.0.123

Now, I can finally connect to my Pi through SSH. From here I will disable the authentication methods I enabled earlier.

Bash
1
2
3
4
5
ssh ubuntu@192.168.0.123
# Welcome to Ubuntu 24.04 LTS
sudo nano /etc/ssh/sshd_config
sudo service ssh restart
logout

Pretty SSH Command

I lied with a few of my ssh commands. I simplified my SSH connection using a (pretty simple) configuration.

Bash
nano ~/.ssh/config
Text Only
1
2
3
4
Host pi
    User ubuntu
    HostName my-server-name.nicfv.com
    Port 123

my-server-name.nicfv.com contains an A+ dynamic DNS record that points to my public network address. Thanks, NameCheap! That means that I can use the much shorter and memorable alias to log into my Raspberry Pi.

Bash
ssh pi

So clean! From here I followed my own advice from my backup story (#1) to get my backup server up and running again.

Pi-Hole

Pi-hole is a DNS server that blocks ad traffic from entering your network. I decided that I wanted to install it on my Raspberry Pi through Docker, a containerized environment. I downloaded the sample docker-compose.yml file and placed it in my ~/pihole/ directory.

Docker

YAML
version: "3"
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      TZ: 'America/Los_Angeles'
      WEBPASSWORD: 'mypassword'
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    restart: unless-stopped
Bash
1
2
3
4
mkdir pihole
cd pihole
nano docker-compose.yml # paste contents of sample file here
snap install docker

Docker installed successfully, but unfortunately required sudo for every command. I was able to fix it using these commands:

Bash
sudo groupadd docker
sudo gpasswd -a $USER docker

After logging out and back in, I was now able to run docker commands without sudo. Now I can run the container using:

Bash
docker compose up -d

I was hit again with another issue. This time, 0.0.0.0:53 was already in use. Luckily I was able to find a StackOverflow post which outlined my issue exactly.

Bash
1
2
3
4
sudo nano /etc/systemd/resolved.conf # change DNSStubListener from yes to no
sudo systemctl restart systemd-resolved.service
sudo rm /etc/resolve.conf
sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

Networking

Now when I compose my docker container, it runs successfully! I can go to 192.168.0.123/admin which takes me directly to my Pi-hole dashboard! But even still, ads were not being blocked on my network because I had not yet changed my DNS settings in my router. To do this, I visited 192.168.0.1 (Motorola modem/router) and 192.168.1.1 (Linksys router). I have a weird daisy-chain configuration, like this:

graph LR

internet(["internet"])===>
motorola{{"Motorola"}}===>
linksys{{"Linksys"}}

motorola-...->tv["TV"]
motorola-...->cam["Camera"]
motorola-...->pi["Raspberry Pi"]

linksys-.->laptop["MacBook"]
linksys-.->pc["Home PC"]
linksys-.->print["Printer"]

Basically, I changed my Motorola DNS settings (Advanced > Status > Connection > IPv4 DNS Servers) to the following, and then restarted the router:

Description Value
Obtain Automatically from MSO Disabled
Primary DNS 192.168.0.123
Secondary DNS 1.1.1.1

For the Linksys router, first I disabled the DHCP server, which was a big mistake. Everything that was connected to the Linksys all of a sudden lost internet connection, even after performing a restart on all devices. After a lot of guess-and-check, I went into my MacBook, and connected to the Motorola's wifi. From here I could at least connect to the internet. I assigned a static IP of 192.168.1.99 to be on the same subnet as the Linksys. What's weird was that I had to keep the gateway assigned to 192.168.0.1. But then finally I could log back into the web interface for the Linksys. I re-enabled the DHCP server, and changed my Linksys DNS settings (Connectivity > Local Network) to the following:

Description Value
Static DNS 1 192.168.0.123
Static DNS 2 1.1.1.1
Static DNS 3 8.8.8.8

After applying the update and restarting everything, I was finally back on track. My PC and MacBook could successfully connect to the internet through the Linksys. I even printed a test page just to make sure the wireless printer still worked. At this point, all my devices on the Linksys router were successfully blocking ad traffic!

Unsolved Issues

Oddly enough, I'm having more trouble with the devices on the Motorola router than I did on the Linksys router, even though the Raspberry Pi is connected to the Motorola. Luckily, for my TV, I was able to directly change the DNS server in the network settings. From the Pi-hole dashboard, it appears to have worked, however the TV's browser must be caching some files because I can still visit blocked websites.

When I connect the MacBook to the Motorola wifi, it doesn't see the Motorola's DNS configuration (in Settings > Network > Wifi > Details > DNS) at all.

DNS Servers
75.75.75.75
75.75.76.76
2001:558:feed::1
2001:558:feed::2

The same list is shown with the terminal command:

Bash
scutil --dns

However, I can work around this by manually setting the DNS to 192.168.0.123, but the issue here is that I have to do this every time I change networks (e.g. if I bring the MacBook to work.)

Another issue is my Android smartphone. When I connect it to the Linksys, I cannot access blocked domains. But once again, as soon as I connect to the Motorola, those domains are suddenly working again. I tried poking around in the network settings, but I could not figure out how to change the DNS. (...I have an old Android.)

Lastly, Pi-hole has a nice feature where you can access the dashboard with pi.hole/admin in a web browser. Unfortunately, this is not working for me. I found a forum thread with my issue exactly, and the original poster claims to have figured out the solution. Frustratingly, he did not post his solution! After a few tries, I gave up on this, since I am still able to access it via the 192.168.0.123/admin workaround.

Conclusion

Despite some issues with the networking portion of this project, as long as I do the bulk of my internet usage from the Linksys router (which I already do anyway), the Pi-hole server is doing a decent job of blocking advertisements. Some YouTube ads still get through, but the page won't load when I accidentally (or purposefully) click on them. My major appreciation goes to the Pi-hole dashboard, which shows me what requests were made from which IP at any given time. The one limitation of this is that everything under the Linksys router will show the IP address for the router itself instead of the subnet IP. Either way, this is a major improvement onto my home network security and monitoring, and while it had its difficulties, was still doable for someone with limited experience.