My Setup for Pi-hole at home and in the cloud to be used with WireGuard for the whole family.

View on GitHub

This project is suitable for: Linux + macOS and has been made-with-bash + Vim +❤️

How to and why combine Pi-hole and WireGuard

This project documents my Setup for Pi-hole

for me and the whole family and gives some food for thought.

You would rightly be disappointed if I wouldn’t show you my hacks and tweaks with an explanation of why I did this and which goals I wanted to achieve and whether I did a good or a bad job.

Now have a look at my Pi-hole(s):




Table of contents

  1. Prerequisites
  2. Why Pi-hole?
  3. Why WireGuard?
  4. Setup and Installation
  5. Some words regarding choosing a DNS upstream resolver
  6. Blocklists and consolidation / deduplication
  7. General Infos regarding your Pi-hole and network setup
  8. Some tools for Pi-hole
  9. Tweaks
  10. Usage at home
  11. Usage in foreign networks (“free” WiFi / Hotspots and mobile data (4G/5G))
  12. Maintenance




You should have at least some basic knowledge about Linux and Docker. Which linux distro you are using is not relevant. Use a linux distro of your choice! I’m using Ubuntu and openSUSE, which are basically totally different regarding package management: Ubuntu is Debian-based, openSUSE is RPM-based.


Why Pi-hole?


🥅 The MAIN GOAL for me is to block ads, tracker, malware, … (everything that harms PRIVACY or DATA INTEGRITY or is just ANNOYING us)
🥅 And the SECONDARY GOAL is to block stuff, that is USED WAY TOO MUCH BY THE KIDS… or what is NOT SUITABLE for this age group.

💡 Conclusion: Pi-hole can save you from “too curious” corporates (Facebook, Google, Amazon, Apple, Microsoft - just to name some) and can save young people from adult content. 💡


Why WireGuard?

WireGuard tunnels all traffic from my mobile device(s) when leaving my home to use my Pi-hole that isn’t exposed on the internet because I don’t want to run a public DNS resolver by forwarding ports from WAN interface to my computer where Pi-hole is running.

💡 Conclusion: WireGuard can save you from “too curious” ISPs at home, mobile providers or (free) VPN providers - but now you still have to trust your cloudserver provider! This is still not 100 percent safe from state authorities or from intelligence services! 💡
This german Howto about “Avoiding Internet-censorship and stay anonym” gives some interesting details and thoughts.

Finally the combination of Pi-hole and WireGuard (also known as WireHole - but I like both projects being separated for reasons of nicer and easier updates which I will explain later) gives you the ability to access your private Pi-hole on all your devices at any place/network any time 👍

ℹ️ More Information (in german only) can be found here.


Setup and Installation

My motivation to run everything for this project in Docker containers has been the following:

💡 I can really recommend Docker, because it’s so super easy! 💡

So I used https://github.com/pi-hole/docker-pi-hole and followed the “Quick Start” to install and start Pi-hole on my machines (at home and on my cloudserver).

To get the advantages and the same “surf and shelter experience” when not being at home/in my home WiFi I thought about a VPN to my Pi-hole. Because I already had an Ubuntu LTS server running at Hetzner with an 1 Gbit/s connection instead of 50 Mbit/s Upload at home, I installed https://github.com/linuxserver/docker-wireguard and followed the “Usage” to install and start my personal WireGuard VPN server 😄 There’s a 20 TByte volume for outgoing traffic free of charge, which really should be enough for many WireGuard users and covering all current existing mobile plans (usually some GByte).

BTW: I use docker-compose and not native docker because I use it already for other projects (Nextcloud).

⚠️ I will not explain and repeat how to install a basic setup - please refer to the links above. ⚠️
⚠️ Don’t forget to change DNS resolver in your routers DHCP options - please refer to your router’s documentation how to do this! ⚠️

Keep in mind to set Permit all origins in Web-GUI (“Settings” > “DNS”) for your Pi-hole at home so that all clients can use it!

Keep in mind to set Allow only local requests for your Pi-hole on your cloudserver if you won’t become a public DNS resolver! 💣


Some words regarding choosing a DNS upstream resolver

Remember why we choose running a local DNS resolver:

Go to “Settings” > “DNS” in Pi-hole’s Web-GUI: and (IPv4)
2a10:50c0::ad1:ff and 2a10:50c0::ad2:ff (IPv6)

