homelab-pihole-dns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHomelab 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
undefinedDocker是安装Pi-hole最简单的方式,能让更新和备份变得简单直接。
yaml
undefineddocker-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
undefinedStep 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
undefinedundefinedPointing Your Network at Pi-hole
将网络指向Pi-hole
undefinedundefinedMethod 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)
undefinedPi-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)
undefinedBlocklist Management
拦截列表管理
undefinedundefinedPi-hole admin → Adlists → Add new adlist
Pi-hole admin → Adlists → Add new adlist
Recommended blocklists:
Recommended blocklists:
default — 200k+ domains
malware domains
tracking/telemetry
default — 200k+ domains
malware domains
tracking/telemetry
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)
undefinedDashboard → Query Log (live DNS query stream with block/allow status)
undefinedDNS-over-HTTPS Upstream
DNS-over-HTTPS上游配置
DNS-over-HTTPS encrypts your DNS queries so your ISP cannot see what sites you resolve.
bash
undefinedDNS-over-HTTPS会加密你的DNS查询,这样你的ISP就无法看到你正在解析哪些网站。
bash
undefinedInstall 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.
CLOUDFLARED_VERSION="<pinned-version>"
curl -LO "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64"
CLOUDFLARED_VERSION="<pinned-version>"
curl -LO "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64"
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
undefinedundefinedLocal DNS Records
本地DNS记录
Make your services reachable by name (e.g. , ).
nas.home.langrafana.home.lanDomain name note:is widely used in homelabs and works in practice. The IETF-reserved suffix for local use is.home.lan(RFC 8375) — use that to follow the standard. Avoid.home.arpafor Pi-hole DNS records as it conflicts with mDNS/Bonjour..local
undefined让你的服务可以通过名称访问(例如、)。
nas.home.langrafana.home.lan域名说明:在家庭实验室中被广泛使用,实际效果良好。IETF保留用于本地使用的后缀是.home.lan(RFC 8375)——遵循标准的话可以使用该后缀。避免在Pi-hole DNS记录中使用.home.arpa,因为它会与mDNS/Bonjour冲突。.local
undefinedPi-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
undefinedPi-hole admin → Local DNS → CNAME Records
Domain: portainer.home.lan → Target: pi.home.lan
undefinedTroubleshooting
故障排查
bash
undefinedbash
undefinedPi-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
undefinedpihole -g
undefinedAnti-Patterns
反模式
undefinedundefinedBAD: 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)
undefinedundefinedBest 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 as your local domain and create DNS records for all your services
home.lan - 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),实现加密的上游查询
- 将设为本地域名,并为所有服务创建DNS记录
home.lan - 定期查看查询日志——被拦截的查询能让你了解设备的活动情况
Related Skills
相关技能
- homelab-network-setup
- homelab-vlan-segmentation
- homelab-wireguard-vpn
- homelab-network-setup
- homelab-vlan-segmentation
- homelab-wireguard-vpn