PiHole setup

From Smith family
Server setup
← Previous Next →
Backups Discourse

I use PiHole as a layer in my DNS setup. PiHole filters DNS requests and drop requests to known advertising and tracking sites. The idea is that you don't leak information to them, and adverts don't get served on web sites you visit (making them faster to load).

Inserting PiHole into the DNS query chain requires some fiddling.

To keep things simple, I use the an instance of PiHole in a Docker container. That minimises installation worries, and helps keep PiHole separated from my existing services (DNS and Web servers). It does mean that PiHole needs its own IP numbers, and its own hostnames.

The DNS query chain looks like this:

+--------+      +--------+      +--------+      +----------+      +------------+ 
| Client | ---> | Router | ---> | PiHole | ---> | Bind DNS | ---> | Upstream   |
| device |      +--------+      +--------+      +----------+      | DNS server | 
+--------+                                                        +------------+

I have two PiHole instances running; one on my server machine, one on my desktop machine. This gives redundancy when one of them falls over. I considered using Nebula Sync to exchange configuration settings between the two PiHoles, but decided that was unnecessary in my case.

Additional IP numbers

PiHole needs its own IP numbers (IPv4 and IPv6) to listen on. These are set up in the Netplan config files, /etc/netplan/01-network-manager-all.yaml:

On the both machine, add the new IPs for the PiHole:

# Let NetworkManager manage all devices on this system
network:
 version: 2
 renderer: NetworkManager
 ethernets:
   eno1:
    dhcp4: no
    dhcp6: no
    addresses: [10.191.106.252/24,
...
      10.191.106.242/24,               # IPs for Pi-hole container
      2a02:390:62aa::8100:53/64
      ]

(Use different IPs for the two machines)

Apply the changes on both machines.

root@desktop:~# netplan apply

Hostnames

Now we have IP numbers, we give them names. On the server machine, edit the zone files /etc/bind/db.domain.tld to make reference to the PiHoles.

; Name servers
ns1 IN  AAAA  aaaa:bbbb:cccc:dddd::53
    IN  A     192.168.1.252
ns2 IN  AAAA  aaaa:bbbb:cccc:dddd::54
    IN  A     192.168.1.251
pihole IN  AAAA  aaaa:bbbb:cccc:pppp::53
    IN  A     192.168.1.242
pihole2 IN  AAAA  aaaa:bbbb:cccc:pppp::54
    IN  A     192.168.1.241

Refresh DNS then check the new names are available.

root@server:~# rndc reload
user@desktop:~$ host pihole

Prevent other services listening

The PiHole container needs to connect to ports 53, 80, and 443 (DNS, HTTP, and HTTPS). The default configuration is for the existing Bind9 and Apache servers to listen to all IPs on these ports. This will conflict with PiHole, so we need to restrict Bind9 and Apache to listen to only the interfaces they actually serve.

Do this on both server and desktop machines.

Bind9 config

Edit /etc/bind/named.conf.options

//      listen-on-v6 { any; };
 listen-on-v6 { aaaa:bbbb:cccc:dddd::53; ::1; ::53; };
//  listen-on { any; };
 listen-on { 192.168.1.252; 127.0.0.1; 127.0.0.53; };

(change the IP numbers for the interfaces on the desktop machine.)

Refresh DNS.

root@server:~# rndc reload

Apache2 config

Edit /etc/apache2/ports.conf

Listen 127.0.0.1:80
Listen [::1]:80

Listen 192.168.1.252:80
Listen [aaaa:bbbb:cccc:dddd::443]:80
Listen [aaaa:bbbb:cccc:eeee::443]:80

<IfModule ssl_module>
 # Listen 443
 Listen 127.0.0.1:443
 Listen [::1]:443

 Listen 192.168.1.252:443
 Listen [aaaa:bbbb:cccc:dddd::443]:443
 Listen [aaaa:bbbb:cccc:eeee::443]:443
   # NameVirtualHost *:443
</IfModule>

<IfModule mod_gnutls.c>
 # Listen 443
 Listen 127.0.0.1:443
 Listen [::1]:443

 Listen 192.168.1.252:443
 Listen [aaaa:bbbb:cccc:dddd::443]:443
 Listen [aaaa:bbbb:cccc:eeee::443]:443

   # NameVirtualHost *:443
</IfModule>

(change the IP numbers for the interfaces on the desktop machine.)

Refresh Apache2.

root@server:~# systemctl restart apache2.service

Docker configuration

Copy the PiHole docker file from the PiHole site into /etc/pi-hole/docker-compose.yml . Make the changes shown.

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    hostname: pihole                # Add this
    networks:                       # Add these two lines to enable IPv6 in Docker
      - pihole-network
    ports:                          # Adjust these, according to your IP numbers
      # DNS Ports
      - "192.168.1.252:53:53/tcp"
      - "10.191.106.222:53:53/udp"
      - "[aaaa:bbbb:cccc:pppp::53]:53:53"
      # Default HTTP Port
      - "192.168.1.252:80:80/tcp"
      - "[aaaa:bbbb:cccc:pppp::53]:80:80/tcp"
      # Default HTTPs Port. FTL will generate a self-signed certificate
      - "192.168.1.252:443:443/tcp"
      - "[aaaa:bbbb:cccc:pppp::53]:443:443/tcp"
    environment:
      FTLCONF_webserver_api_password: 'your-password-here'

# Add this stanza (at top level) to enable a network that supports IPv6
networks:
  pihole-network:
    enable_ipv6: true

Then create the container.

root@server:/etc/pi-hole# docker compose up -d

Do the same on the desktop machine.

You may need to increase the inotify limit:

root@desktop:# cat /proc/sys/fs/inotify/max_user_instances
128
root@desktop:# echo "fs.inotify.max_user_instances=500" >> /etc/sysctl.conf
root@desktop:# sysctl -p
root@desktop:# docker compose restart pihole

You should be able to log into the PiHole's web interface at https://pihole.domain.tld/admin/ to view what it's doing and make changes.

PiHole configuration

In the PiHole web interface, in Settings > DNS > Upstream DNS servers > Custom DNS Servers , set your local Bind9 DNS servers as the upstream servers.

192.168.1.251
192.168.1.252
aaaa:bbbb:cccc:dddd::53
aaaa:bbbb:cccc:dddd::54

Also set the Settings > DNS > Conditional forwarding section, enable "Expert" settings rather than "Basic", and allow PiHole to do reverse DNS lookups on the local network. Add these lines.

true,192.168.1.0/24,192.168.1.251,domain.tld
true,aaaa:bbbb:cccc:dddd::1/64,aaaa:bbbb:cccc:dddd::53,domain.tld

Router configuration

We now need to tell the router to direct DNS queries to the PiHoles.

The details will depend on your router. I'm using a Unifi Dream Machine.

I connect to the router's web interface, go to Settings > Internet > Primary .

  • Under IPv4 configuration and IPv6 configuration, I uncheck the DNS Server: Auto and add the IP numbers of the PiHoles.

(This makes the router connect to the Piholes.)

I then connect to the router's web interface, go to Settings > Networks > Select my network .

  • In the IPv4 tab, under DHCP Service Management, uncheck DNS Server: Auto and add the IP numbers of the two PiHoles.
  • In the IPv6 tab, uncheck DNS Server: Auto and add the IP numbers of the two PiHoles.

(This makes the DHCP clients connect directly to the PiHoles, so I can see the different clients in the PiHole logs.)