If you’re wondering why raw performance on dnsperf.com differ so much from my results and are “much better”:
“All DNS providers are tested every minute from 200+ locations around the world”

My project is measuring very close to an end user via WiFi and via Vodafone ISP (coax/cable). So these results are what you also can expect on your home internet connection regardless which ISP (Telekom, Vodafone, 1-und-1, …) and which technology (DSL, Coax/Cable, Fiber or even mobile (4G/5G)).

💡 You can check this out before installing Pi-hole with my little project dnspingtest_rrd. You may have want to have a look at real data from my home. For one-time-checks you could also use:

docker run --rm --name=dnstrace redsift/dnstrace --color -n 10 -c 10 --server --recurse web.de

image (“mean” is the relevant/interesting timing for you!)


Blocklists and consolidation / deduplication

There’s already at least one single blocklist shipped with Pi-hole: https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts. But that didn’t fit my needings (see “goals” above). So I constantly and repeatedly check and add/remove blocklists on an irregular base.

Currently I’m using these blocklist (Web-GUI: “Group management” > “Adlist” - you may want to assign a group to some blocklists to be able to block some domains only for some devices) in column “address” (this is an extract from real output from pihole_adlist_tool which I will introduce later). These list sum up to more than 4 mio domains/hosts. For better reading I rearranged the rows by groups:

id  enabled  total_domains  domains_covered  hits_covered  unique_domains_covered  address
--  -------  -------------  ---------------  ------------  ----------------------  --------------------------------------------------------------------------------------------------------
# default
1   1        189924         1253             125255        105                     https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts

# additional blocklists:
11  0        11395          262              46693                                 https://someonewhocares.org/hosts/zero/hosts
13  1        2196                                                                  https://raw.githubusercontent.com/StevenBlack/hosts/master/extensions/fakenews/hosts
19  1        23782          102              19612         1                       https://raw.githubusercontent.com/blocklistproject/Lists/master/crypto.txt
20  1        26562          1                1             1                       https://raw.githubusercontent.com/blocklistproject/Lists/master/drugs.txt
21  1        196085         6                64            4                       https://raw.githubusercontent.com/blocklistproject/Lists/master/fraud.txt
23  1        190229         5                70            5                       https://raw.githubusercontent.com/blocklistproject/Lists/master/phishing.txt
27  1        2499           3                23            1                       https://raw.githubusercontent.com/blocklistproject/Lists/master/gambling.txt
28  1        2134           6                70            6                       https://raw.githubusercontent.com/blocklistproject/Lists/master/piracy.txt
33  1        4185           3                90            3                       https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/Streaming
34  1        476667         11               3502          4                       https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/Phishing-Angriffe
35  1        283757                                                                https://zerodot1.gitlab.io/CoinBlockerLists/hosts
37  1        441936                                                                https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/Corona-Blocklist
43  1        91462          70               1209          5                       https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/malware
59  1        347            13               868                                   https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt
60  1        347            13               868                                   https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy_v6.txt
62  1        1679                                                                  https://raw.githubusercontent.com/lightswitch05/hosts/master/docs/lists/hate-and-junk-extended.txt
63  1        431080         1516             142449        451                     https://raw.githubusercontent.com/lightswitch05/hosts/master/docs/lists/ads-and-tracking-extended.txt
64  1        171731         86               15259         53                      https://raw.githubusercontent.com/lightswitch05/hosts/master/docs/lists/tracking-aggressive-extended.txt
67  1        539365         41               14947         13                      https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/spam.mails
74  1        2571           2                13                                    https://raw.githubusercontent.com/Sinfonietta/hostfiles/master/gambling-hosts
82  0        201416                                                                https://raw.githubusercontent.com/notracking/hosts-blocklists/master/hostnames.txt
84  1        916            47               4657          20                      https://raw.githubusercontent.com/liamengland1/mischosts/master/microsoft-telemetry
86  0        2325                                                                  https://hosts.tweedge.net/malicious.txt
87  1        3757           263              14157         6                       https://pgl.yoyo.org/as/serverlist.php?showintro=0;hostformat=hosts
89  1        291106                                                                https://big.oisd.nl/

