Pi-hole on Raspberry Pi with IPv6
Tags: beginners, opensource, linux, learning
Published: 2021-02-23 03:35:23

---
title: "Pi-hole on Raspberry Pi with IPv6"
tags: ["beginners", "opensource", "linux", "learning"]
categories: ["Infrastructure"]
published: true
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n34sbe8edir2d0y4jy7l.png
canonical_url: https://arif.co/posts/pi-hole-raspberry-pi-ipv6/
---

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. 

![Home Network Layout](https://arif.co/posts/pi-hole-raspberry-pi-ipv6/network-layout.png)

### Installing Pi-hole

Pi-hole is quite easy to deploy, especially with the auto install script.

```bash
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.

![Pi-hole home](https://arif.co/posts/pi-hole-raspberry-pi-ipv6/pi-mob-home.png)

### The Problem

Ads still show!

To ensure that I wasn't fudging up DHCP/DNS discovery I used scutil: 

```bash
scutil --dns

resolver #1
  search domain[0] : lan
  nameserver[0] : 2405:201:xxxx:xxxx:xxx:xxxx:4209:2091
  nameserver[1] : fe80::a204:60ff:fe43:3005%en0
  nameserver[2] : 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

```bash
ip addr show
```

* Enable IPv6 support on pi-hole

![IPv6 Slaac](https://arif.co/posts/pi-hole-raspberry-pi-ipv6/ph-slaac.png)

* Set the `IPV6_ADDRESS` add `/etc/pihole/setupVars.conf`

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

```bash
IPV4_ADDRESS=192.168.2.50/24
IPV6_ADDRESS=2405:xxx:xxxx:xxxx::50/64
```

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.

Restart FTL:

```bash
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 `AAAA`.

```bash
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

```bash
pihole -g
```

* Stateful DHCPv6

![ISP Stateful DHCPv6](https://arif.co/posts/pi-hole-raspberry-pi-ipv6/jio-dhcpv6.png)

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

```bash
pihole -d
```

### 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.

```bash
apt install unbound
```

Update the unbound config to support Pi-hole

`/etc/unbound/unbound.conf.d/pi-hole.conf`

Make a note of the port, the default port `53` is used by Pi-hole and must be changed.

```yaml
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

```bash
systemctl restart unbound
```

### Check unbound

Will pass:
```bash
root@pi-desktop:~# dig sigok.verteiltesysteme.net @127.0.0.1 -p 5335
```

```bash
; <<>> 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	134.91.78.139

;; 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
```

Will fail:
```bash
root@pi-desktop:~# dig sigfail.verteiltesysteme.net @127.0.0.1 -p 5335
```

```bash
; <<>> 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
```

### DHCP Confirmation

At least for IPv4, you can run the debug tool to make sure DHCP is correct.

```bash
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:

IPv4 - `127.0.0.1#5335`

IPv6 - `::1#5335`

![Unbound with Pi-hole](https://arif.co/posts/pi-hole-raspberry-pi-ipv6/pi-unbound.png)

That should be it! Hope you enjoyed reading the article.