I have recently been able to run PiHole on OpenWrt x86 using Docker. Before OpenWrt I had an Ubuntu Docker host which was running the PiHole container. The PiHole container was attached to the LAN network using Linux/Docker macvlan. Also for the Ubuntu Host to be able to ping the PiHole container, a workaround posted on stackoverflow was applied which creates a linux macvlan that the container uses. Giving PiHole an IP Address different than the IP Address of the host greatly simplifies the setup and prevents any conflict with DNS/DHCP/HTTP ports overlapping.
The idea for setting this up on OpenWrt is very similar and so would like to share it with rest of the community and get some feedback. Bear in mind that this was tested on OpenWrt x86 and may differ or otherwise be unsupported for other targets. The goal of this tutorial is to setup PiHole as an AdBlock DNS server only without using it's DHCP capabilities (DHCP is handled by OpenWrt).
opkg update && opkg install docker luci-app-dockerman docker-compose
Here the MACVLAN interface will be created which is a virtual interface bridged to current LAN interface. This interface will later be used by Docker and PiHole.
Look for the
config interface 'lan' section and note down the device from the
option device line. In my case it is
Add the following at the end of the file. The key part here is
option device and
option name which is the same device as in the
lan section with
config interface 'macvlan' option proto 'static' option defaultroute '0' option netmask '255.255.255.255' option device 'br-lan.20' option ipaddr '192.168.1.2' config device option type 'macvlan' option ifname 'br-lan' option mode 'bridge' option name 'br-lan.20' option acceptlocal '1' config route option interface 'macvlan' option target '192.168.1.3' option netmask '255.255.255.255'
Look for section similar to below:
config zone option name 'lan' option input 'ACCEPT' option output 'ACCEPT' option forward 'ACCEPT' list network 'lan'
Then add the following line to it:
list network 'macvlan'
/etc/init.d/network restart /etc/init.d/firewall restart
cd ~ vi docker-compose.yml
Copy and paste the following and save. The following was retrieved from PiHole docs and slightly modified to fulfill our purpose. In the
netowrk section at the bottom, the
parent is set to the new
macvlan interface created in the previous step from the
option device line (the one with suffix
.20). Also, the PiHole container will have a static IP which I've set to 192.168.1.3.
version: "3.3" # More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/ services: pihole: container_name: pihole image: pihole/pihole:latest hostname: pihole.lan environment: # TZ: 'set timezone' # WEBPASSWORD: 'set a secure password here or it will be random' # Volumes store your data between container upgrades volumes: - './pihole/etc-pihole/:/etc/pihole/' - './pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/' - './pihole/var-log/:/var/log' - './pihole/etc-cont-init.d/10-fixroutes.sh:/etc/cont-init.d/10-fixroutes.sh' # Recommended but not required (DHCP needs NET_ADMIN) # https://github.com/pi-hole/docker-pi-hole#note-on-capabilities cap_add: - NET_ADMIN restart: unless-stopped networks: internal: lan: ipv4_address: 192.168.1.3 networks: internal: lan: name: lan driver: macvlan driver_opts: parent: br-lan.20 ipam: config: - subnet: 192.168.1.0/24
Create the folders for the volumes:
mkdir -p ./pihole/etc-pihole/ mkdir -p ./pihole/etc-dnsmasq.d/ mkdir -p ./pihole/var-log/ mkdir -p ./pihole/etc-cont-init.d/
echo '#!/usr/bin/with-contenv bash set -e echo "fixing routes" ip route del default ip route add default via 172.18.0.1 echo "done fixing routes"' >> ./pihole/etc-cont-init.d/10-fixroutes.sh
cd ~ docker-compose up -d pihole docker logs -f pihole
Wait for PiHole to finish starting up and then hit
CTRL+C. Then run the following:
cd ~/pihole/etc-pihole sed -i -e 's/REV_SERVER.*//; s/REV_SERVER_CIDR.*//; s/REV_SERVER_TARGET.*//; s/REV_SERVER_DOMAIN.*//; s/PIHOLE_INTERFACE.*//' setupVars.conf echo 'REV_SERVER=true REV_SERVER_CIDR=192.168.1.0/24 REV_SERVER_TARGET=127.0.0.11 REV_SERVER_DOMAIN=lan PIHOLE_INTERFACE=eth0' >> setupVars.conf
Restart PiHole container
docker restart pihole
You could do some testing and see if it works. From another machine connected to the LAN network or WiFi:
ping 192.168.1.3 nslookup openwrt.org 192.168.1.3 nslookup $(hostname).lan 192.168.1.3
Open PiHole admin: http://192.168.1.3/admin
If all of the above works then PiHole container is ready to be the DNS server for your devices on the LAN network.
Look for the following section:
config dhcp 'lan' option interface 'lan' option start '100' option limit '150'
Then add the following line to it:
list dhcp_option '6,192.168.1.3'
Disconnect and reconnect your devices (or wait for the DHCP leases to expire) and enjoy ad blocking!
This would mean that something is wrong with
macvlan interface or the
docker-compose.yml network related section. Check again these two steps from before.
Check the interfaces in the PiHole container:
docker exec -it pihole ip a
Look for an interface with the IP Address that starts with 172. Is it having the same first three numbers 172.18.0 (the subnet) same as in the
10-fixroutes.sh script? If not then modify
10-fixroutes.sh and fix the subnet to be matching (keeping the last number .1 as is) and then restart the container.
There could be multiple reasons for this, but the basic idea from this test is to ensure that PiHole is forwarding any lookup with
.lan suffix to OpenWrt DNS. OpenWrt creates DNS entries for the devices connecting to the LAN network on the fly with
.lan suffix (as in belonging to the
lan domain). Check again
setupVars.conf, make sure of
REV_SERVER_TARGET=127.0.0.11 in there (notice the extra 1 in the end, that is because 127.0.0.11 is the embedded Docker DNS which eventually forwards to OpenWrt local DNS).