Install Pi-hole on TrueNAS Scale

Network-wide ad blocker — blocks ads, trackers, and malware for every device on your network, no browser extensions needed.

Cover for Install Pi-hole on TrueNAS Scale

Pi-hole is the network-wide ad blocker that runs on your TrueNAS box and blocks ads, trackers, and malware domains for every device on your network — no browser extensions, no per-device configuration.

What it is

Platform TrueNAS Scale (Docker custom app)
Ports 53 (DNS), 80 (web UI), 443 (HTTPS)
Image ghcr.io/pi-hole/pihole:latest
Config path /mnt/apps/pihole/config → /etc/pihole
Web path /mnt/apps/pihole/dnsmasq → /etc/dnsmasq.d
License MIT

Pi-hole sits between your devices and the internet, filtering DNS requests through blocklists. When a device asks for an ad domain (like ads.doubleclick.net), Pi-hole responds with 0.0.0.0 — the request is silently dropped. The device never loads the ad.

It works at the network level: every device that uses your Pi-hole as its DNS server gets ad blocking automatically. Phones, smart TVs, gaming consoles, IoT devices — all covered without installing anything on them individually.

The hard part: port 53 and DNS conflicts

The install is five minutes. The hard part is that port 53 (DNS) is often already in use on TrueNAS Scale by systemd-resolved. If you try to start Pi-hole and get a "port already in use" error, this is why.

PACKET ANALYSIS
Port 53 conflict
systemd-resolved is listening on 127.0.0.53
53
Pi-hole tries to bind to 0.0.0.0
53
→ Error
address already in use
Fix
stop systemd-resolved and disable it
Or
use a different port (5353) and configure your router to forward DNS to 5353

The cleanest approach: disable systemd-resolved before deploying Pi-hole. This frees port 53 for Pi-hole to use exclusively.

PACKET ANALYSIS
DNS resolution chain without Pi-hole
DNS resolution chain with Pi-hole
Device → Router (DNS) → Pi-hole (192.168.1.x
53) → Upstream DNS (1.1.1.1) → Internet

How to install it

Step 1: Stop systemd-resolved

sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
sudo rm /etc/resolv.conf
echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf

This prevents port 53 conflicts. Pi-hole needs port 53 to serve DNS to your network.

Step 2: Create directories

mkdir -p /mnt/apps/pihole/config
mkdir -p /mnt/apps/pihole/dnsmasq

Step 3: Generate a password

# Generate a random password for the web UI:
openssl rand -base64 12

Save this password — it is the admin password for the Pi-hole web interface.

Step 4: Deploy the Docker Compose

TrueNAS Scale → Apps → Discover Apps → Custom App (Docker Compose):

services:
  pihole:
    image: ghcr.io/pi-hole/pihole:latest
    container_name: pihole
    restart: unless-stopped
    environment:
      - TZ=Europe/London
      - WEBPASSWORD=your_generated_password_here
      - DNSMASQ_LISTENING=all
      - PIHOLE_DNS_=1.1.1.1;1.0.0.1
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    volumes:
      - /mnt/apps/pihole/config:/etc/pihole
      - /mnt/apps/pihole/dnsmasq:/etc/dnsmasq.d
    cap_add:
      - NET_ADMIN

After deploy:

# Check Pi-hole is running:
docker logs pihole 2>&1 | tail -5

# Verify DNS is working:
dig @127.0.0.1 google.com

Log in at http://<nas-ip>/admin with username admin and the password you generated.

Step 5: Point your router to Pi-hole

  1. Open your router's admin page (usually 192.168.1.1)
  2. Go to DNS Settings or WAN Settings
  3. Set the Primary DNS to your TrueNAS IP (192.168.1.x)
  4. Set the Secondary DNS to 1.1.1.1 (Cloudflare as fallback)
  5. Save and restart your router

All devices on your network now use Pi-hole for DNS automatically.

Configuration that matters

Upstream DNS servers

