Article cover image

How to configure Pi-hole for local DNS resolution in your LAN

Author profile image
Aitor Alonso

9 min read

RSS feed

This article is a companion to my previous one on how to use Caddy as a reverse proxy for your services. In that article, I set up Caddy so that services are reachable via custom local domains like myservice.home.arpa, but for those domains to actually work, every device on your LAN needs to be able to resolve them — and that’s exactly what we tackle here. In today’s article I’ll explain how I use Pi-hole as a local DNS server to achieve network-wide resolution for those custom domains without touching every device’s hosts file. Let’s dive in!

Why local domains and why .home.arpa?

Before jumping into the setup, let me quickly explain why this is useful and why I use .home.arpa as my local TLD.

When you self-host services, you usually access them by typing their local IP address and port directly in the browser, like http://192.168.1.100:8080. This works, but it’s ugly, hard to remember, and doesn’t play well with HTTPS (certificates are usually tied to domain names, not bare IPs, although I explain how to generate certificates for bare IPs with your own CA in another article). The natural solution is to assign readable domain names to your services, like myservice.home.arpa, which it’s not only easier to remember, but gives you more flexibility if for whatever reason you need to migrate it to a different hardware over a different IP address.

As for the TLD choice: .home.arpa is the officially reserved special-use domain for residential LANs. Using it ensures you will never accidentally conflict with a real public domain now or in the future, which is a real risk if you just invent something like .local or .home. .local in particular is already reserved for mDNS (Bonjour/Avahi), so you must avoid it. Stick with .home.arpa and you’ll be safe.

Installing Pi-hole

Pi-hole is a network-level DNS server and ad-blocker. It’s designed to run on a Raspberry Pi (hence the name), but it will happily run on any Linux machine, including a VM or a Docker container. For this tutorial, I’ll assume you’re installing it on a Debian-based system (Raspberry Pi OS, Debian, Ubuntu…).

Pi-hole provides an official one-liner installer:

curl -sSL https://install.pi-hole.net | bash

The installer is interactive and will guide you through the configuration. A couple of things to keep in mind during the setup:

  • When asked for the upstream DNS provider, choose any public resolver you trust (I use Cloudflare’s 1.1.1.1 and 1.0.0.1). Pi-hole will forward queries it can’t answer locally to this provider.
  • When asked for the network interface, select the one connected to your LAN.
  • Take note of the static IP address your Pi-hole machine will use. The installer will remind you about this, but it’s crucial: if your Pi-hole’s IP changes, everything breaks. Make sure to either set a static IP on the machine itself, or create a DHCP reservation for it on your router.

Once the installer finishes, it will print the URL and credentials to access the Pi-hole web admin panel. Keep them safe!

Adding simple local DNS records

