Pi-hole on Raspberry Pi with IPv6
Setting up Pi-hole with Unbound on Raspberry Pi 4 B with IPv6 support
I’ve had a Raspberry Pi 4B sitting in my cabinet for a few months now. I dusted it off and realized that the SD card was busted. Got a replacement 64GB U3 A2 card and got it up and running with Ubuntu server. The primary intended use was to run docker with DB containers that I use for my side projects such as Postgres/MySQL/MongoDB.
My current home network consists of several routers for WiFi reachability. I try to ensure 5Ghz coverage to all my devices. Due to the concrete walls a single router does not suffice, hence a home made mesh.
The earlier ISP was a IPv4 only provider. Easy to setup. Worked out of the box. To safeguard other users of the network, I use a privacy sensitive DNS provider, Adguard. The issue with Adguard DNS was no geo proximity. It caused large ping times, as the closest CDN was never picked.
When I moved to my new ISP which supports IPv6, I decided to also deploy Pi-hole alongwith my docker containers.
Pi-hole is quite easy to deploy, especially with the auto install script.
curl -sSL https://install.pi-hole.net | bash
Once I followed the steps I got Pi-hole running out of the box. As suggested you have to change your router settings to send the IP address of your Pi-hole server as your local DNS. Done and done.
Ads still show!
To ensure that I wasn’t fudging up DHCP/DNS discovery I used scutil:
scutil --dns resolver #1 search domain : lan nameserver : 2405:201:xxxx:xxxx:xxx:xxxx:4209:2091 nameserver : fe80::a204:60ff:fe43:3005%en0 nameserver : 192.168.2.50 if_index : 6 (en0) flags : Scoped, Request A records, Request AAAA records reach : 0x00020002 (Reachable,Directly Reachable Address)
IPv4 looked good.
192.168.2.50 is the IP of my pi-hole server.
However, the IPv6 didn’t belong to pi-hole. The default ISP setting was to use stateless IPv6 config and DNS was being advertised by the router. It was using my upstream DNS (ISP) server.
To fix this, I made the following changes:
IPv6 on pi-hole
- Get your Ipv6 address for pi-hole
ip addr show
- Enable IPv6 support on pi-hole
- Set the
This should’ve already been done during the installation of pi-hole but if isn’t, you can manually set it up using the address above
A neat trick I learnt while assigning static IPv6 addresses is to the use the same suffix as IPv4. Easy to remember and deal with.
systemctl restart pihole-FTL
- Enable AAAA query analysis for Pi-hole
Pi-hole by default will only analyse
A queries, so we need to add support for
DBINTERVAL=60 MAXDBDAYS=7 AAAA_QUERY_ANALYSIS=yes PRIVACYLEVEL=0
I also added a throttling parameters to not wear out the SD Card.
- Refresh Pi-hole
Reboot the server. Fetch gravity lists again
- Stateful DHCPv6
My attempts at trying to get DHCP v4 and v6 from pi-hole failed. This is probably due to wrong assumptions of SLAAC + RA.
- Debug Pi-hole
At the end I made sure everything is kosher by running diagnosis on Pi-hole
Setting up Unbound
I do not like using any of the open DNS servers. They have their place and provide a lot of value but it’s not for me. I prefer a combo of ad-block and recursive DNS. Unbound works perfectly with Pi-hole. Setting it up is again very simple.
apt install unbound
Update the unbound config to support Pi-hole
Make a note of the port, the default port
53 is used by Pi-hole and must be changed.
server: interface: 0.0.0.0 interface: ::0 port: 5335 access-control: 192.168.2.0/24 allow access-control: 127.0.0.0 allow access-control: 2001:db8:dead:beef::/48 allow # unbound optimisation num-threads: 4 msg-cache-slabs: 16 rrset-cache-slabs: 16 infra-cache-slabs: 16 key-cache-slabs: 16 outgoing-range: 206 so-rcvbuf: 4m so-sndbuf: 4m so-reuseport: yes rrset-cache-size: 100m msg-cache-size: 50m # unbound security do-ip4: yes do-ip6: yes do-udp: yes do-tcp: yes cache-max-ttl: 86400 cache-min-ttl: 3600 hide-identity: yes hide-version: yes minimal-responses: yes prefetch: yes use-caps-for-id: yes verbosity: 1 harden-glue: yes harden-dnssec-stripped: yes # download from ftp://ftp.internic.net/domain/named.cache # root-hints: "/var/lib/unbound/root.hints" # Ensure privacy of local IP ranges private-domain: "lan" private-address: 192.168.0.0/16 private-address: 169.254.0.0/16 private-address: 172.16.0.0/12 # private-address: 10.0.0.0/8 private-address: fd00::/8 private-address: fe80::/10
Tweak it as per your needs and restart Unbound
systemctl restart unbound
root@pi-desktop:~# dig sigok.verteiltesysteme.net @127.0.0.1 -p 5335
; <<>> DiG 9.16.6-Ubuntu <<>> sigok.verteiltesysteme.net @127.0.0.1 -p 5335 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48863 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;sigok.verteiltesysteme.net. IN A ;; ANSWER SECTION: sigok.verteiltesysteme.net. 3600 IN A 188.8.131.52 ;; Query time: 499 msec ;; SERVER: 127.0.0.1#5335(127.0.0.1) ;; WHEN: Tue Feb 23 08:53:17 IST 2021 ;; MSG SIZE rcvd: 71
root@pi-desktop:~# dig sigfail.verteiltesysteme.net @127.0.0.1 -p 5335
; <<>> DiG 9.16.6-Ubuntu <<>> sigfail.verteiltesysteme.net @127.0.0.1 -p 5335 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 56203 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;sigfail.verteiltesysteme.net. IN A ;; Query time: 1147 msec ;; SERVER: 127.0.0.1#5335(127.0.0.1) ;; WHEN: Tue Feb 23 08:53:43 IST 2021 ;; MSG SIZE rcvd: 57
At least for IPv4, you can run the debug tool to make sure DHCP is correct.
root@pi-desktop:~# pihole-FTL dhcp-discover Scanning all your interfaces for DHCP servers Timeout: 10 seconds * Received 301 bytes from eth0:192.168.2.1 Offered IP address: 192.168.2.113 Server IP address: 192.168.2.1 Relay-agent IP address: N/A BOOTP server: (empty) BOOTP file: (empty) DHCP options: Message type: DHCPOFFER (2) server-identifier: 192.168.2.1 lease-time: 3600 ( 1h ) renewal-time: 1800 ( 30m ) rebinding-time: 3150 ( 52m 30s ) netmask: 255.255.255.0 broadcast: 192.168.2.255 router: 192.168.2.1 dns-server: 192.168.2.50 dns-server: 192.168.2.50 domain-name: "lan" --- end of options ---
Switching Pi-hole to use unbound
Disable all Upstream DNS servers and add custom DNS that you setup for Unbound. Use the loopback addresses for Unbound:
That should be it! Hope you enjoyed reading the article.