$linuxjunkies
>

How to Set Up Pi-hole on a Linux Server

Set up Pi-hole on Linux for network-wide ad and tracker blocking — covers installation, blocklists, gravity updates, conditional forwarding, and DHCP.

IntermediateUbuntuDebianFedoraArch9 min readUpdated June 7, 2026

Before you start

  • A Linux server (physical, VM, or container) with a static LAN IP address
  • Root or sudo access on the server
  • Access to your router's admin interface to change DNS and optionally DHCP settings
  • Basic familiarity with your distro's firewall tool (ufw, firewalld, or nftables)

Pi-hole turns any Linux server into a network-wide DNS sinkhole that blocks ads, trackers, and telemetry before they reach any device on your LAN. Unlike browser extensions, it works on smart TVs, phones, consoles — anything that uses your network. This guide covers installation, blocklist management, conditional forwarding, and optionally handing DHCP duties to Pi-hole so every device gets it automatically.

Prerequisites and Network Planning

Before you start, decide on a static IP for the server running Pi-hole. Every router has a DHCP reservation option; use that or configure a static address at the OS level. If Pi-hole goes down and its IP changes, your whole network loses DNS. Pick something outside your router's DHCP pool — 192.168.1.2 is a common choice.

  • The server needs a working internet connection during install.
  • Open port 53 (TCP/UDP) inbound on any host firewall so clients can reach Pi-hole's DNS listener.
  • Port 80 (TCP) is needed for the web admin interface (optionally 443 if you add a cert later).
  • If Pi-hole will serve DHCP, also open port 67 (UDP).

Step 1 — Install Pi-hole

Pi-hole provides an automated installer. Audit the script at github.com/pi-hole/pi-hole before running it — that is good practice for any curl-pipe-bash install.

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

The interactive TUI walks you through interface selection, upstream DNS provider, blocklist selection, and whether to install the web interface. Accept the defaults for a first install — you can change everything afterwards. When prompted for a static IP, confirm the address you planned above.

At the end of the installer you'll see the randomly-generated web password. Copy it. You can reset it at any time:

pihole -a -p

Step 2 — Open the Firewall

Pi-hole needs DNS and HTTP reachable from your LAN. Commands differ by distro firewall tool.

ufw (Ubuntu/Debian default)

sudo ufw allow 53/tcp
sudo ufw allow 53/udp
sudo ufw allow 80/tcp
sudo ufw reload

firewalld (Fedora / RHEL / Rocky)

sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

nftables (Arch / manual setup)

sudo nft add rule inet filter input udp dport 53 accept
sudo nft add rule inet filter input tcp dport 53 accept
sudo nft add rule inet filter input tcp dport 80 accept

Make those nftables rules persistent by saving them to your ruleset file (typically /etc/nftables.conf) and ensuring nftables.service is enabled.

Step 3 — Point Your Router (or Clients) at Pi-hole

The fastest way to get network-wide coverage is to change the DNS server advertised by your router's DHCP. Log into your router admin page and set the primary DNS to Pi-hole's static IP. Leave secondary DNS blank or set it to the same IP — if you set a fallback to 8.8.8.8, devices will bypass Pi-hole when it's briefly unreachable and you'll lose blocking silently.

If you can't modify the router, configure each device's DNS manually, or skip ahead to the Pi-hole DHCP section so Pi-hole takes over DHCP entirely.

Step 4 — Manage Blocklists

Pi-hole ships with one default blocklist. The web interface at http://<pi-hole-ip>/adminAdlists is where you add more. A well-maintained starting set:

  • Steven Black's unified hostshttps://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
  • OISD (big)https://big.oisd.nl
  • hagezi/dns-blocklists (Pro)https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/pro.txt

