Running PiHole on OpenWrt (x86/RPi) using Docker - Tutorial/Experiences

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 RPi (thanks to @Deuxst) 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).

Note: The PiHole Image version being used in this tutorial is 2021.09. Recent images seem to be having an issue with permissions as shown here and here.

Warning: The tutorial has been worked on IPv4 LAN setups, and has not been made to support IPv6. For it to work, the IPv6 DHCP settings need to be disabled which are shown as part of the tutorial. (If anyone would like to figure out how to make it work with IPv6, I'd be glad to update the tutorial, though we might need to consider having both options IMO)

Disable IPv6 DHCP on OpenWrt

uci -q delete dhcp.lan.dhcpv6
uci -q delete dhcp.lan.ra
uci -q delete network.lan.ipv6
uci commit
/etc/init.d/odhcpd stop
/etc/init.d/odhcpd disable
/etc/init.d/network restart

The LAN should look something like the below where IPv6 is not showing anymore:

image

Install Docker and Docker-Compose on OpenWrt

opkg update && opkg install docker luci-app-dockerman docker-compose dockerd kmod-macvlan
reboot

Setup MACVLAN interface in OpenWrt

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.

vi /etc/config/network

Look for the config interface 'lan' section and note down the device from the option device line. In my case it is br-lan.

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 .20 suffix.

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'

Modify the firewall adding the new interface to the lan zone

vi /etc/config/firewall

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'

Restart the network and firewall services

/etc/init.d/network restart 
/etc/init.d/firewall restart

Setup docker-compose.yml and PiHole

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:2021.09
    hostname: pihole
    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/var-log/lighttpd
chown 33:33 ./pihole/var-log/lighttpd
mkdir -p ./pihole/etc-cont-init.d/

Create 10-fixroutes.sh.

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
chmod 755 ./pihole/etc-cont-init.d/10-fixroutes.sh

Start PiHole and finalize its setup

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

Test

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 pihole.lan 192.168.1.3
nslookup openwrt.org 192.168.1.3
# For *nix
nslookup $(hostname).lan 192.168.1.3
# For Windows
nslookup %COMPUTERNAME%.lan 192.168.1.3

Open PiHole admin: http://pihole.lan/admin

If all of the above works then PiHole container is ready to be the DNS server for your devices on the LAN network.

Configure DNS settings in OpenWrt and Profit!

vi /etc/config/dhcp

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'

Restart dnsmasq service (the service that manages the DHCP on openwrt):

/etc/init.d/dnsmasq restart

Disconnect and reconnect your devices (or wait for the DHCP leases to expire) and enjoy ad blocking!

Troubleshooting

Pinging PiHole IP is not working or opening the PiHole admin is not working

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.

nslookup openwrt.org 192.168.1.3 is not working

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.

nslookup $(hostname).lan 192.168.1.3 or nslookup %COMPUTERNAME%.lan 192.168.1.3 is not working

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

Change Notes:

  • April 7th 2022: added dockerd kmod-macvlan to Install Docker and Docker-Compose on OpenWrt. Thanks @grrr2.
  • April 10th 2022: minor fixes to the folders creations, the 10-fixroutes.sh and changed the PiHole image version to 2021.09 in Setup docker-compose.yml and PiHole based on this feedback. Thanks @Deuxst.
  • April 10th 2022: Added code coloring for bash/shell snips.
  • April 13th 2022: Added new section Disable IPv6 DHCP on OpenWrt along with warning above it.
  • April 13th 2022: Updated section Test and added command for Windows machines.
  • April 13th 2022: Mentioned RPi support.
  • April 13th 2022: Added note about PiHole version and issues with latest versions.
  • April 22nd 2022: Fixed mistake in Configure DNS settings in OpenWrt and Profit! for the command that restarts the dhcp/dnsmasq service in OpenWrt
  • July 25th 2022: Added reboot after installing Docker in Install Docker and Docker-Compose on OpenWrt
  • September 28th 2022: Fixed value of hostname in Setup docker-compose.yml and PiHole. Apparently if hostname: pihole.lan, lookup for pihole or pihole.lan will actually be blocked, but hostname: pihole will give successful response for pihole or pihole.lan lookup. This took me a while to figure out...
  • September 28th 2022: Updated Tests section to used pihole.lan instead of IP address in URL and pihole.lan lookup.
6 Likes

Thanks for this great tutorial ! :+1:

1 Like

Thank you, and thanks to the devs and community for getting us there!

1 Like

hi,

thanks for the guide! could you please elaborate why you decided to use pihole over "native" adblock (i.e. no docker wrap is required)? what are the benefits you see with pihole please? can you setup pihole to provide service to multiple subnets (e.g. lan less restrictive, guest restrictive, IoT most restrictive)? can you integrate pihole UI with LuCI?

thanks in advance.

1 Like

Hi, and thank you for your message

Do you mean running pihole without using docker? If so then one reason for running it with docker is that currently OpenWrt by default runs dnsmasq and dhcp service which reserve ports 53 and 67 on all of its interfaces. Running it without using docker would require to disable/modify one or both services, I find that unnecessary and complicated compared to docker setup I've done because docker can give me network isolation between container and host hence avoiding any conflicts. It not impossible to run pihole without using docker, just has extra work.

Benefits of PiHole compared to what? Generally speaking its a great AdBlock DNS service, I didn't do too much comparison between it and other AdBlock DNS services available and just went with it and so far did not find any shortcomings in using it.

Its definitely possible, in theory I would setup multiple macvlan interfaces in OpenWrt and have PiHole container attached to them. There might be some extra configuration needed to be done on PiHole which I recall reading about in its release notes and I have a feeling that it would work.

What's the end goal here? Honestly I consider setting up something like heimdall on an Ubuntu Docker host and adding links to PiHole admin and OpenWrt luci. If its for statistics I currently rely on HomeAssistant which has an integration with PiHole but any other solution could work.

1 Like

sorry maybe was not clear enough:

dnsmasq + adblock are providing similar services (i.e. DHCP, DNS filtering), am wondering what are the benefits using docker + pihole? i understand that docket is a workaround here for the reason you mentioned.

am not familiar with pihole to be honest hence wondering is it worth to replace my current setup (dnsmasq + adblock). looks it is just a matter of choice, right?

1 Like

give it a try...
There is also AdGuard Home, as alternative to AdBlock !

Not at all. With dnsmasq + adblock setup, as far as I understood its done by editing the dnsmasq.conf file and downloading one of the adblock txt lists for dnsmasq to use for blocking. PiHole has that and adds to it periodic adblock list updates, query logs, statistics, per client configuration, and a nice UI to manage all of that and more. Definitely worth a try.

@ahasbini . @erdoukki - thanks, yes probably i will give a try. the per client setup sounds interesting.

edit: i have checked pihole. couple of comments:

  1. i found the guide above missing installation of dockerd, kmod-macvlan, without it i could not start docker.
  2. according to https://docs.pi-hole.net/main/origins/ it is using dnsmasq too under the hood :slight_smile:
  3. indeed looks very fancy with a nice web gui, i can understand why to use it.
2 Likes

Congrats!

You're right I totally missed those two packages. I'll mark your post as the solution as it seems the time window for editing the original post has expired.

I think it's always good to be able to learn and compare new and different ways to achieve desired goals with existing known solutions. While I don't use either PiHole, nor AdBlock as I do prefer AdGuard Home, I understand different people may prefer different things. After all, this is not Ford in the early days, when you could have any car color, as long as it was black...

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.