Before everything, please note:
- Pi-Hole has dropped support for Ubuntu 18.04. If your Firewalla is using Ubuntu 18.04, follow our guide to reflash your box. Gold New Image & Purple New Image
- This is a tech doc only for advanced user.
- This is for Firewalla in Router mode.
- Incorrect settings of port forwarding will result in ports being opened on your WAN interface
- Pi-hole won't work with the following features of Firewalla on the same device. Firewalla's features always have a higher priority. These features are: Family Protect, Adblock, and DNS over HTTPS.
- You should not enable conditional forwarding in most cases or it might create a DNS loop.
1. Create Configuration Files
You have to choose
- a network as your docker network, we use 172.16.0.0/24 in this tutorial
- a static IP for your pi-hole instance, we use 172.16.0.2 in this tutorial
- a password for your pi-hole management console, we use firewalla in this tutorial
Use the values above unless you know exactly what you are doing and have a reason to change them.
Create the following folder/files
/home/pi/.firewalla/run/docker/pi-hole/docker-compose.yaml
version: "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:v5.1.2
environment:
# set a secure password here or the default will be firewalla
WEBPASSWORD: 'firewalla'
# Volumes store your data between container upgrades
volumes:
- '/data/pi-hole/etc-pihole/:/etc/pihole/'
- './etc-dnsmasq.d/:/etc/dnsmasq.d/'
- '/etc/localtime:/etc/localtime:ro'
restart: unless-stopped
cap_add:
- NET_ADMIN
networks:
default:
# static IP address for pi-hole
ipv4_address: 172.16.0.2
networks:
default:
driver: bridge
ipam:
config:
# your chosen docker network here
- subnet: 172.16.0.0/24
2. Start and Test Pi-hole
run the following commands to install and start pi-hole
cd /home/pi/.firewalla/run/docker/pi-hole sudo systemctl start docker sudo docker-compose pull sudo docker-compose up --no-start sudo ip route add 172.16.0.0/24 dev br-$(sudo docker network inspect pi-hole_default |jq -r '.[0].Id[0:12]') table lan_routable sudo ip route add 172.16.0.0/24 dev br-$(sudo docker network inspect pi-hole_default |jq -r '.[0].Id[0:12]') table wan_routable
sudo ip -4 rule add from all iif br-$(sudo docker network inspect pi-hole_default |jq -r '.[0].Id[0:12]') lookup lan_routable priority 5003 sudo docker-compose up --detach
If you are using Gold SE, run one more command to add SNAT for the docker network.
sudo iptables -t nat -A POSTROUTING -s 172.16.1.0/16 -o eth0 -j MASQUERADE
If everything is good, pi-hole will be booted and you can now access its management portal by visiting http://172.16.0.2 in your browser.
If you use docker_compose.yaml above, your docker web password is "firewalla"
3. Set Pi-hole as DNS for your network.
Now proceed to the network settings on Firewalla App, assign 172.16.0.2 as the primary DNS server for the networks that you want to enable Pi-Hole.
- Tap on Network Button
- Tap on the Top right edit button
- Tap on the LAN segment you want to change DNS to pi-hole
- Scroll down and change the primary DNS to 172.16.0.2
- Save and you should be able to see DNS requests coming up in the management console.
4. Persisting The Configuration
You must be on firewalla 1.971 or later for this
create folder /home/pi/.firewalla/config/post_main.d and the following file
/home/pi/.firewalla/config/post_main.d/start_pi_hole.sh
sudo systemctl start docker sudo ipset create -! docker_lan_routable_net_set hash:net sudo ipset add -! docker_lan_routable_net_set 172.16.0.0/24 sudo ipset create -! docker_wan_routable_net_set hash:net sudo ipset add -! docker_wan_routable_net_set 172.16.0.0/24 sudo systemctl start docker-compose@pi-hole
And you are ready to go.
BONUS: Use DoH on Pi-hole
Change your docker-compose file as following
version: "3" # More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/ services: cloudflared: container_name: cloudflared # Restart on crashes and on reboots restart: unless-stopped image: cloudflare/cloudflared:2020.12.0 command: proxy-dns environment: - "TUNNEL_DNS_UPSTREAM=https://1.1.1.1/dns-query,https://1.0.0.1/dns-query,https://9.9.9.9/dns-query,https://149.112.112.9/dns-query" # Listen on an unprivileged port - "TUNNEL_DNS_PORT=5053" # Listen on all interfaces - "TUNNEL_DNS_ADDRESS=0.0.0.0" # Attach cloudflared only to the private network networks: default: ipv4_address: 172.16.0.3 pihole: container_name: pihole image: pihole/pihole:v5.1.2 environment: # set a secure password here or the default will be firewalla WEBPASSWORD: 'firewalla' DNS1: '172.16.0.3#5053' DNS2: 'no' # Volumes store your data between container upgrades volumes: - '/data/pi-hole/etc-pihole/:/etc/pihole/' - './etc-dnsmasq.d/:/etc/dnsmasq.d/' - '/etc/localtime:/etc/localtime:ro' restart: unless-stopped networks: default: # static IP address for pi-hole ipv4_address: 172.16.0.2 networks: default: driver: bridge ipam: config: # your chosen docker network here - subnet: 172.16.0.0/24
Restart your docker service and it's done
sudo systemctl restart docker-compose@pi-hole
Notes:
1. If the DNS Booster is enabled. The DNS requests from clients will be first redirected to the local DNS cache on Firewalla, which further uses pi-hole in docker as the upstream DNS server. So you will see all DNS requests from Firewalla's IP of docker network, which is 172.16.0.1. We strongly recommend keeping DNS Booster enabled.
2. In case docker service doesn't start, please follow this guide to reset your docker service. https://help.firewalla.com/hc/en-us/articles/360060535553
3. For those who have a local search domain, you might also want to check: Difference between Search Domain and Local Domain
All product names, logos, and brands are the property of their respective owners. All company, product, and service names used in this website are for identification purposes only. The use of these names, logos, and brands does not imply endorsement.
Known Issue
Note: This was fixed in our 1.976 release so this step is no longer necessary.
On ubuntu 22.04 and later, when docker starts up, it may load a kernel module br_netfilter
which conflicts with ubuntu 22.04 if you are using Smart Queue. Dockers managed by Firewalla will automatically handle this, but if you create docker instance, you may need to run:
sudo rmmod br_netfilter
after starting docker service or the firewalla routing function may break.
References
https://github.com/pi-hole/docker-pi-hole/
https://docs.docker.com/compose/
https://mroach.com/2020/08/pi-hole-and-cloudflared-with-docker/
Comments
118 comments
So far this looks great. We're pretty lazy and since this isn't persistent across reboots we created a script to perform all the steps above.
Wont give all the details - if you need more than what is presented here then you might not be ready to play with this.
We created a script named start-pihole with this content:
@chris hewitt nice script, it almost worked for me. It doesn't appear that the YAML file that is created from your cat command turns out as valid YAML though, so when starting the docker-compose command came with with errors.
I used http://www.yamllint.com/ to validate the YAML and paste that in to the script instead and that seemed to fix the problem.
What exactly doesn't persist between reboots? the entire docker? or that the docker doesn't start automatically? or...
Hmm, seems that the startup script does not persist if I put it in /etc/init.d/ like most do.
Let me reboot and check it again. I created a "tools" folder where we keep our goodies and notes. We also save things on /sata-drive, our 500GB SSD drive. But that's another post :-)
You can't save anything on any of the tmpfs mounts. You might think you are putting it in /etc/init.d/ but what is actually happening is that it's getting overwritten by /media/root-ro/etc/init.d/ on reboot.
Of course, I could also be 100% wrong.
What error are you getting? When I post the code it's clean?
@Chris Hewitt thanks, good tip. I didn't realize that was what was happening. How do you make your startup script run in this situation then? /media/root-ro/etc/init.d/ is not write-able for good reason, I would assume.
I found that the docker container was intact after a reboot, but docker was just not started and neither was the pi-hole docker container. So, as such, do you think your start up script really needs to redo the whole thing? why couldn't you just run the last few commands to start the docker container up?
The folder /media/root-ro/etc/init.d/ is not writable and for good reason. It keeps people like me from breaking my toys permanently. It also helps support people, like our friends at Firewalla, have an enjoyable life. All they have to do is tell people with issues to reboot and the machine is back to a known-good state.
Running my script
For me, I just run ...
... after rebooting.
I haven't had enough time to really look into this to figure out everything it's doing.
I'm not sure....huh interesting. When I used your whole script, it failed. When I paste in from YAML lint, it works. I have no idea *shrug*
OK, so you have not found a way to make the script auto execute.
Did you find that having DNS booster enabled and applying to devices on the Firewalla caused problems with pi-hole? For example, I was having issues with devices that were covered by the family filter and DNS booster function not showing up as hitting the pi-hole for DNS requests. Once I removed them from the DNS booster, then they started showing up.
This appears to make sense because DNS booster functionality is supposed to intercept DNS traffic and redirect it to the FWG. But, for some reason, it's going to the FWG internal DNS server, and not to the configured DNS server I had set in the LAN configuration.
I haven’t tried to auto execute. But you should be able to do that with an “@reboot” crontab entry.
I don’t use the DNS Booster. This links seems to say DNS Booster will work with Pi Hole - https://help.firewalla.com/hc/en-us/articles/360034635473?fbclid=IwAR15r7_G4XsSKEWcU-IipIsMyNNDUikubBP9EGWzlrCXfenmuYNcvih9sos
Actually, I think that the article you linked seems to imply that family guard (and by extension, anything to do with filtering by DNS, including DNS booster) will not work with pi-hole. This makes sense--it all depends which DNS server is the "upstream" server in your network.
Quoting:
Warning: The conflict of DNS blocking between Pi-Hole and Firewalla
If you install Pi-Hole on Firewalla, Pihole will become the upstream DNS server of Firewalla. All DNS traffic will route through Firewalla first then to Pi-Hole, so that you will only be able to see localhost and Firewalla on the Pi-Hole portal.
Devices -> Firewalla -> Pi-Hole -> further upstream DNS servers
To get individual stats on devices, you will have to install Pi-Hole on a separate device and use it as DNS server in your router DHCP setting. But in this way, you will lose all the per-device DNS features (Family Protect, Ad-Block, Safe search, etc.) on Firewalla, because Firewalla will only see DNS traffic from Pi-Hole.
Devices -> Pi-Hole -> Firewalla -> further upstream DNS servers
--and--
Step 3. Turn off Family Protect on Firewalla App. Family Protect Feature and Pi-Hole can't be activated at the same time.
DNS booster actually intercepts DNS traffic and redirects them to the local DNS server on the box. All kinds of DNS-based features, e.g., safe search, family protect, AD block, DNS over HTTPs, and domain-based blocking are implemented on the local DNS server. Some of them simply return static domain IP mapping, others will further query the configured upstream DNS server, e.g., OpenDNS, Cloudflare DoH server, etc.
So if the pi-hole in docker is set as the upstream DNS server, it will see all requests coming from Firewalla. If you run a pi-hole in another device, it will see requests coming from different devices in the same network segment, but still from Firewalla if original requests are from devices in a different segment.
In conclusion, if the DNS booster is enabled, all DNS traffic going through the box will be redirected to the local DNS server. The local DNS server may further query the upstream DNS server if necessary.
@Support thank you, perfect explanation and what I was needing to know concerning the "order" of DNS servers when DNS booster is enabled.
I think my additional complication to this is that IF that upstream DNS server is on the LAN, DNS booster should NOT be enabled on the DNS server in the LAN. (I have a DNS server running on my windows server box to serve up my local domain DNS)
My setup:
192.168.1.118 = Windows server DNS to serve up DNS for domain, set to forward DNS requests to 172.0.0.2
192.168.1.1 = FWG
172.0.0.2 = Pi-hole docker running on FWG
192.168.1.xxx = Client covered by DNS booster
DHCP settings are set such that DNS server 1 is 192.168.1.118 (my windows server)
If I disable DNS booster on 192.168.1.118 (windows DNS server), this setup works. FWG is "downstream" from my windows DNS server, so any (uncached) domain name lookup is passed from the FWG to my windows DNS server, which then passes to pi-hole and I see the resulting activity.
Effective DNS request chain: client->FWG via DNS booster intercept->192.168.1.118->172.0.0.2->public DNS (this is acceptable for me)
If i enable DNS booster on 192.168.1.118, then I no longer see ANY activity in pi-hole.
Effective DNS request chain: client->FWG via DNS Booster intercept->loops back to FWG via DNS booster intercept?????....but somehow the domain names resolve, despite no logged activity on the pi-hole.
Tried a different way:
Set DHCP settings so that DNS server 1 is set to the pi-hole directly, 172.0.0.2.
In this situation, ANY device that has DNS booster enabled on it will not have any activity show up on pi-hole.
Effective DNS request chain: Client -> FWG via DNS booster intercept -> loops back to FWG via DNS booster intercept????? No activity logged in pi-hole....but somehow, still resolving the domain name.
But if you disable DNS booster on a client with DNS server set to the pi-hole, then it starts working and pi-hole shows activity from that client.
Effective DNS request chain: client->172.0.0.2->public DNS
Of course, disabling DNS booster on a client removes many of the DNS based protection, as mentioned previously so this is not desired for me.
I don't know how to explain this behavior. I theorize that maybe DNS booster is applied to 172.0.0.2 automatically, but there's no way in the UI to disable it for an IP not in the LAN.
@Hans
Setup 1:
In theory, the DNS loop will occur and the DNS query will not work. However, Firewalla has a mechanism to automatically disable DNS booster on devices that are set as DNS resolver on the box. The periodical check is done once every minute and very likely the DNS booster was automatically disabled on 192.168.1.118 soon after you enabled it.
Setup 2:
If you enable DNS booster on a device, the DNS request chain is: client -> FWG -> 172.0.0.2 -> public DNS. In theory, you should see activities from FWG on pi-hole.
If you disable DNS booster on a device, the DNS request chain is: client -> 172.0.0.2 -> public DNS.
DNS booster is only applied to devices that are monitored by Firewalla. It is not applied to docker container.
@Support
When your say "devices that are set as DNS resolver on the box" you mean any ip that is set as a dns server in the dhcp config? As there is no other way I know of to set dns servers...
I would like to get setup 2 to work (client->fwg via dns booster->pi-hole), but as I have tried, turning on dns booster on devices makes it such that no dns requests hit the pi-hole. Shall I open a support ticket and have you all take a look?
@Hans
"devices that are set as DNS resolver on the box" means any IP that belongs to the local network.
Regarding setup 2, is there any feature on Gold enabled that may change the upstream DNS server, e.g., family protect or DNS over HTTPs? If there is, Gold will send DNS request to other DNS servers, not 172.0.0.2.
It’s awkward on mobile devices to interact with a Pi-Hole through a browser.
Try this iPhone app:
https://apps.apple.com/us/app/pi-hole-remote/id1515445551
Very well-designed UI.
@Support Yes, I do have DNS over HTTP turned on as well as family protect for some devices, and Ad block for all devices.
I would like to layer these features together, and basically use pi-hole as the final upstream DNS before going to public DNS. My goal is to have the robust and thorough ad-blocking capability of pi-hole for my whole network, but still use FWG's additional protection features (family protect, DoH, domain blocking rules) for specific groups of devices. Is there a way to do this?
I followed the instructions exactly on my FWG box. However, I don't see any queries from devices on the network. I tested disabling the DNS Booster on 1 of the laptop device. I then started seeing the queries from that device. By disabling the DNS Booster on the device, looks like we lose the Family Protect, Ad Block, Safe Search, DNS over HTTPS, right?
@Binh Tom yes, that's been my experience, and what @Firewalla has said.
Thanks Hans. I like your request to combine the pi-hole into FWG so that we don't lose other features due to disabling the DNS Booster.
Agreed with Hans, I'd like to use pi-hole as the last leg in the chain while keeping the firewalla features. Right now I have most of the features turned off to get pi-hole to work. I can't live without pi-hole now because the internet is an ad machine.
By the way, thanks for the support. I love the active threads and dev work from the firewalla team!!
Have any of you wonderful chaps tried installing DNS over HTTPS on the Pi-hole using
https://docs.pi-hole.net/guides/dns-over-https/
Anyone who installs Pi-hole onto their Firewalla has to turn off the built in service. Just wondering if this would conflict with anything already installed.
Thanks
@Andy brown I haven't tried this yet, but just for simplicity of management I have opted not to use pi-hole with FWG until we figure out if there's a way to layer it with DNS Booster functionality (and the associated protection associated with the booster) with pi-hole. I really think this means we need functionality in FWG to explicitly and manually define the upstream DNS server that is used.
@Firewalla @Support can you comment here? Haven't heard from you all in a while on this topic. Thank you! The new early access release is very good!
I slightly modified the script to run cloudflared docker along with pihole. Also switched off the DoH on the app. (DNSbooster still ON).
The chain goes like this
device => FWG => DNSbooster or Pihole(depends on cached or not) => DoH Upstream
on my try outs.. 18+ block and safesearch worked as intended in this setup.
Need to evaluate in the long run. Also need to check if the cloudflared will get autostarted.
Script is as follows (5054 is the cloudflared port)
```
I am trying to install using this document. I get this error. Any idea?
ERROR: for pihole Cannot start service pihole: OCI runtime create failed: container_linux.go:346: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"/home/pi/.firewalla/run/docker/pi-hole/etc/localtime\\\" to rootfs \\\"/var/lib/docker/overlay2/a47de3d7fa1caf8265cb36a6d8f019ae9664499a1cf323d8f51381936ffc62af/merged\\\" at \\\"/var/lib/docker/overlay2/a47de3d7fa1caf8265cb36a6d8f019ae9664499a1cf323d8f51381936ffc62af/merged/usr/share/zoneinfo/UCT\\\" caused \\\"not a directory\\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
ERROR: Encountered errors while bringing up the project.
If anyone is interested in an ansible implementations of this post, more coming soon.
https://github.com/hhcalder92/ansible-firewalla-role/
@hector, super! We love ansible
Sundar, I got that same error. The problem for me was the last line here:
I am having odd results. I've followed the directions and I end up with my clients having their DNS queries resolved, but nothing gets logged (or blocked) by pi-hole.
Here is dig output from one of my clients
$ dig @172.16.0.2 a-ads.com
; <<>> DiG 9.9.5-9+deb8u19-Raspbian <<>> @172.16.0.2 a-ads.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38369
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;a-ads.com. IN A
;; ANSWER SECTION:
a-ads.com. 300 IN A 104.26.14.247
a-ads.com. 300 IN A 172.67.69.167
a-ads.com. 300 IN A 104.26.15.247
;; Query time: 24 msec
;; SERVER: 172.16.0.2#53(172.16.0.2)
;; WHEN: Wed Sep 30 13:04:46 EDT 2020
;; MSG SIZE rcvd: 86
And here is the dig output from the firewalla box itself
(Firewalla) $ dig @172.16.0.2 a-ads.com
; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> @172.16.0.2 a-ads.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40266
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;a-ads.com. IN A
;; ANSWER SECTION:
a-ads.com. 2 IN A 0.0.0.0
;; Query time: 1 msec
;; SERVER: 172.16.0.2#53(172.16.0.2)
;; WHEN: Wed Sep 30 13:04:32 EDT 2020
;; MSG SIZE rcvd: 43
The pi-hole UI reflects these results too, sort of. The query from the FWG box shows as "172.16.0.1" and there is no record at all from the client machine.
The really odd thing is that I followed these instructions for 1.970 (back when the ip address was 172.0.0.2 and there were not the post_main.d instructions) and everything worked then. I saw all of my clients activity in pi-hole and things were being blocked (I even had to whitelist somethings for my kid's school.)
Anyone have any ideas?
@Nathan Jones
Just to level set: Do you have Family Protect, DNS booster, Ad block, and/or DNS over HTTPS turned on in firewalla?
Please sign in to leave a comment.