Ad blockling docker image

I’ve been wanting to block ads on a dns level on my home network for awhile lately.
Today wasn’t going to be a productive day, so I said I may as well make it productive.

Setting up a pi hole is the obvious choice, but I couldn’t find any SD cards after moving a few months ago. I did want to to setup on a dedicated pi to have some redundancy in case my home server was down, but I decided to be a grown up about and set up a docker image to do it.

Fortunately a docker image already exists for this project. It does want to take over ports 53, 80, but I’m already using them for a named daemon for openvpn and nginx.

Instead I decided to add a vip to the docker host and have it used 53 and 80 for the pi hole bound on that address instead.
It’s quite easy.

ip addr add 10.2.2.250/24

And then a systemd unit to to make it persistent across reboots.

view /etc/systemd/system/eno1-vip.service
[Unit]
Description=Add vip to eno1 after dhcp
Requires=dhcpcd@eno1.service
[Service]
ExecStart=/usr/bin/ip addr add 10.2.2.250/24 dev eno1
[Install]
WantedBy=default.target

This looks slightly at odds with itself, but I still prefer to use DHCP for the primary IP on the box.

The docker image is built with:

#!/bin/bash
IMAGE='diginc/pi-hole:alpine'
NIC='eno1'
IP="10.2.2.250"
#opennicproject.org public DNS
DNS1="5.9.49.12"
DNS2="5.135.183.146"
#Bind ports to the vip
docker run -p 10.2.2.250:53:53/tcp -p 10.2.2.250:53:53/udp -p 10.2.2.250:80:80 \
  --cap-add=NET_ADMIN \
  -e ServerIP="$IP" \
  -e DNS1=$DNS1 -e DNS2=$DNS2 \
  --name pihole \
  -d "$IMAGE"

This will result in the following iptables rules:

# iptables -t nat --list
....
Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
DNAT       tcp  --  anywhere             Farnsworth           tcp dpt:http to:172.17.0.2:80
DNAT       tcp  --  anywhere             Farnsworth           tcp dpt:domain to:172.17.0.2:53
DNAT       udp  --  anywhere             Farnsworth           udp dpt:domain to:172.17.0.2:53

and the systemd unit for the pi hole docker image will look like:

view /etc/systemd/system/pihole.service
[Unit]
Description=pihole ad blocker
Requires=docker.service
After=eno1-vip.service

[Service]
Restart=always
ExecStart=/usr/bin/docker start -a pihole
ExecStop=/usr/bin/docker stop -t 2 pihole

[Install]
WantedBy=default.target

I had issue getting the http working on my openwrt setup. It did transpire to be a safety mechanism within dnsmasq, it won’t return a DNS record for an address that is the DNS server. This is due to rebind_protection.
Edit /etc/config/dhcp and set:

config dnsmasq
        option rebind_protection '0'

and restart dnsmasq. You’ll know this will have worked as you should be able to

dig +short pi.hole
10.2.2.250

In short it wasn’t too bad. I need to explore further how to incorporate a local DNS server, but I enjoyed putting this together and I may use docker more with this vip setup.