This is the core of what we want to achieve. Pi-hole includes a built-in local DNS resolver that lets you define custom DNS records, mapping domain names to local IPs. Open the Pi-hole web admin panel (by default at http://<pihole-ip>/admin) and log in. Then navigate to Settings → Local DNS Records. You will see a simple form with two fields: Domain and IP Address.

For example, if I have a Caddy reverse proxy running on a machine with IP 192.168.1.100, and I want myservice.home.arpa to point to it, I would fill in:

  • Domain: myservice.home.arpa
  • IP Address: 192.168.1.100

Click Add and that’s it. The record is immediately active, no restart needed. You can add as many records as you want, one per service or server. In my homelab, for example, I have records for my NAS, my Proxmox nodes, and each of the services I expose through Caddy.

Note
Pi-hole also supports CNAME records under Local DNS → CNAME Records. CNAMEs are useful when multiple service domains should point to the same machine. For example, if both serviceA.home.arpa and serviceB.home.arpa live behind the same reverse proxy at 192.168.1.100, you could create a single DNS A record for proxy.home.arpa → 192.168.1.100, and then two CNAME records: serviceA.home.arpa → proxy.home.arpa and serviceB.home.arpa → proxy.home.arpa. This way, if the proxy IP ever changes, you only update one DNS A record.

Adding complex local DNS records

But what about wildcard domains? For example, if you want *.home.arpa to resolve to the same IP, so you can have service1.home.arpa, service2.home.arpa, etc without adding a record for each one? Pi-hole’s built-in local DNS doesn’t support wildcards, but there’s a simple workaround: you can use dnsmasq directly, which is the DNS server Pi-hole uses under the hood. Just SSH into your Pi-hole machine and create a new file under /etc/dnsmasq.d/ with a .conf extension, for example /etc/dnsmasq.d/99-homelab.conf, and add the following content:

# Specific subdomain overrides
address=/myservice.home.arpa/192.168.1.100

# Wildcard for everything else
address=/home.arpa/192.168.1.120

With the above configuration, myservice.home.arpa will resolve to 192.168.1.100, while any other subdomain under home.arpa (like service1.home.arpa, nas.home.arpa, etc) will resolve to 192.168.1.120. After saving the file, we need to configure pi-hole to load the custom dnsmasq configuration files, and then restart it so the file is actually loaded. We can do that with the following commands:

sudo pihole-FTL --config misc.etc_dnsmasq_d true
sudo systemctl restart pihole-FTL

Alternatively, you can go to the Pi-hole admin panel, then Settings → Advanced (in the upper right corner) → All settings (back in the lateral menu) → Miscellaneous and checking the checkbox under misc.etc_dnsmasq_d. Then, again, restart Pi-hole to load the new configuration.

Making your devices use Pi-hole as their DNS server

Defining the DNS records is only half the work. The other half is telling your devices to actually query Pi-hole instead of the default DNS server assigned by your ISP. There are two ways to do this.

  • Option 1: Configure it on your router (recommended) - This is the best approach because it’s network-wide: every device that connects to your LAN (laptops, phones, smart TVs, IoT devices…) will automatically use Pi-hole as their DNS server without any extra configuration on each device. Every router is different, but the setting you’re looking for is usually under DHCP settings or LAN settings, and is often labeled DNS server or Primary DNS. Set the value to the static IP of your Pi-hole machine.

  • Option 2: Configure it per device - If you can’t or don’t want to change your router’s settings, you can configure each device individually to point to Pi-hole. The downside is obvious: you need to repeat this on every device, and any new device that joins your network won’t automatically benefit from it.

    • On macOS, go to System Settings → Network, select your active connection (Wi-Fi or Ethernet), click Details, and under the DNS tab add your Pi-hole’s IP as a DNS server. To avoid breaking internet connection when you are outside of your LAN (for example, if you are using a MacBook on the go), you might want to set up a network location, so that your Mac uses Pi-hole only when connected to your home network.
    • On other systems like Windows and Linux, the process is similar, and very often can be configured directly in the network settings. Just look for the DNS server configuration and set it to your Pi-hole’s IP. An in case you are using a portable device (like a laptop), be sure to configure it to use Pi-hole only when connected to your home network, otherwise you might have DNS resolution issues when outside of your LAN.

Verifying it works

Once you’ve configured at least one device to use Pi-hole as its DNS, it’s time to verify everything works correctly. The quickest way is to use nslookup or dig from a terminal on that device.

For example, to verify that myservice.home.arpa resolves correctly:

nslookup myservice.home.arpa

You should see an output like this:

Server:		192.168.1.10
Address:	192.168.1.10#53

Name:	myservice.home.arpa
Address: 192.168.1.100

Here, 192.168.1.10 is your Pi-hole, and 192.168.1.100 is the IP you configured in the DNS record. If you see that, your local DNS resolution is working! You can also verify it from a browser: open http://myservice.home.arpa and, if the service is running and listening on that IP, it should load. Of course, if you’ve set up TLS with Caddy and your own CA as I described in my previous articles, you can use https://myservice.home.arpa and get a green padlock too.

Note
The Pi-hole admin panel also shows the DNS query log in real time under Query Log. This is a great place to confirm your devices are sending queries to Pi-hole, and to troubleshoot any resolution issues. If you see your queries there and the status is OK, you’re all set.

Bonus: Using your own certificate to secure pi-hole admin panel with HTTPS

If you also want to use your own self-signed certificate from your own CA to secure the Pi-hole admin panel with HTTPS, you can jus follow the instructions on my CA article to generate a certificate for the Pi-hole. Then, once you have your separated server.key and server.crt files, you can just merge them into a pem file with cat server.key server.crt > pihole.pem, and copy that pihole.pem file into the Pi-hole machine under /etc/pihole/pihole.pem. Then, ensure the files permissions are correct:

# In the pihole machine
cd /etc/pihole
sudo chown pihole:pihole pihole.pem
sudo chmod 600 pihole.pem

Then, configure Pi-hole to use that certificate by editing the /etc/pihole/pihole.toml file

  [webserver.tls]
    # Path to the TLS (SSL) certificate file.
    #
    # All directories along the path must be readable and accessible by the user running
    # FTL (typically 'pihole'). This option is only required when at least one of
    # webserver.port is TLS. The file must be in PEM format, and it must have both,
    # private key and certificate (the *.pem file created must contain a 'CERTIFICATE'
    # section as well as a 'RSA PRIVATE KEY' section).
    #
    # The *.pem file can be created using `cp server.crt server.pem && cat server.key >>
    # server.pem` if you have these files instead
    #
    # Allowed values are:
    #     A valid TLS certificate file (*.pem)
-   cert = "/etc/pihole/tls.pem"
+   cert = "/etc/pihole/pihole.pem"

And finally, restart Pi-hole to apply the changes:

sudo systemctl restart pihole-FTL

Bonus: best adblock list to remove ads and protect your LAN against malware

For blocking ads, malware, cookie banners and other annoyances on my LAN I’m using a single adblock list: HaGeZi’s Pro DNS Blocklist. I highly recommend HaGeZi’s lists for a simple and easy single-list installation that will avoid you the hassle and problems of managing multiple lists. The list is updated frequently, and personally, the Multi Pro variant works perfectly for me, with not false positives so far. I recommend you to take your time to fully read the Readme of the GitHub repo to understand what each list contains. Higher tier list already includes the lower tier ones (for example, Multi Pro++ includes Multi Pro, which also includes Multi Normal, etc).

Wrapping up

That’s everything you need to have a clean, network-wide local DNS setup at home; that not only resolves local domain names like *.home.arpa to the correct IPs, but also removes annoying ads from your devices and protect your network against malware. Until next time!