# adult and NSFW:
42  1        414048         790              57435         211                     https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/child-protection
71  1        23                                                                    https://raw.githubusercontent.com/Sinfonietta/hostfiles/master/snuff-hosts
72  1        19670          36               429           8                       https://raw.githubusercontent.com/Sinfonietta/hostfiles/master/pornography-hosts
73  1        369                                                                   https://raw.githubusercontent.com/tiuxo/hosts/master/porn
77  1        30786          52               473           13                      https://raw.githubusercontent.com/StevenBlack/hosts/master/extensions/porn/clefspeare13/hosts
80  1        56711          23               240           6                       https://mypdns.org/my-privacy-dns/matrix/-/raw/master/source/porn_filters/explicit_content/hosts.list
81  1        5629           3                8             1                       https://mypdns.org/my-privacy-dns/matrix/-/raw/master/source/porn_filters/explicit_content/domains.list
88  1        341009                                                                https://nsfw.oisd.nl

# tracking on mobiles:
30  1        767            173              66383         12                      https://raw.githubusercontent.com/d43m0nhLInt3r/socialblocklists/master/MobileAppAds/appadsblocklist.txt
68  1        80             32               40481                                 https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/android-tracking.txt
83  1        234            66               223348        55                      https://raw.githubusercontent.com/liamengland1/mischosts/master/apple-telemetry

# smart TVs:
5   0        209                                                                   https://raw.githubusercontent.com/d43m0nhLInt3r/socialblocklists/master/SmartTV/smarttvblocklist.txt
32  1        20             5                264           4                       https://www.technoy.de/lists/FireTVAds.txt

# tracking in minecraft:
69  1        6                                                                     https://raw.githubusercontent.com/StevenBlack/hosts/master/data/minecraft-hosts/hosts

# tracking on tiktok:
85  1        184            6                13029         2                       https://raw.githubusercontent.com/liamengland1/mischosts/master/tiktok-hosts

Some infos about big.oisd.nl:

Contrary to it’s name, FULL does NOT include NSFW The NSFW list can be used as stand-alone, or alongside basic or full

What is the difference between the full and basic list? –> https://oisd.nl/faq#basic

The Basic list is a smaller, less comprehensive variant of the full list, which focussus mainly on Ads, (Mobile) App Ads

The Full list blocks: Ads, (Mobile) App Ads, Phishing, Malvertising, Malware, Spyware, Ransomware, CryptoJacking, Scam … Telemetry/Analytics/Tracking (Where not needed for proper functionality)


General Infos regarding your Pi-hole and network setup