Provider Primary Secondary Protocol
Cloudflare 1.1.1.1 1.0.0.1 DNS-over-TLS
Google 8.8.8.8 8.8.4.4 Standard DNS
Quad9 9.9.9.9 149.112.112.112 DNS-over-TLS
OpenDNS 208.67.222.222 208.67.220.220 Standard DNS

Configure in Pi-hole → Settings → DNS. Cloudflare and Quad9 support DNS-over-TLS for encrypted queries.

Blocklists

List URL What it blocks
Steven Black's https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts Ads, malware, phishing
OAD https://big.oisd.nl Ads, tracking, telemetry
1Hosts (Lite) https://cdn.jsdelivr.net/gh/badmojr/1Hosts@master/Lite/hosts.txt Balanced blocking
Peter Lowe's https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts Ads and tracking

Add lists in Pi-hole → Adlists → paste URL → Save → Run pihole -g to update.

DHCP (optional)

Setting Recommended value Why
DHCP server Off (use your router) Simpler setup, less to break
DHCP on Pi-hole On only if you disable router DHCP Pi-hole can serve DHCP instead
Lease time 24 hours Default is fine for most networks

If you enable DHCP on Pi-hole, disable it on your router first. Two DHCP servers on the same network cause IP conflicts.

Whitelist and blacklist

Action When to use
Whitelist domain A legitimate site is broken by Pi-hole (e.g., analytics.example.com)
Blacklist domain An ad domain slips through the blocklist
Disable blocking Temporarily, for debugging DNS issues

Access via Pi-hole → Whitelist / Blacklist in the web UI, or via CLI:

# Whitelist a domain:
docker exec pihole pihole -w example.com

# Blacklist a domain:
docker exec pihole pihole -b ads.example.com

# Temporarily disable blocking:
docker exec pihole pihole -n off

# Re-enable blocking:
docker exec pihole pihole -n on

What I'd tell anyone building this

  • Disable systemd-resolved before deploying Pi-hole. If port 53 is already in use, Pi-hole will not start. The fix is to stop and disable systemd-resolved, then point /etc/resolv.conf to a public DNS like 1.1.1.1.

  • The password is set at deploy time via WEBPASSWORD. If you forget it, check the container logs or reset it with docker exec pihole pihole -a -p.

  • Do not run Pi-hole on a Raspberry Pi if you have a NAS. Pi-hole uses almost no CPU or RAM. Running it on TrueNAS means one less device to maintain, and it stays up as long as your NAS is up.

  • Pi-hole does not replace a firewall. It blocks DNS requests to ad domains, but it does not block traffic at the IP level. For that, you need pfSense, OPNsense, or firewall rules on your router.

  • The blocklist update is manual. Run docker exec pihole pihole -g periodically, or set up a cron job to run it weekly. Pi-hole does not auto-update blocklists.

  • Whitelist carefully. If a website or app breaks, temporarily disable Pi-hole to confirm it is the cause, then whitelist only the specific domain causing the issue. Whitelisting too broadly defeats the purpose.

Get it

Links:

Quick install (Docker Compose):

services:
  pihole:
    image: ghcr.io/pi-hole/pihole:latest
    container_name: pihole
    restart: unless-stopped
    environment:
      - TZ=Europe/London
      - WEBPASSWORD=your_generated_password_here
      - DNSMASQ_LISTENING=all
      - PIHOLE_DNS_=1.1.1.1;1.0.0.1
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    volumes:
      - /mnt/apps/pihole/config:/etc/pihole
      - /mnt/apps/pihole/dnsmasq:/etc/dnsmasq.d
    cap_add:
      - NET_ADMIN

After deploy:

# Verify DNS is working:
dig @<nas-ip> google.com

# Update blocklists:
docker exec pihole pihole -g

# Check stats:
docker exec pihole pihole status

Log in at http://<nas-ip>/admin, add blocklists, and point your router's DNS to the NAS IP.

Comments (0)

Join the discussion — sign in to comment.

Sign in

No comments yet — be the first to share your thoughts.

Related reading