After adding URLs, update Gravity (Pi-hole's compiled block database):

pihole -g

Output ends with a line like Pi-hole blocking is enabled (1,234,567 domains). The exact count varies by the lists you chose.

Automate weekly gravity updates with the built-in cron job Pi-hole installs at /etc/cron.d/pihole — it runs pihole updateGravity on a randomised weekly schedule by default. Verify it's present:

cat /etc/cron.d/pihole

Step 5 — Configure Conditional Forwarding

Without conditional forwarding, Pi-hole only knows devices by IP address. Conditional forwarding tells Pi-hole to send reverse-DNS lookups for your local subnet to your router, so the dashboard shows hostnames (laptop.local) instead of bare IPs.

In the web interface: Settings → DNS → Advanced DNS settings → enable Use Conditional Forwarding. Fill in:

  • Local network in CIDR notation — e.g. 192.168.1.0/24
  • IP address of your DHCP server — your router's LAN IP, e.g. 192.168.1.1
  • Local domain name — e.g. home or lan (match your router's setting)

Save, and within a few minutes the query log will start showing device names. This relies on your router answering PTR queries; some cheap routers don't. In that case, Pi-hole's own DHCP (next step) does a better job because it controls the leases directly.

Step 6 — Optional: Use Pi-hole as Your DHCP Server

Running DHCP inside Pi-hole gives it first-class knowledge of every hostname on the network and eliminates the need for conditional forwarding.

First, disable DHCP on your router. The exact location varies — look for "LAN settings" or "DHCP server" in your router's admin UI. Turn it off, but keep the router's static LAN IP as the gateway.

Then enable Pi-hole DHCP: Settings → DHCP → tick DHCP server enabled. Set the range to match your subnet (e.g. 192.168.1.100192.168.1.250), set the gateway to your router IP (192.168.1.1), and save.

Because Pi-hole listens on UDP port 67 as DHCP, the process needs that port open and — on Linux — must be allowed to bind a privileged port. Pi-hole handles this with a CAP_NET_BIND_SERVICE capability on its DHCP helper binary. If you're running Pi-hole in a container or behind strict seccomp, verify that capability is present:

getcap /usr/bin/pihole-FTL

Expected output includes cap_net_bind_service+eip. Re-run the Pi-hole installer or repair command if it's missing:

pihole -r

Step 7 — Verify Everything Works

From any client on the network, confirm DNS is resolving through Pi-hole:

dig +short whoami.akamai.net @192.168.1.2

Substitute your Pi-hole IP. You should get your WAN IP back, confirming Pi-hole answered the query.

Test that a known ad domain is blocked:

dig +short doubleclick.net @192.168.1.2

Pi-hole returns 0.0.0.0 (or the configured block page IP) for blocked domains. If you get a real IP, the domain isn't in your lists — check the query log in the web interface for the exact result.

Watch live traffic in the dashboard or from the CLI:

pihole -t

Troubleshooting

Pi-hole service not running

sudo systemctl status pihole-FTL
sudo journalctl -u pihole-FTL -n 50

FTL (Faster Than Light) is the combined DNS/DHCP daemon. If it failed to start, the journal usually points to a port conflict — something else (commonly systemd-resolved) is already listening on port 53.

Port 53 conflict with systemd-resolved (Ubuntu/Debian)

Ubuntu enables systemd-resolved's stub listener on 127.0.0.53:53 by default. Disable the stub but keep name resolution working:

sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

Then start Pi-hole FTL again. On Fedora/RHEL, systemd-resolved is often not enabled by default, so this is less common.

Clients not using Pi-hole DNS

Many devices (Android 9+, some browsers) use DNS-over-HTTPS to a hardcoded provider, bypassing your local DNS entirely. You can block these at the router/firewall level or use Pi-hole's Local DNS features. Check Settings → DNS → Blocking mode and consider blocking outbound port 443 to known DoH providers if needed.

Legitimate domains getting blocked

Use the web interface's Query Log to identify the blocked domain, then add it to the Whitelist (Domains → Allow). The CLI equivalent:

pihole -w example.com
tested on:Ubuntu 24.04Debian 12Fedora 40Arch rolling

Frequently asked questions

Do I need a Raspberry Pi to run Pi-hole?
No. Despite the name, Pi-hole runs on any Linux system — a VM, a VPS, an old desktop, or a container. The Raspberry Pi is just a popular low-power host for it.
Will Pi-hole break any websites or services?
Aggressive blocklists occasionally catch legitimate domains. Check the Query Log when something stops working and whitelist the domain with 'pihole -w'. Most users need only a handful of whitelistings after initial setup.
How do I keep Pi-hole itself updated?
Run 'pihole -up' to update Pi-hole, FTL, and the web interface in one command. It's safe to automate this in a cron job or systemd timer.
Can I run Pi-hole in Docker instead of installing it directly?
Yes, the official pihole/pihole Docker image is well-maintained. The main gotcha is port 53 conflicts with systemd-resolved on the host, and DHCP requires host networking mode ('--network host') to work correctly.
What happens to my network if the Pi-hole server goes down?
DNS stops resolving for all clients, which effectively breaks internet access. Mitigate this with a secondary Pi-hole instance, a UPS on the server, or configuring your router as a DNS fallback with awareness that ads will temporarily appear.

Related guides