Installing & Configuring Pi‐Hole DNS with Conditional Forwarding - cfloquetprojects/homelab GitHub Wiki
Introduction:
-
The Pi-hole project was started in 2015, and has evolved into one of the most popular network-level advertisement and internet tracker blocking applications for DIY and tech enthusiasts, acting as a DNS server/sinkhole (and even DHCP server) for local clients within your network.
-
Today we will be deploying Pi-hole onto a virtualized instance of Ubuntu 22.04 LTS.
graph LR
A[Local Network Device] <-- 53/UDP --> B{Pi-hole}
B -- Malicious/Suspicious Query --> D(Not forwarded, but logged and rejected)
B <--> C[Upstream Recursive DNS such as Cloudflare, OpenDNS]
B <-- Conditionally Forwarded Internal Query --> E[Local DNS Server]
Resources:
- Pi-hole Docs: Basic Installation
- Redhat Docs: Configuring Complex Firewwall Rules with "Rich Landguage" Syntax
Pre-Flight Check:
💡 If you are installing on a Raspberry Pi device, I highly recommend using the free Pi Imager software which is extremely intuitive and has Ubuntu v22.04 (as well as many other cool Linux distros you can check out).
-
Properly networked (has a static internal IPv4 address, and local gateway defined) Ubuntu v22.04 LTS (core) virtual machine.
1a. Preferably 2gb+ of RAM, 15-20gb storage (SSD best for performance, we will also be exporting logs to a SIEM on regular basis).
-
Requisite software includes
net-tools
,curl
, and optionallyfirewalld
which I use to configure firewalls, butufw
is a native firewall for Ubuntu and works just as well, this software can be installed with the following on Ubuntu v22.04:
# sudo apt-get -y install net-tools curl firewalld
-
The last portion of this blog includes instructions on how we can direct DNS queries according to the destination network of the target IPv4/hostname being resolved through "conditional forwarding" on the Pi-hole administration panel.
3a. If you don't have an internal DNS server or domain controller and are using this guide strictly for guidance on how to deploy Pi-hole on Ubuntu v22.04 LTS, then feel free to ignore this (final) section..
💣 I strongly recommend taking additional steps to harden your device running Pi-hole such as changing any default account passwords, disabling remote login (via ssh) as root, and updating any out of date packages (which is our first/next step anyways).
Setting Up the System and Pi-hole User:
- First things first, we need to make sure our host is has the latest packages & updates prior to any installations:
# sudo apt-get -y update && sudo apt-get -y upgrade
- Additionally, while using the
root
user is required (via it's invocation throughsudo
) for the installation of Pi-hole, I will be creating a named user (called pihole for simplicities sake - separate from the root account).
💡 We will use the
pihole
user for accessing the system remotely (since it's best practice to disable root login withinsshd_config
), as well as for future projects where we enhance & augment our DNS blocking capabilities, where we can store scripts or keys within that user's profile, rather than the root account.
- We can create a new named user using the native
adduser
command within Ubuntu, from which we will be prompted to set that users credentials, as well as some contextual information (name, contact, etc.) which we can leave blank/default (as shown in the screenshot below).
# adduser pihole
- Next we need to add this user to the "sudoer" group, which will allow us to assume or invoke the root user via the
sudo
command (which is just a shortened version of 'super user do').
💡 If you're curious what the "-aG" flags are for, you can read more about it on the usermod manual page, but essentially it means we will be adding a group membership to this user.
# usermod -aG sudo pihole
Fetching & Running the Pi-hole Install Script:
- The installation of Pi-Hole on Ubuntu is extremely simple, thanks to a very nifty shell script that we can fetch/save using
curl
, before usingchmod
to make it executable, and launching (as shown below):
$ curl -sSL https://install.pi-hole.net >> install-pihole.bash
$ chmod +x install-pihole.bash
$ sudo ./install-pihole.bash
💡 You can proceed with defaults, when prompted for upstream DNS server I typically opt for CloudFlare and OpenDNS, but you can choose whatever provider you want, and it shouldn't impact your success in completing this lab.
- Once the installation completes, you should be presented with a screen similar to the one shown below, with the static IPv4 of your server, as well as the the URL that you can now use to access the administrative panel of your Pi-hole instance:
- Navigate to
http://<your_pi-hole_server_ip/admin
using a browser of your choice to see if it loads properly for you:
💡 Now that we have confirmed general access/availability to the management/administration panel of our Pi-hole instance is possible, we can then take the OPTIONAL step to restrict what networks (and subsequently, devices) within our environment can access this page, reducing the chance of unauthorized access/discovery of this management panel by nosy end users or even malicious actors.
Restricting Access to Pi-hole Administration Panel using Rich FirewallD rules:
💣 This section covers the optional step of implementing "rich" rules within the firewalld utility on our Pi-hole instance, feel free to skip this section if you aren't looking to further restrict/harden access to your Pi-hole instance.
- By invoking the
root
user through thesudo
command, we can start thefirewalld
service that we installed earlier, and from there use thefirewall-cmd
command combined with the--list-all
flag to display all current (default) rules:
$ sudo systemctl start firewalld
$ sudo systemctl enable firewalld
- Let's use
firewall-cmd
to modify the local iptables rules to strictly limit connections over HTTP/HTTPS ports (80 and 443 respectively) from remote clients that are not within our designated management subnet (10.0.3.0/24), starting with 443/tcp:
$ sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.3.0/28"
port protocol="tcp" port="443" accept'
- Next create a similar rule for port 80/tcp, for allowing HTTP traffic (since we don't yet have any PKI infrastructure with which we can apply valid certificates to our internal websites for authenticity etc.):
$ sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.3.0/28"
port protocol="tcp" port="80" accept'
- Finally we need to allow 53/udp, which is the port & protocol used for DNS, and since we will be broadly accepting DNS queries from clients regardless of what their origin/network disposition, we won't apply any "rich" filters for this ingress rule:
$ sudo firewall-cmd --add-port=53/udp --permanent
- With these rules applied, we can confirm our configuration is setup for success by using the
firewall-cmd
command combined with the--list-all
flag:
$ sudo firewall-cmd --list-all
- At this point, as a test for posterity we can test accessing our Pi-holes' administrative web dashboard (as we did before) from an IP not in the subnet we explicitly allowed earlier (in my case the management network of 10.0.3.0/24).
💡 The screenshot below depicts a successful connection from my management workstation (hera01) while a failing connection from my personal desktop:
Configuring Conditional Forwarding of Local DNS Record Queries on Pi-hole:
-
For our us to benefit from our domain clients forwarding their DNS queries any destination other than a domain controller for processing/review, we need to setup rules which can selectively forward DNS queries for internal records to our domain controller for resolution.
-
We can accomplish this using conditional forwarding, found under
Settings > DNS > Advanced DNS Settings
in the Pi-hole management dashboard, as shown in the screenshot below:
💣 Please note that failure to take this step to configure special forwarding of these requests will result in issues for future network clients using Pi-hole as it's primary DNS server when attempting to join the domain, or resolve hostnames for any internal network resources.
- The screenshot below shows my management workstation
hera01
after being reconfigured to use the Pi-hole server (10.0.3.12) as it's primary DNS, and first failing to resolvehomer.local
before I implemented the conditional forwarding rules, when after I was able to properly receive the IPv4 address associated with that A record (according to the local domain controller, not the Pi-hole server!).
- At this point we've confirmed a successful install & configuration of our Pi-hole server, specifically for use in the context of our home lab to field DNS queries and forward them accordingly based on the target being resolved.