I’m using only static IP adresses in my home-network because this is essential for the “Client group management” (Web-GUI: “Group management” > “Clients”). It’s essential to turn off “private wifi address” on iOS and the pendant on android. Otherwise you won’t be able to identify your clients and you won’t be able to use static IP addresses! (IP addresses are easier to manage and to “remember” than MAC addresses. As Apple writes on their support site “private Wi-Fi addresses (can) … improve privacy …”. For “network administrator” Apple continues to write “use an MDM-defined network profile to turn off Private Address for enrolled devices that join their Wi-Fi network”.

After you have once identified your “known clients” by IP address or MAC addres you are now able to assign groups of blocklists to your clients. Assume you have an Adlist group “social” and don’t want your kids to consume social media, then you might assign group “social” additional to “default” to your kids device(s).

⚠️ Please refer to your router’s documentation how to setup “static DHCP” addresses! ⚠️

If you are experiencing false positives for some domains,

I’m also blocking:


Some tools for Pi-hole


PADD provides in-depth information about your Pi-hole.

I can also be used as a systemd-service on tty11 in addition to pihole-live-output.service on tty10 that can easily be implemented:

My cloudserver:

My desktop computer at home:


📝 Just add these lines in your /etc/systemd/system/pihole-padd.service and do a systemctl daemon-reload and a systemctl start pihole-padd.service:

# PADD - A more advanced version of the chronometer provided with Pihole.

Description=PADD - A more advanced version of the chronometer provided with Pihole.
After=docker.service network-online.target dhcpd.service pihole.service

ExecStart=/usr/bin/sh -c "/usr/bin/docker exec --tty pihole /etc/pihole/padd.sh > /dev/tty11 < /dev/tty11"
ExecStop=/usr/bin/sh -c "/usr/bin/clear > /dev/tty11 < /dev/tty11"


📝 Do the same procedure for /etc/systemd/system/pihole-live-output.service:

# Pi-hole: View the live output of the Pi-hole log

Description=View the live output of the Pi-hole log.
After=docker.service network-online.target dhcpd.service pihole.service

ExecStart=/usr/bin/sh -c "/usr/bin/docker exec -it pihole pihole -t > /dev/tty10 < /dev/tty10"
ExecStop=/usr/bin/sh -c "/usr/bin/clear > /dev/tty10 < /dev/tty10"


Now you can switch to your tty10 and tty11 console to view Pi-hole’s query log or to displays stats about your piHole 👍

🚧 Here I documented how to run padd.sh with your docker container. 🚧


A tool to analyse how your pihole adlists cover you browsing behavior.

⚠️ This has to be run from outside your Docker container in the directory where your Pi-hole database files reside! ⚠️


Monitoring of average response times of DNS resolvers in RRD databases and simple HTML pages with PNG graphs.

Use this if you want to find out which DNS resolver will be the fastest and most reliable for you. I run it closest to a user experience via WiFi because most devices today are connected via WiFi and not via LAN. Think of smartphones and tablets! After some time (a day, a week; what you expect as “reliable”) there’s some data on a 5 minute base available and by interpreting the generated charts you should have more than just a clue which DNS resolvers from the ones you monitored are the fastest and most reliable for your internet connection at home 👍

⚠️ Please have a look at the README to check and how to set up this nice tool for your needings. ⚠️

You might be also interested in my DNS-Ping Monitoring with real data from my home or my cloudservers at Hetzner: Nuremberg, Germany, Falkenstein, Germany and Helsinki, Finnland.



Reduce top lists from useless information

If you find your “top” lists on the dashboard of the Web-GUI not suitable for the information you really need, you might exclude some top domains / top adverters and/or top clients in “Settings” > “API / Web Interface”. For example I exclude these domains because they are much to generic or are queried very, very often by my linux machine’s cronjobs and therefore useless to know:


And pi.hole itself does a lot of DNS queries as a client with types DS and DNSKEY which are technically absolutely neccessary for DNSSEC; but this information (how much queries) is absolutely worthless for me 😜

Keep database “small” / disable DoH and Apple’s iCloud Private Relay / reduce queries

I’ve added these lines in my etc-pihole/pihole-FTL.conf. Read the comments/links to understand:

# https://docs.pi-hole.net/ftldns/configfile/

# ---
# https://docs.pi-hole.net/ftldns/configfile/#mozilla_canary
# ---
# Should Pi-hole always replies with NXDOMAIN to A and AAAA queries
# of use-application-dns.net to disable Firefox automatic DNS-over-HTTP?
# This is following the recommendation on
# https://support.mozilla.org/en-US/kb/configuring-networks-disable-dns-over-https

# ---
# https://docs.pi-hole.net/ftldns/configfile/#icloud_private_relay
# ---
# Should Pi-hole always replies with NXDOMAIN to A and AAAA queries of
# mask.icloud.com and mask-h2.icloud.com to disable Apple's iCloud Private Relay
# to prevent Apple devices from bypassing Pi-hole?
# This is following the recommendation on
# https://developer.apple.com/support/prepare-your-network-for-icloud-private-relay

# https://discourse.pi-hole.net/t/how-to-stop-all-of-the-ptr-queries/22085/4
# due to https://github.com/thomasmerz/issue-tracker/issues/522

# https://docs.pi-hole.net/ftldns/configfile/#rate_limit
# Control FTL's query rate-limiting. Rate-limited queries are answered with a REFUSED reply and not further processed by FTL.
# …
# Rate-limiting may be disabled altogether by setting RATE_LIMIT=0/0
# this results in the same behavior as before FTL v5.7.

# https://docs.pi-hole.net/ftldns/configfile/#block_ttl
# FTL's internal TTL to be handed out for blocked queries.
# This settings allows users to select a value different from the dnsmasq config option local-ttl.
# This seems useful in context of locally used hostnames that are known to stay constant over long times
# Note that large values may render whitelisting ineffective due to client-side caching of blocked queries.

# https://docs.pi-hole.net/ftldns/configfile/#reply_addr4
# This option is deprecated and may be removed in future versions, please use BLOCK_IPV4 and LOCAL_IPV4 instead.
# LOCAL_IPV4= (unset by default, PR #1293)
# BLOCK_IPV4= (unset by default, PR #1293)

You may also raise min-cache-ttl in your etc-dnsmasq.d/05-pihole-custom-ttl.conf so that all your devices don’t need to query your Pi-hole quite often (every minute), but only every hour:

# https://00f.net/2019/11/03/stop-using-low-dns-ttls/
# https://discourse.pi-hole.net/t/increase-ttl/25157
# https://discourse.pi-hole.net/t/change-the-ttl/6903/14

Reduce also blocked queries

In conjunction with BLOCK_TTL=300 (blocked domains will be cached on client side for 5 minutes instead of 2 seconds!) this drasically reduces the amount of queries and of the blocked-domain-ratio!
In my case this reduced daily queries from around usually 80.000/100.000 to 40.000/50.000 and block-ratio dropped from 30-40% down to 15-20%

I’m running a daily cronjob to gather these stats with padd.sh:

59 23 * * * echo -e $(date +\%Y-\%m-\%d) $(docker exec --tty pihole /etc/pihole/padd.sh -j) >> ~/logs/pihole-padd.log


With these tweaks I’m usually getting a cache hit ratio of 50% (see screenshot on top of this page: “Upstream servers”, the blue cake slice is “cached”)) and more with a very low latency for most DNS queries with an average of slightly below 20ms (on a weekly basis and if there are no internet outages).

