Pihole + unbound docker setup on Raspberry Pi

Pihole is DNS based Ad blocking solution. It can also be used to enhance your home network security by filtering out malicious domain and provide privacy protection by preventing unnecessary telemetry data leaking out.

I have mentioned couple times in my previous posts. As pihole project has very good documentation of installation, even with the configuration of unbound recursive DNS server, I don’t feel the need to repeat the normal straightforward installation process. However, there’s not much guide talking about the details of pihole + unbound setup in docker container. And during the migration from straight installation to docker containers, I met lot of unexpected issues and mistakes. I think it worth to share my experience and my configuration to save your time doing the troubleshooting.

Why move pihole and unbound to docker container?

Docker adds another abstraction layer on top of OS.

It increases the complexity of initial configuration, but gives you flexibility of future maintenance and migration.

Neat and clean is the main reason people like docker. No need to install hundreds of library and packages into Operation System which may mess up.

Each service is a container. Configuration can be managed by file and docker-compose.yaml. Very quick to replicate the configuration to different devices.

And by using Raspberry pi, considering the SD card may wear after constant write, to backup the docker container configuration is the easiest way to recovery the configuration.


So how to setup pihole and unbound into docker container on Raspberry pi?


You need a Raspberry Pi and with OS (Raspbian) installed.

Raspbian has already configured with SSH access and static IP address / DNS resolver.

Raspbian installed docker packages including docker-compose. (search google or docker website if you don’t know how to)

File and Structure

Assume you have logged in Raspbian with user ‘pi‘, your home directory will be /home/pi/ .

Create below folders and files with the right path with mkdir command.

mkdir /home/pi/pihole

mkdir /home/pi/pihole/etc-dnsmasq.d

mkdir /home/pi/pihole/etc-pihole

mkdir /home/pi/unbound

Unbound Configuration

Let’s get recursive DNS server unbound configuration right first.

Create some config files under /home/pi/unbound/

/home/pi/unbound/a-records.conf this file is mandatory required as we mapped volume of unbound docker image, otherwise the container will fail to start. You can leave it empty or put your local custom a records if you need. Below is example.

# A Record
#local-data: "somecomputer.local. A"

# PTR Record
#local-data-ptr: " somecomputer.local."

/home/pi/unbound/unbound.conf main configuration file unbound service. It will automatically generate a default one if you not create it. For this guide, let’s define the unbound.conf first. Example below, modify by your situation.

# If no logfile is specified, syslog is used
# logfile: "/var/log/unbound/unbound.log"
verbosity: 0

access-control: allow
access-control: allow
access-control: allow
access-control: allow
port: 5053
do-ip4: yes
do-udp: yes
do-tcp: yes

# May be set to yes if you have IPv6 connectivity
do-ip6: no

# You want to leave this to no unless you have *native* IPv6. With 6to4 and
# Terredo tunnels your web browser should favor IPv4 for the same reasons
prefer-ip6: no

# Use this only when you downloaded the list of primary root servers!
# If you use the default dns-root-data package, unbound will find it automatically
#root-hints: "/var/lib/unbound/root.hints"

# Trust glue only if it is within the server's authority
harden-glue: yes

# Require DNSSEC data for trust-anchored zones, if such data is absent, the zone becomes BOGUS
harden-dnssec-stripped: yes

# Don't use Capitalization randomization as it known to cause DNSSEC issues sometimes
# see https://discourse.pi-hole.net/t/unbound-stubby-or-dnscrypt-proxy/9378 for further details
use-caps-for-id: no

# Reduce EDNS reassembly buffer size.
# Suggested by the unbound man page to reduce fragmentation reassembly problems
edns-buffer-size: 1472

# Perform prefetching of close to expired message cache entries
# This only applies to domains that have been frequently queried
prefetch: yes

# One thread should be sufficient, can be increased on beefy machines. In reality for most users running on small networks or on a single machine, it should be unnecessary to seek performance enhancement by increasing num-threads above 1.
num-threads: 1

# Ensure kernel buffer is large enough to not lose messages in traffic spikes
so-rcvbuf: 1m

# Ensure privacy of local IP ranges
private-address: fd00::/8
private-address: fe80::/10

private-domain: plex.direct

And download root.hints to /home/pi/unbound/

wget -O root.hints https://www.internic.net/domain/named.root

Unbound initial configuration is done.

Pihole and Docker Compose setup

This is the key part of this guide.

Create docker-compose.yml in your favourite directory with the content below.

version: '3'

    driver: bridge
        - subnet:

    container_name: pihole
    hostname: pihole
    image: pihole/pihole:latest
    - "53:53/tcp"
    - "53:53/udp"
    - "80:80/tcp"
    - "443:443/tcp"
    - 'TZ=Australia/Sydney'
    - 'WEBPASSWORD=yourpasswd'
    - 'DNS1='
    - 'DNS2=no'
    - '/home/pi/pihole/etc-pihole/:/etc/pihole/'
    - '/home/pi/pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/'
    restart: unless-stopped
    container_name: unbound
    image: mvance/unbound-rpi:latest
    - /home/pi/unbound:/opt/unbound/etc/unbound
    - "5053:5053/tcp"
    - "5053:5053/udp"
      disable: true
    restart: unless-stopped

Start the services

Let’s start unbound container first

sudo docker-compose up -d unbound

If everything goes right, you will see something says pi_dns_net has been created a new container is up.

You can now test if unbound is working as expected

dig www.google.com @ -p 5053

dig www.google.com @ -p 5053

If all return normal results then unbound is up running.

Then start pihole container.

sudo docker-compose up -d pihole

You can test if pihole is working

dig www.google.com @ -p 53

dig www.google.com @ -p 53

You can also try to access http://your-Raspberry-pi-ip/admin/index.php to configure pihole blocklist and etc.

Override container configuration

If there’s any configuration you need to change, you can first add environment into docker-compose file if the image support.

Otherwise, you can touch the configuration file directly.

For example, if you want to reduce the pihole cache size from 10000 to 0, let unbound do the caching. You can modify /home/pi/pihole/etc-dnsmasq.d/01-pihole.conf to set cache-size=0 . Save the file then restart dnsmasq service from pihole admin portal.

If you want to add a custom configuration file for pihole or unbound, just add *.conf file under the mapped volume.

Then restart the container.

sudo docker stop <container name>

sudo docker-compose up -d <container name>

It will usually recreate the container if there’s any configuration change.

Commands to troubleshoot

sudo docker ps

sudo docker inspect <container name, such as pihole or unbound>

sudo docker logs pihole

Maintenance and Update

sudo docker pull pihole/pihole:latest

sudo docker pull mvance/unbound-rpi:latest

sudo docker stop pihole

sudo docker stop unbound

sudo docker rm pihole

sudo docker rm unbound

sudo docker-compose up -d unbound

sudo docker-compose up -d pihole


Hope this post help you and save your time. Please leave comment if you have any question.


Written by Felix. Licensed under CC BY-NC-SA 3.0 Unported.

Leave a Reply



Pihole + unbound docker setup on Raspberry Pi
Pihole is DNS based Ad blocking solution. It can also be used to enhance your home network security by filtering out malicious domain and provide privacy protection by preven…
Scan QR code to continue reading