I recently setup Pi-hole on an existing Raspberry Pi running CentOS on my home network to serve as my DNS server and block advertising and unwanted domains for all internet-connected devices. I’m still using an ASUS router with Shibby Tomato firmware for routing, DHCP and private VLANs so I had to make a few changes. This is how I got up and running along with some performance tuning.
Pi-hole is a set of software packages that provide filtering and advertisement blocking for all internet services on your network. It alleviates what might traditionally be done via adblockers or per-device software because it blocks things at the DNS level. It uses dnsmasq, lighttpd, FTL and some other packages to tie all this together into a nice, easy-to-use web interface. Pi-hole can be installed on any existing Linux device or VM.
Pi-hole utilises several well known and trusted internet blacklists and keeps them up-to-date. At the DNS level it can then thwart unwanted ads, malware domains and other unsavoury internet denizens from appearing on any of your internet devices or computers.
This video gives a decent overview.
How It Works
You can have pi-hole handle your DNS, DHCP or both. On the LAN side it uses dnsmasq as a caching DNS server where filtering/discarding happens. Upstream lookups are performed by choosing one of the several free options like Google DNS, OpenDNS, Level3 and others or you can enter your own.
For my purposes I wanted Pi-hole to perform bare-minimum caching DNS duties as my Tomato router does a good enough job of handling DHCP and address assignment. I am also using private, isolated VLANs for devices that are less than trustworthy like Smart TVs.
Update: 2018-04: If you want to setup Pi-Hole as a Docker container and have it “on the go” on your laptop via local DNS scroll to the bottom of this guide.
Getting Started – My Network
I am running pi-hole on an existing Raspberry Pi for DNS services, but this could be any host or VM inside your network. I have DHCP services handled by my router. Once setup I just needed to point static DNS from my Tomato router to use the new pi-hole service.
I am going to assume you’re using a Linux-based device like a Raspberry Pi running on CentOS but any VM or host will work. The official instructions tell you to curl a script and pipe it to bash as root but we’re not going to do that.
Install Git and EPEL Repository for ARM
yum install git -y
Next, ensure you have the EPEL repository installed. On ARM devices like the Raspberry Pi you can use the snippet below to enable it.
cat > /etc/yum.repos.d/epel.repo << EOF [epel] name=Epel rebuild for armhfp baseurl=https://armv7.dev.centos.org/repodir/epel-pass-1/ enabled=1 gpgcheck=0 EOF
Now you’re ready to clone pi-hole and run the automated installation script.
Clone and Run the Installation Script
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole cd "Pi-hole/automated install/" sudo bash basic-install.sh
The automated installation script will now execute.
After any missing packages are installed it will setup and configure itself and you’ll be presented with configuration details.
You’ll then be presented with an ncurses configuration guide, the defaults are just fine.
At this point you should be able to access http://your-pi-hole-machine/admin/index.php to access the web interface. Be sure to copy the web GUI admin password printed on the screen and keep it somewhere safe. You may need to manage your own firewall rules here, so make sure that UDP/53 (DNS) and TCP/80 (HTTP) are open on your Pi-hole host.
Limit Writes to Solid State Devices
It’s recommended to lower the DBINTERVAL setting for the FTL service from the default of 1second to 60 seconds to limit the frequency of database writes. This should prolong the life of your SD, SSD, M2, or similar solid state device if you’re using one.
cat > /etc/pihole/pihole-FTL.conf << EOF # Lower DB writes for SD card life to 60 # https://wiki.archlinux.org/index.php/Pi-hole#FTL DBINTERVAL=60 EOF
Now restart the FTL service to take effect.
systemctl restart pihole-FTL
Resolving Internal Domain Names
If you’re not using Pi-hole for managing both DHCP and DNS then you’ll want to maintain a static mapping of local (LAN) ip addresses to hostnames for local resolution.
Pi-hole needs this so you will show hostnames instead of local ip addresses in your query logs, dashboard and visualizations.
You can do this with the /etc/hosts file on your Pi-hole host.
192.168.0.22 localwebserver01 192.168.0.23 localwebserver02 192.168.0.24 mysketchytelevision
Tuning dnsmasq for Higher Traffic
Before you point your router or clients to start using pi-hole for your DNS you may want to tune settings for more demanding networks or a larger amount of clients. I added the following to my /etc/dnsmasq.d/02-custom-settings.conf.
cat > /etc/dnsmasq.d/02-custom-settings.conf << EOF #### EDIT SETTINGS dns-forward-max=5096 min-cache-ttl=300 rebind-domain-ok=/plex.direct/ #### END EDIT EOF
Let me explain these above:
- dns-forward-max = this increases the max DNS forward limit, if you have a rather busy internal network you will easily hit the limit of 150 which in my opinion is way too low. 1024+ is more realistic.
- min-cache-ttl = This extends the minimum time-to-live settings for cached lookups and ensures all DNS lookups will be cached for at least 300 seconds. This is a very useful setting and lets you take full advantage of caching nameserver capabilities.
- rebind-domain-ok = this lets you specify domains where DNS rebind support is needed like the Plex Media Server. If this doesn’t mean anything to you then you probably don’t need it.
Apply the new tunings by restarting the dnsmasq service.
systemctl restart dnsmasq
Test DNS resolution on another system in your network, you should quickly get responses back from dig requests
dig @192.168.0.98 hobo.house
If all is clear now it’s time move your DNS to pi-hole. If you specify DNS servers for each of your clients then you just need to update them to point to your newly setup device.
At this point you’re done, skip past the Tomato section if this doesn’t apply to you for Pi-hole usage, common commands and useful tips.
Pointing your ASUS Tomato Router to Pi-Hole for DNS
I am using an ASUS Black Knight router running the Shibby Tomato firmware, which I will use for demonstration purposes.
First I need to point it to use my new pi-hole DNS (192.168.0.98 in my case)
Next, I need to turn off the existing DNS settings that Shibby Tomato previously managed for me.
Additionally you might need these settings for dnsmasq.conf within Tomato to ensure that all wireless clients obtain Pi-hole DNS via Tomato DHCP if you see (forwarded) in query logs.
If you see the following in Pi-hole query logs then you need to set the below setting
Besides setting the below dnsmasq Tomato settings I also enabled the two SLAAC and DHCP IPv6 options below.
Here are the dnsmasq lines for easy copy/paste, you should substitute my 192.168.0.98 for your Pi-hole address.
server=192.168.0.98 dns-forward-max=5096 min-cache-ttl=600 dhcp-option=6,192.168.0.98
Lastly I need to add a static route for any private, isolated VLANS I am managing with Tomato Shibby. In my case I was using 172.16.0 for my private VLAN but I use 192.168.0 networks for everything else. This is needed to allow DNS traffic between the normally-isolated networks. You can disregard this step if you don’t have such a setup.
Without the static route I would never be able to route 172.16.0 –> 192.168.0.98 (Pi-hole) for DNS traffic.
Testing and Using Pi-Hole
At this point clients in your home network, including all wireless clients should be immediately benefiting from the ad, malware and bad-people-on-the-internet filtering provided by pi-hole. You can access the web UI and note stats, percentage of traffic , statistics per client, blocks, common domains and other useful information.
Note that the Percent Blocked are DNS queries to/from undesirable locations like known advertising, beacons, trackers which would normally denote some level of accompanying network traffic – it’s not actual network traffic blocked.
For reference these are the DNS settings I have set in the UI. You can just as easily manage these in /etc/dnsmasq.d/01-pihole.conf via SSH and restarting the dnsmasq service.
Note: I am now using the Cloudflare DNS 126.96.36.199 / 188.8.131.52 and their IPv6 servers in lieu of Google DNS or others.
Here they are for your convenience:
IPv4 DNS #1 -> 184.108.40.206 IPv4 DNS #2 -> 220.127.116.11 IPv6 DNS #1 -> 2606:4700:4700::1111 IPv6 DNS #2 -> 2606:4700:4007::1001
I have opted for listening/permitting all origin traffic as my Pi-hole is firewalled behind my Tomato router and I need to accept multi-hop origin requests from private VLANs from within my network. Most people can use “Listen only on interface eth0” for example.
There are also options for blacklisting and whitelisting domains, you can access this in the UI settings.
You can run the supplied pihole script to update it over SSH – this will update the core version if there is an update available.
Pi-hole already sets up a cron job in /etc/cron.d/pihole however which updates the ad sources once a week, the above is just for updating the released version. You can also run this inside the web interface.
You can also issue common commands as needed via SSH, check pihole -h for more info.
pihole -b unwantedsalescrap.net moreunwantedjunk.com
White listing domain(s)
pihole -w myfriendsblogthing.org thisotherblog.net
Blacklisting wildcard domains, e.g. any url and associated subdomains.
This is for single domains only.
pihole -wild reallyirritatingmarketing.com badpeople.org
Querying the ad lists domains. You can also pass -exact to match more precisely.
pihole -q domain.match.here
Changing the web admin password. If you leave the new password blank it will simply not prompt for one.
pihole -a -p
Pi-hole also comes with a nice top-like chronometer utility
Adding More Block Lists
While you can use either the pihole -b (blacklist) or pihole -wild (wildcard domain block) for blocking single domains the most efficient way to protect your network is through domain block lists.
Domain block lists are cultivated 3rd party lists that contain many many domains that are known to be malicious or contain unwanted advertising and trackers. When you add block lists your pi-hole will query them and keep your block lists updated via cron.
I’ve found a great source of additional block lists over at the cryptoaustralia.org blog as well as wally3k. You can easily add/manage block lists in the web UI under Settings -> Block Lists. Enter each block list one at a time and hit save, click save and update when you are finished and it will regenerate.
You can also manage them via the CLI by adding entries new sources to 3rd party blocklists in /etc/pihole/adlists.list and then tell pi-hole about it.
Here are the additional 3rd party block lists I am using, they’ve worked for me with no issues and block around 555,000 domains. Out of the box Pi-hole should block around 123,000 domains as of typing this.
Below you can paste this and it will add all my blocklists to your Pi-hole
pihole tee -a /etc/pihole/adlists.list >/dev/null << EOF ### hobo.house list https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts https://mirror1.malwaredomains.com/files/justdomains http://sysctl.org/cameleon/hosts https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt https://hosts-file.net/ad_servers.txt https://hosts-file.net/exp.txt https://hosts-file.net/emd.txt https://hosts-file.net/psh.txt https://v.firebog.net/hosts/Airelle-hrsk.txt https://v.firebog.net/hosts/Shalla-mal.txt https://ransomwaretracker.abuse.ch/downloads/RW_DOMBL.txt https://ransomwaretracker.abuse.ch/downloads/LY_C2_DOMBL.txt https://ransomwaretracker.abuse.ch/downloads/CW_C2_DOMBL.txt https://ransomwaretracker.abuse.ch/downloads/TC_C2_DOMBL.txt https://ransomwaretracker.abuse.ch/downloads/TL_C2_DOMBL.txt http://www.networksec.org/grabbho/block.txt https://isc.sans.edu/feeds/suspiciousdomains_Medium.txt http://someonewhocares.org/hosts/hosts https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt http://www.joewein.net/dl/bl/dom-bl.txt https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/win10/spy.txt https://v.firebog.net/hosts/static/SamsungSmart.txt https://gist.githubusercontent.com/anudeepND/adac7982307fec6ee23605e281a57f1a/raw/5b8582b906a9497624c3f3187a49ebc23a9cf2fb/Test.txt https://raw.githubusercontent.com/StevenBlack/hosts/master/data/KADhosts/hosts https://reddestdream.github.io/Projects/MinimalHosts/etc/MinimalHostsBlocker/minimalhosts https://raw.githubusercontent.com/StevenBlack/hosts/master/data/add.Spam/hosts https://v.firebog.net/hosts/static/w3kbl.txt EOF
Now you’ll want to reload Pi-hole with the new list:
You may want to keep an eye on your DNS queries the first 24hours or so to make sure you’re not blocking any false positives. You can unblock/whitelist domains with the pihole CLI (it’s reported doing this via the UI doesn’t always work currently).
Domains I Whitelist Manually
There were a few I had to white list for example:
pihole -w youtu.be opensubtitles.org www.opensubtitles.org t.co
Update: here are a few more I had to add, wrapped for your convenience. Your mileage here may vary depending on the services you use.
pihole -w pubsub.plex.tv plugins.plex.tv chapterdb.plex.tv cloudfront.net \ plex.direct csi.gstatic.com dl.opensubtitles.org speedvideo.net ton.twimg.com \ twimg.com chapterdb.plex.tv tinyurl.com bit.ly ton.twimg.com dropbox.com \ pubsub.plex.bz fonts.gstatic.com assets.adobedtm.com www.googletagmanager.com \ links.services.disqus.com ump.plex.tv meta.plex.tv goo.gl
Domains I Block Manually
On that same note, here are domains I’ve manually blacklisted after a few weeks of watching my query logs. These either came from my hawkish observations or known telemetry domains, one or two even traced back to questionable entities located in the Washington, D.C. area. Some of these are just downright ridiculous, come on Microsoft ..
pihole -b dxp.baidu.com hmma.baidu.com pasta.esfile.duapps.com \ neweegg.net config.a-mo.net nrc.tapas.net xpu.samsungelectronics.com \ upu.samsungelectronics.com dns.msftncsi.com bn2wns1b.wns.windows.com \ a-0001.a-msedge.net msnbot-65-52-108-90.search.msn.com a-0011.a-msedge.net \ bn2ap002.device.ra.live.com a.ads1.msn.com a.ads2.msn.com ad.doubleclick.net \ adnexus.net adnxs.com ads.msn.com ads1.msads.net ads1.msn.com \ az361816.vo.msecnd.net az512334.vo.msecnd.net ca.telemetry.microsoft.com \ cache.datamart.windows.com choice.microsoft.com corp.sts.microsoft.com \ choice.microsoft.com.nsatc.net choice.microsoft.com.nstac.net \ choice.microsoft.com.nstac.net compatexchange.cloudapp.net corp.sts.microsoft.com \ corpext.msitadfs.glbdns2.microsoft.com cs1.wpc.v0cdn.net \ db3wns2011111.wns.windows.com df.telemetry.microsoft.com \ diagnostics.support.microsoft.com fe2.update.microsoft.com.akadns.net \ fe3.delivery.dsp.mp.microsoft.com.nsatc.net feedback.microsoft-hohm.com \ feedback.search.microsoft.com feedback.windows.com i1.services.social.microsoft.com \ i1.services.social.microsoft.com.nsatc.net msnbot-207-46-194-33.search.msn.com \ oca.telemetry.microsoft.com oca.telemetry.microsoft.com.nsatc.net \ pre.footprintpredict.com preview.msn.com rad.msn.com \ redir.metaservices.microsoft.com reports.wes.df.telemetry.microsoft.com \ settings-sandbox.data.microsoft.com settings-win.data.microsoft.com \ settings.data.microsof.com sls.update.microsoft.com.akadns.net spynet2.microsoft.com \ spynetalt.microsoft.com sqm.df.telemetry.microsoft.com sqm.telemetry.microsoft.com \ sqm.telemetry.microsoft.com.nsatc.net ssw.live.com statsfe1.ws.microsoft.com \ statsfe2.update.microsoft.com.akadns.net statsfe2.ws.microsoft.com \ survey.watson.microsoft.com telecommand.telemetry.microsoft.com \ telecommand.telemetry.microsoft.com.nsatc.net telemetry.appex.bing.net \ telemetry.microsoft.com telemetry.urs.microsoft.com view.atdmt.com \ v10.vortex-win.data.microsoft.com vortex-sandbox.data.microsoft.com \ vortex-win.data.microsoft.com vortex.data.microsoft.com watson.live.com \ watson.microsoft.com watson.ppe.telemetry.microsoft.com \ watson.telemetry.microsoft.com watson.telemetry.microsoft.com.nsatc.net \ wes.df.telemetry.microsoft.com win10.ipv6.microsoft.com adservice.google.com \ ads.aws.viber.com stats.appsflyer.com adservice.google.ie referrer.disqus.com \ browser.pipe.aria.microsoft.com tracking.campaign-tracking-service.placelocal.com \ primoitaliablob.blob.core.windows.net srv.dc-1.net \ wdcpeurope.microsoft.akadns.net wdcp.microsoft.akadns.net
Wildcard Domains I Block Manually
Additionally I also started blocking these wildcard domains as they were advertisers, trackers or just sketchy connections from China that showed up with an older Android tablet I use as an alarm clock.
pihole -wild bidr.io 88-f.net mythings.com
I will be keeping all these lists updated
Right away I saw an increase in general responsiveness across all my devices, most likely due to the caching name server settings. I expect a further increase in responsiveness soon due to blocking many of the known advertising sources. The graphing, logging and dashboard information is easy to read and inspect.
I really like the idea of this project and how it ties everything together. Ad-blocking using 3rd party block lists isn’t a new concept but packaging this into an easy-to-use solution that works on any existing machine using OSS tools is really useful.
In upcoming versions the FTLDNS or “Faster than Light DNS” should make an appearance which adds more direct hooks into dnsmasq and speed things up even more from a user perspective, though it’s already pretty snappy.
Performance and Usage
A few hours after implementing Pi-hole around 10% of the DNS lookups on my home network showed to be attempts by advertisements, trackers and other undesirables, this is now curbed. I even managed to blacklist some additional domains from China (baidu.com) I noticed in the query log that I’m not sure had any reason to be talking to my network. It is also very lightweight to run, consuming around 9mb of memory and a very nominal amount of CPU on the Raspberry Pi2 and CentOS7.
Whitelisting not Working via Web UI
As of Pi-hole 3.3 there are some known issues with whitelisting domains via the web interface, the workaround for this is to remove the whitelist via the web interface and re-add it via pihole -w domain.name.here. This does not affect all users, only some due to a locale issue and should be fixed soon. This did not affect me on CentOS7 / Raspberry Pi2 in the GMT timezone.
Statistics 24 Hours after Install
After 24hours I started to see the real DNS blocking imprint with 20-some-odd devices on my home network, a few friends over contributing to the fray and a full day of working remotely. I also added a dozen more block lists to the mix, pushing my block domains up to around 555,000.
Upwards of 22% of the DNS lookups were blocked which normally would have incurred some additional traffic overhead. CPU and memory usage stayed about the same, it’s pretty lightweight. General device network responsiveness to queries continued to be snappier than they were before it was deployed.
Containerized Pi-hole on the Go
You can also install Pi-hole as a docker container and then set it up on your laptop and set the Pi-hole container as your DNS. This works pretty well, and supports any platform that can run Docker containers. Credit goes to Kayvan Sylvan for providing the script and idea for this.
Here’s a quick and dirty guide to get this going, note that I’m not a docker expert so there may be a better way – if so please leave me a comment.
Install and Setup Docker
First you need docker installed and running on your system
dnf install docker wget -y
Set docker to auto-start on boot and start the docker container service.
systemctl enable docker systemctl start docker
Run the Pihole Docker Container
Now you’re going to pull down and run the latest docker pihole container. We’re going to run it in daemon mode and restart on boot.
docker run -d --name pihole --restart=always diginc/pi-hole:debian
This will take about 20-30seconds to start up, you’ll want to query and wait for it to be fully instantiated before any further customization. You can query this via docker ps. You’re looking for “starting” status to turn into “healthy”
[root@oberschnutz ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2212eaa2d5ff diginc/pi-hole:debian "/s6-init" 27 seconds ago Up 26 seconds (health: starting) 53/tcp, 80/tcp, 53/udp pihole
Checking again in a 20 seconds we see it’s up and running now
[root@oberschnutz ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2212eaa2d5ff diginc/pi-hole:debian "/s6-init" About a minute ago Up About a minute (healthy) 53/tcp, 80/tcp, 53/udp pihole
Run Post-Setup Script
Right now Pi-hole is running. If you don’t care about adding additional blocklists you can just point your local /etc/resolv.conf to use the Pi-hole container IP address or wherever you set your name resolution to use it. For me that was 172.17.0.2 but see command below to check it.
At any point you can access a console in your docker container via:
docker exec -ti pihole bash
We’re going to proceed with adding more blocklists however and further customization. Pull down the custom setup script and run it. This will add additional block lists and remove the web admin password since you’re running it locally.
Now run it against the container.
sh +x ./pihole-post-config.sh
Point Local DNS to your Pihole Container
You’re going to need to first obtain the IP address your container is running with so you know what to set as your nameserver as well as the web interface.
docker container inspect pihole | grep IPAddress
"SecondaryIPAddresses": null, "IPAddress": "172.17.0.2",
I took this opportunity to point DNS to use CloudFlare’s new IPv4 and IPv6 addresses for external lookups.
Next do a quick dig test to make sure it’s working correctly.
dig @172.17.0.2 hobo.house
If this returns a response you’re in business, now you can set your DNS to this.
To make this persistent where connecting to other wifi or wired networks won’t change this you’ll need to use the chattr command to make it immutable.
chattr +i /etc/resolv.conf
NOTE: This may break VPN connections which need to impose their own internal DNS – in those cases you’ll want edit your DNS after you’ve connected to place the Pi-hole DNS back in your /etc/resolv.conf after getting the VPN DNS entry.
If your VPN client provides pre and post scripting (OpenVPN CLI can do this) it’s better to have this happen automatically (chattr -i / connect / re-add pi-hole DNS / chattr +i ) but here’s how you’d do it manually.
chattr -i /etc/resolv.conf
Now connect to your VPN. After connecting you can add it back:
echo "nameserver 172.17.0.2" >> /etc/resolv.conf
Now set your /etc/resolv.conf back to being immutable
chattr +i /etc/resolv.conf
At this time I don’t believe NetworkManager supports pre and post connection for VPN clients but the OpenVPN cli can do this for you.
Caveat: Wildcard Blocking is Broken using Fedora Docker Repositories
Note: I have noticed that adding wildcard blocklists will break Pi-hole running in the container, either via the UI or pihole -wild. I haven’t dug into this in-depth but it does break the running DNS service. This happens for me anyway on Docker 1.13 via the Fedora 27 repositories. I’m told this isn’t the case with the latest docker-ce packages from Docker.
If this happens you can either remove the offending dnsmasq wildcard config or simply kill the container and pull it down again and re-run the setup script.
docker exec -ti pihole rm -f /etc/dnsmasq.d/03-pihole-wildcard.conf docker exec -ti pihole -g
Or the hammer approach
docker rm -f pihole
Now re-run the post-setup script above. If you want wildcard functionality you should use the Docker-ce repos instead until this is fixed.
Docker Power Usage on Laptops
I haven’t seen a whole lot of power usage from running a Pi-hole docker container, on my Lenovo x270 it looks to be minimal – around 173 mW or 0.17 W.
73.8 mW 366.4 µs/s 14.8 Process [PID 3508] pihole-FTL no-daemon 100 mW 0.0 pkts/s Device nic:docker0 357 µW 72.8 µs/s 2.1 Process [PID 1154] /usr/bin/dockerd-current 0 mW 6.6 µs/s 0.00 Process [PID 3584] /usr/bin/dockerd-current
Pi-Hole Container Performance
The Pi-hole container is pretty lightweight, on average using aronud 50 MB of memory or around 0.36% of my 16GB of memory on my Lenovo x270 running Fedora 27.
You can run query the performance at any time via:
docker stats pihole