Force network-wide usage of SafeSearch (Google, Startpage.com):

“This method leverages SafeSearch VIP to force all users on your network to use SafeSearch on Google Search while still allowing a secure connection via HTTPS. The VIP in SafeSearch VIP refers to a Virtual IP, which is an IP address that can be routed internally to multiple Google servers. We will serve SafeSearch results for all requests that we receive on this VIP, which includes Google search, image search, and video search. It works for all browsers on your device and only users who are administrators on the device can undo this change.” Map google domains to forcesafesearch.google.com
Just add these hostnames/domains to your “Local DNS” / “DNS Records”:


Other search engines use “moderate search” by default, but “safe search” can be turned off at any time). I didn’t find any offer like this for Bing, DuckDuckGo and others.

⚠️ Caution: This forces SafeSearch for all devices on your network! ⚠️


Usage at home

Just change DNS resolver in DHCP options of your router so that all devices in your home network use your Pi-hole. For example:

💣 If you’re a Vodafone Customer and if you’re only using the provided Vodafone Station you will not be able to do this! VF Station has no option to change DNS resolvers, so go and buy a router that you own and that you can configure as you want and build up a router cascade. 💣


Usage in foreign networks (“free” WiFi / Hotspots and mobile data (4G/5G))

Go and download WireGuard app for your device:

After you’ve set up your WireGuard server with one or the desired amount of peers you can show your WireGuard tunnel config as QR-code:

docker exec -it wireguard /app/show-peer <peer-name>

On your mobile device you can simply scan this QR-code and you’re finished. Edit your config to enable “on-demand tunneling” for “mobile data” and all WiFi except your WiFi at home which is already protected by your Pi-hole at home.

On your computer you have to copy and paste the following output from your WireGuard server into your WireGuard app:

docker exec -it wireguard cat /config/peer_<peer-name>/peer_<peer_name>.conf



I use some scripts for regular and automated updates:



cd ~/dev/docker-pi-hole && {
  git stash; git pull; git stash pop -q
  # https://github.com/docker/compose/issues/5960#issuecomment-390952779
  docker-compose pull --no-parallel 2>&1 | grep "is up to date" || \
    { docker-compose stop && docker-compose up -d; }



docker pull ghcr.io/linuxserver/wireguard | grep "is up to date" || \
docker stop wireguard
docker rm wireguard

# https://github.com/linuxserver/docker-wireguard

# peer names are only supported alphanumeric:
# https://github.com/linuxserver/docker-wireguard/issues/135

#  -e ALLOWEDIPS=, `#optional` \
docker run -d \
  --name=wireguard \
  --cap-add=NET_ADMIN \
  --cap-add=SYS_MODULE \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Europe/Berlin \
  -e SERVERURL=wireguard.example.com\
  -e SERVERPORT=12345 \
  -e PEERS=1 `#optional` \
  -e PEERDNS=auto `#optional` \
  -e INTERNAL_SUBNET= `#optional` \
  -p 12345:12345/udp \
  -v ~/temp/etc-wireguard:/config \
  -v /lib/modules:/lib/modules \
  --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
  --restart unless-stopped \


With these cronjobs for daily WireGuard updates and weekly Pi-hole updates:

10  5 * * * ~/bin/docker-wireguard-update.sh &> ~/logs/docker-wireguard-update.sh.log
15  7 * * 1 ~/bin/pi-hole-update.sh &> ~/logs/pi-hole-update.sh.log

Have fun and stay safe! 💚