homelab-pihole-dns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Homelab Pi-hole DNS

家庭实验室Pi-hole DNS

Pi-hole is a network-wide DNS ad blocker that runs on a Raspberry Pi or any Linux host. Every device on your network gets ad and malware domain blocking automatically — no browser extension needed.
Pi-hole是一款运行在Raspberry Pi或任何Linux主机上的全网DNS广告拦截器。网络中的所有设备都会自动拦截广告和恶意软件域名——无需浏览器扩展。

When to Use

使用场景

  • Installing Pi-hole on a Raspberry Pi or Linux host
  • Configuring Pi-hole as the DNS server for a home network
  • Adding or managing blocklists
  • Setting up DNS-over-HTTPS (DoH) upstream resolvers
  • Creating local DNS records (e.g.
    nas.home.lan
    ,
    pi.home.lan
    )
  • Troubleshooting devices that lose internet access after Pi-hole is installed
  • Running Pi-hole alongside or instead of DHCP
  • 在Raspberry Pi或Linux主机上安装Pi-hole
  • 将Pi-hole配置为家庭网络的DNS服务器
  • 添加或管理拦截列表
  • 配置DNS-over-HTTPS (DoH)上游解析器
  • 创建本地DNS记录(例如
    nas.home.lan
    pi.home.lan
  • 排查安装Pi-hole后设备无法访问互联网的问题
  • 配合DHCP运行Pi-hole,或直接用Pi-hole替代DHCP

How Pi-hole Works

Pi-hole工作原理

Normal flow (without Pi-hole):
  Device → requests ads.tracker.com → ISP DNS → real IP → ads load

With Pi-hole:
  Device → requests ads.tracker.com → Pi-hole DNS → blocked (returns 0.0.0.0) → no ad

All DNS queries go through Pi-hole first.
Pi-hole checks against blocklists.
Blocked domains return a null response — the ad/tracker never loads.
Allowed domains get forwarded to your upstream resolver (Cloudflare, Google, etc.).
Normal flow (without Pi-hole):
  Device → requests ads.tracker.com → ISP DNS → real IP → ads load

With Pi-hole:
  Device → requests ads.tracker.com → Pi-hole DNS → blocked (returns 0.0.0.0) → no ad

All DNS queries go through Pi-hole first.
Pi-hole checks against blocklists.
Blocked domains return a null response — the ad/tracker never loads.
Allowed domains get forwarded to your upstream resolver (Cloudflare, Google, etc.).

Installation

安装方法

Docker (Recommended)

Docker安装(推荐)

Docker is the easiest way to install Pi-hole and makes updates and backups straightforward.
yaml
undefined
Docker是安装Pi-hole最简单的方式,能让更新和备份变得简单直接。
yaml
undefined

docker-compose.yml

docker-compose.yml

services: pihole: image: pihole/pihole:<pinned-release-tag> container_name: pihole ports: - "53:53/tcp" - "53:53/udp" - "80:80/tcp" # Web admin environment: TZ: "America/New_York" WEBPASSWORD: "${PIHOLE_WEBPASSWORD}" # set via .env file or secret PIHOLE_DNS_: "1.1.1.1;1.0.0.1" DNSMASQ_LISTENING: "all" volumes: - "./etc-pihole:/etc/pihole" - "./etc-dnsmasq.d:/etc/dnsmasq.d" restart: unless-stopped cap_add: - NET_ADMIN # only needed if Pi-hole will serve DHCP

Replace `<pinned-release-tag>` with a current Pi-hole release tag before deploying.
Avoid `latest` for long-lived DNS infrastructure so upgrades are deliberate and
reviewable.

Set `PIHOLE_WEBPASSWORD` in a `.env` file next to `docker-compose.yml`, chmod it to
`600`, and keep it out of git — do not put the password directly in the compose file.

Access web admin at: `http://<pi-ip>/admin`
services: pihole: image: pihole/pihole:<pinned-release-tag> container_name: pihole ports: - "53:53/tcp" - "53:53/udp" - "80:80/tcp" # Web admin environment: TZ: "America/New_York" WEBPASSWORD: "${PIHOLE_WEBPASSWORD}" # set via .env file or secret PIHOLE_DNS_: "1.1.1.1;1.0.0.1" DNSMASQ_LISTENING: "all" volumes: - "./etc-pihole:/etc/pihole" - "./etc-dnsmasq.d:/etc/dnsmasq.d" restart: unless-stopped cap_add: - NET_ADMIN # only needed if Pi-hole will serve DHCP

替换`<pinned-release-tag>`为当前的Pi-hole版本标签后再部署。对于长期运行的DNS基础设施,避免使用`latest`标签,这样升级可以是可控且可审查的。

在`docker-compose.yml`旁边的`.env`文件中设置`PIHOLE_WEBPASSWORD`,将其权限改为`600`,并且不要提交到git——不要将密码直接写在compose文件中。

访问Web管理界面:`http://<pi-ip>/admin`

Bare-Metal Install (Raspberry Pi OS / Debian / Ubuntu)

裸机安装(适用于Raspberry Pi OS / Debian / Ubuntu)

Pi-hole requires a static IP before installing.
bash
undefined
安装Pi-hole前需要先设置静态IP。
bash
undefined

Step 1: Assign a static IP (edit /etc/dhcpcd.conf on Pi OS)

Step 1: Assign a static IP (edit /etc/dhcpcd.conf on Pi OS)

sudo nano /etc/dhcpcd.conf
sudo nano /etc/dhcpcd.conf

Add at the bottom:

Add at the bottom:

interface eth0 static ip_address=192.168.3.2/24 static routers=192.168.3.1 static domain_name_servers=192.168.3.1
interface eth0 static ip_address=192.168.3.2/24 static routers=192.168.3.1 static domain_name_servers=192.168.3.1

Step 2: Download and inspect the installer before running it.

Step 2: Download and inspect the installer before running it.

Prefer the package or installer path documented by Pi-hole for your OS/version.

Prefer the package or installer path documented by Pi-hole for your OS/version.

curl -sSL https://install.pi-hole.net -o pi-hole-install.sh less pi-hole-install.sh # review before proceeding
curl -sSL https://install.pi-hole.net -o pi-hole-install.sh less pi-hole-install.sh # review before proceeding

Step 3: Run

Step 3: Run

bash pi-hole-install.sh
bash pi-hole-install.sh

Follow the interactive installer:

Follow the interactive installer:

1. Select network interface (eth0 for wired — recommended)

1. Select network interface (eth0 for wired — recommended)

2. Select upstream DNS (Cloudflare or leave default — can change later)

2. Select upstream DNS (Cloudflare or leave default — can change later)

3. Confirm static IP

3. Confirm static IP

4. Install the web admin interface (recommended)

4. Install the web admin interface (recommended)

5. Note the admin password shown at the end

5. Note the admin password shown at the end

undefined
undefined

Pointing Your Network at Pi-hole

将网络指向Pi-hole

undefined
undefined

Method 1: Change DNS in your router DHCP settings (recommended)

Method 1: Change DNS in your router DHCP settings (recommended)

Router admin UI → DHCP Settings → DNS Server Primary DNS: 192.168.3.2 (Pi-hole IP) Secondary DNS: leave blank for strict blocking, or use a second Pi-hole. A public fallback such as 1.1.1.1 improves availability during rollout but can bypass blocking because clients may query it.
All devices get Pi-hole as DNS automatically on next DHCP renewal. Force renewal: reconnect Wi-Fi or run 'sudo dhclient -r && sudo dhclient' on Linux
Router admin UI → DHCP Settings → DNS Server Primary DNS: 192.168.3.2 (Pi-hole IP) Secondary DNS: leave blank for strict blocking, or use a second Pi-hole. A public fallback such as 1.1.1.1 improves availability during rollout but can bypass blocking because clients may query it.
All devices get Pi-hole as DNS automatically on next DHCP renewal. Force renewal: reconnect Wi-Fi or run 'sudo dhclient -r && sudo dhclient' on Linux

Method 2: Per-device DNS (useful for testing before network-wide rollout)

Method 2: Per-device DNS (useful for testing before network-wide rollout)

Windows: Control Panel → Network Adapter → IPv4 Properties → set DNS manually macOS: System Settings → Network → Details → DNS → set manually Linux: /etc/resolv.conf or NetworkManager
Windows: Control Panel → Network Adapter → IPv4 Properties → set DNS manually macOS: System Settings → Network → Details → DNS → set manually Linux: /etc/resolv.conf or NetworkManager

Method 3: Pi-hole as DHCP server (replaces router DHCP)

Method 3: Pi-hole as DHCP server (replaces router DHCP)

Pi-hole admin → Settings → DHCP → Enable Disable DHCP on your router first — two DHCP servers on the same network cause conflicts Advantage: hostname resolution works automatically (devices register their names)
undefined
Pi-hole admin → Settings → DHCP → Enable Disable DHCP on your router first — two DHCP servers on the same network cause conflicts Advantage: hostname resolution works automatically (devices register their names)
undefined

Blocklist Management

拦截列表管理

undefined
undefined

Pi-hole admin → Adlists → Add new adlist

Pi-hole admin → Adlists → Add new adlist

Recommended blocklists:

Recommended blocklists:

After adding a list:

After adding a list:

Tools → Update Gravity (downloads and compiles all blocklists)
Tools → Update Gravity (downloads and compiles all blocklists)

If a site is blocked that should not be (false positive):

If a site is blocked that should not be (false positive):

Pi-hole admin → Whitelist → Add domain Example: api.my-legitimate-service.com
Pi-hole admin → Whitelist → Add domain Example: api.my-legitimate-service.com

Check what is being blocked in real time:

Check what is being blocked in real time:

Dashboard → Query Log (live DNS query stream with block/allow status)
undefined
Dashboard → Query Log (live DNS query stream with block/allow status)
undefined

DNS-over-HTTPS Upstream

DNS-over-HTTPS上游配置

DNS-over-HTTPS encrypts your DNS queries so your ISP cannot see what sites you resolve.
bash
undefined
DNS-over-HTTPS会加密你的DNS查询,这样你的ISP就无法看到你正在解析哪些网站。
bash
undefined

Install cloudflared (Cloudflare's DoH proxy).

Install cloudflared (Cloudflare's DoH proxy).

Prefer Cloudflare's package repository for automatic signed package verification.

Prefer Cloudflare's package repository for automatic signed package verification.

If you download a binary directly, pin a release version and verify its checksum.

If you download a binary directly, pin a release version and verify its checksum.

Verify the checksum/signature from Cloudflare's release notes before installing.

Verify the checksum/signature from Cloudflare's release notes before installing.

sudo mv cloudflared-linux-arm64 /usr/local/bin/cloudflared sudo chmod +x /usr/local/bin/cloudflared
sudo mv cloudflared-linux-arm64 /usr/local/bin/cloudflared sudo chmod +x /usr/local/bin/cloudflared

Create cloudflared config

Create cloudflared config

sudo mkdir -p /etc/cloudflared sudo tee /etc/cloudflared/config.yml << EOF proxy-dns: true proxy-dns-port: 5053 proxy-dns-upstream:
sudo mkdir -p /etc/cloudflared sudo tee /etc/cloudflared/config.yml << EOF proxy-dns: true proxy-dns-port: 5053 proxy-dns-upstream:

Create systemd service

Create systemd service

sudo cloudflared service install sudo systemctl start cloudflared sudo systemctl enable cloudflared
sudo cloudflared service install sudo systemctl start cloudflared sudo systemctl enable cloudflared

Now point Pi-hole at the local DoH proxy:

Now point Pi-hole at the local DoH proxy:

Pi-hole admin → Settings → DNS → Custom upstream DNS

Pi-hole admin → Settings → DNS → Custom upstream DNS

Set to: 127.0.0.1#5053

Set to: 127.0.0.1#5053

Uncheck all other upstream resolvers

Uncheck all other upstream resolvers

undefined
undefined

Local DNS Records

本地DNS记录

Make your services reachable by name (e.g.
nas.home.lan
,
grafana.home.lan
).
Domain name note:
.home.lan
is widely used in homelabs and works in practice. The IETF-reserved suffix for local use is
.home.arpa
(RFC 8375) — use that to follow the standard. Avoid
.local
for Pi-hole DNS records as it conflicts with mDNS/Bonjour.
undefined
让你的服务可以通过名称访问(例如
nas.home.lan
grafana.home.lan
)。
域名说明:
.home.lan
在家庭实验室中被广泛使用,实际效果良好。IETF保留用于本地使用的后缀是
.home.arpa
(RFC 8375)——遵循标准的话可以使用该后缀。避免在Pi-hole DNS记录中使用
.local
,因为它会与mDNS/Bonjour冲突。
undefined

Pi-hole admin → Local DNS → DNS Records

Pi-hole admin → Local DNS → DNS Records

Domain IP nas.home.lan 192.168.30.10 pi.home.lan 192.168.30.2 grafana.home.lan 192.168.30.3 proxmox.home.lan 192.168.30.4
Domain IP nas.home.lan 192.168.30.10 pi.home.lan 192.168.30.2 grafana.home.lan 192.168.30.3 proxmox.home.lan 192.168.30.4

From any device on your network:

From any device on your network:

ping nas.home.lan → 192.168.30.10 http://grafana.home.lan → your Grafana dashboard
ping nas.home.lan → 192.168.30.10 http://grafana.home.lan → your Grafana dashboard

For subdomains, add a CNAME:

For subdomains, add a CNAME:

Pi-hole admin → Local DNS → CNAME Records Domain: portainer.home.lan → Target: pi.home.lan
undefined
Pi-hole admin → Local DNS → CNAME Records Domain: portainer.home.lan → Target: pi.home.lan
undefined

Troubleshooting

故障排查

bash
undefined
bash
undefined

Pi-hole blocking something it should not

Pi-hole blocking something it should not

pihole -q example.com # Check if domain is blocked and which list pihole -w example.com # Whitelist immediately
pihole -q example.com # Check if domain is blocked and which list pihole -w example.com # Whitelist immediately

DNS not resolving at all

DNS not resolving at all

pihole status # Check if pihole-FTL is running dig @192.168.3.2 google.com # Test DNS directly against Pi-hole
pihole status # Check if pihole-FTL is running dig @192.168.3.2 google.com # Test DNS directly against Pi-hole

Restart Pi-hole DNS

Restart Pi-hole DNS

pihole restartdns
pihole restartdns

Check query logs for a specific device

Check query logs for a specific device

pihole -t # Live tail of all queries
pihole -t # Live tail of all queries

Or filter by client in the web admin Query Log

Or filter by client in the web admin Query Log

Pi-hole gravity update (refresh blocklists)

Pi-hole gravity update (refresh blocklists)

pihole -g
undefined
pihole -g
undefined

Anti-Patterns

反模式

undefined
undefined

BAD: Depending on one Pi-hole without a recovery path

BAD: Depending on one Pi-hole without a recovery path

If Pi-hole crashes or the Pi loses power, DNS can stop working

If Pi-hole crashes or the Pi loses power, DNS can stop working

GOOD: Keep a documented router fallback for rollback during setup

GOOD: Keep a documented router fallback for rollback during setup

BETTER: Run two Pi-hole instances for redundancy; avoid public fallback DNS for strict blocking

BETTER: Run two Pi-hole instances for redundancy; avoid public fallback DNS for strict blocking

BAD: Installing Pi-hole without a static IP

BAD: Installing Pi-hole without a static IP

If the Pi gets a new DHCP IP, all devices lose DNS

If the Pi gets a new DHCP IP, all devices lose DNS

GOOD: Set static IP first, then install Pi-hole

GOOD: Set static IP first, then install Pi-hole

BAD: Enabling Pi-hole DHCP without disabling the router's DHCP first

BAD: Enabling Pi-hole DHCP without disabling the router's DHCP first

Two DHCP servers on the same network hand out conflicting IPs

Two DHCP servers on the same network hand out conflicting IPs

GOOD: Disable router DHCP, then enable Pi-hole DHCP

GOOD: Disable router DHCP, then enable Pi-hole DHCP

BAD: Never updating gravity (blocklists)

BAD: Never updating gravity (blocklists)

New ad and malware domains accumulate — stale lists miss them

New ad and malware domains accumulate — stale lists miss them

GOOD: Schedule weekly gravity update: pihole -g (or enable in Settings → API)

GOOD: Schedule weekly gravity update: pihole -g (or enable in Settings → API)

undefined
undefined

Best Practices

最佳实践

  • Give the Pi a static IP or DHCP reservation before installing Pi-hole
  • Use Pi-hole as primary DNS; for redundancy, add a second Pi-hole instead of a public resolver if you need strict blocking
  • Enable DoH (DNS-over-HTTPS) with cloudflared for encrypted upstream queries
  • Set
    home.lan
    as your local domain and create DNS records for all your services
  • Review the Query Log occasionally — blocked queries show you what devices are doing
  • 在安装Pi-hole前,给树莓派设置静态IP或DHCP保留地址
  • 将Pi-hole作为主DNS;如果需要严格拦截且冗余,添加第二个Pi-hole实例,而不是使用公共解析器
  • 搭配cloudflared启用DoH(DNS-over-HTTPS),实现加密的上游查询
  • home.lan
    设为本地域名,并为所有服务创建DNS记录
  • 定期查看查询日志——被拦截的查询能让你了解设备的活动情况

Related Skills

相关技能

  • homelab-network-setup
  • homelab-vlan-segmentation
  • homelab-wireguard-vpn
  • homelab-network-setup
  • homelab-vlan-segmentation
  • homelab-wireguard-vpn