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
Create below folders and files with the right path with
Let’s get recursive DNS server unbound configuration right first.
Create some config files under
/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 192.168.1.1" # PTR Record #local-data-ptr: "192.168.1.1 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.
server: # If no logfile is specified, syslog is used # logfile: "/var/log/unbound/unbound.log" verbosity: 0 access-control: 172.16.0.0/12 allow access-control: 127.0.0.0/8 allow access-control: 10.0.0.0/8 allow access-control: 192.168.0.0/16 allow interface: 0.0.0.0 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 # I have to quote out this root-hints, as it causing container endless restarting for a new installation. You can add root-hints back after first run. #root-hints: “/opt/unbound/etc/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: 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 #plex private-domain: plex.direct
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.
docker-compose.yml in your favourite directory with the content below.
version: '3' networks: dns_net: driver: bridge ipam: config: - subnet: 172.20.0.0/16 services: pihole: container_name: pihole hostname: pihole image: pihole/pihole:latest networks: dns_net: ipv4_address: 172.20.0.6 ports: - "53:53/tcp" - "53:53/udp" - "80:80/tcp" - "443:443/tcp" environment: - 'TZ=Australia/Sydney' - 'WEBPASSWORD=yourpasswd' - 'DNS1=172.20.0.7#5053' - 'DNS2=no' volumes: - '/home/pi/pihole/etc-pihole/:/etc/pihole/' - '/home/pi/pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/' restart: unless-stopped unbound: container_name: unbound image: mvance/unbound-rpi:latest networks: dns_net: ipv4_address: 172.20.0.7 volumes: - /home/pi/unbound:/opt/unbound/etc/unbound ports: - "5053:5053/tcp" - "5053:5053/udp" healthcheck: 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 @172.20.0.7 -p 5053
dig www.google.com @127.0.0.1 -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 @172.20.0.6 -p 53
dig www.google.com @127.0.0.1 -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.