Pi-hole with BIND

As I wrote in my review of the iPad Pro, as the device doesn’t have a terminal of its own, I’ve set up a Raspberry Pi 4 as a terminal I can access from anywhere.

On top of that, however, I’ve configured a few things to make it accessible, and slowly it became one of my main servers—a tiny one—doing some crucial tasks. Besides being the gateway to my LAN, using OpenVPN, its running my network’s BIND 9 DNS server.

This makes it really easy to assign names to my devices on my network. Of course, I could settle with mDNS and have automatic .local domain names for every computer. But that doesn’t work via VPN—it just wasn’t designed for this. Hence the DNS server with my very own local top-level domain. It’s more setup, but better at the end, especially if some devices don’t work with mDNS.

There was one problem, however. I have apps on my iPhone and iPad to help me block domains pointing to ads, trackers, malware, etc. That’s good, but, shouldn’t my DNS server take care of that? Wouldn’t it be great if I could stay connected to my VPN anywhere and be protected all the time, while having access to my personal network?

Turns out Pi-hole is great for that. It’s a special DNS server that will block unwanted sites anywhere on your network. That sounds perfect, but, what if I already had my own DNS server that I also want to run?

As you can imagine, it wasn’t that hard. All I had to do, is to have my BIND 9 DNS server run on a different port other than the default, 53, and have Pi-hole use that server as its upstream. It worked well.

Alternative minimalist solution: bind-adblock

But later, I found an even simpler solution, bind-adblock, which merely lets you download lists of domain names from URLs you provide and adds them to a zone in your BIND configuration. That’s all I needed.

As I described in a recent tweet, I ended up sticking with the BIND-only solution and uninstalled Pi-hole:

Still, there are a few things I’ve learned along the way that maybe you’ll want to know. I wrote them on Twitter already, but since I delete old tweets often, perhaps it’s best I write those notes below.

Using Pi-hole without Web UI: Where’s the config?

I wanted to save on resources, so I opted out of installing the Web server to configure Pi-hole. Besides, I’m comfortable editing config files in the /etc directory, so I didn’t see a problem.

But, Pi-hole has barely any config file. How could I set it up?

Not to worry. Most of the config is in a SQLite database, in /etc/pihole/gravity.db. You can open it to explore and make modifications:

$ sqlite3 /etc/pihole/gravity.db

Adding block lists

Pi-hole comes with two very basic block lists. You can find many more of them at FilterLists. To add them to Pi-hole without using a Web interface, you can open the config database, as mentioned above, and add the URLs of the lists using SQL:

# Open the config DB in SQLite:
$ sqlite3 /etc/pihole/gravity.db

sqlite> -- Insert block list URLs:
sqlite> insert into adlist (address) values ('url1'), ('url2');

sqlite> -- Verify the update:
sqlite> .headers on
sqlite> select * from adlist;
sqlite> .quit

# Reload block lists:
$ pihole -g

Change default port of BIND 9

The default DNS port is 53. If you need to change it for BIND 9, open /etc/bind/named.conf or /etc/bind/named.conf.options and add these lines (or add the whole section if options doesn’t already exist):

// /etc/bind/named.conf.options (or /etc/bind/named)
// This example will set the port to 533.

options {
  listen-on port 533 { any; };
  listen-on-v6 port 533 { any; };
  query-source port 533;
}

// Be sure there are no other listen-on or listen-on-v6.

Set upstream DNS servers with ports in Pi-hole

When it is time to specify upstream DNS servers in Pi-hole and you need to use your BIND 9 server on a special port, you can append a hash with a number:

127.0.0.1#533

As I already mentioned, I stuck with the minimalist solution bind-adblock offers. Nevertheless, I hope these tips may be of use to you.