飞牛 OS + Docker + Pi-hole 家庭双栈 DNS 部署说明

作者: Chatgpt, Leo
文档用途: 部署记录、后续维护、重装及故障恢复\
部署平台: 飞牛 OS(NAS)\
DNS 服务: Pi-hole(Docker)\
网络模式: IPv4 + IPv6 双 Macvlan\
更新时间: 2026-11-01


1. 部署目标

在家庭网络中部署 Pi-hole,由它统一承担 DNS 解析和广告域名过滤。

主要目标:

  • 家庭设备统一使用 Pi-hole DNS。
  • 同时支持 IPv4 和 IPv6,避免设备通过 IPv6 DNS 绕过过滤。
  • 过滤抖音、快手、微信视频号等应用的部分广告及追踪域名。
  • 使用中文 DNS 过滤清单增强广告过滤效果。
  • 保留家庭网络正常上网能力,不改变现有路由器拨号和 DHCP 架构。

注意: Pi-hole 是 DNS 层过滤器,不能直接隐藏网页中的广告元素,也不能保证去除 X 信息流推广帖子。DoH、DoT、VPN 和应用内置 DNS 仍可能绕过 Pi-hole。

2. 家庭网络拓扑

运营商网络
    │
烽火光猫(桥接模式)
    │
    │ PPPoE
    ▼
TP-Link 路由器(负责拨号)
    │
    │ LAN:192.168.31.0/24
    │
    ├── Windows:192.168.31.41
    │
    ├── Pi-hole:192.168.31.53
    │             IPv6:240e:3a6:1e18:a160::1000
    │
    └── NAS:192.168.31.100

2.1 网络参数

项目配置
NAS 网卡enp1s0
NAS IPv4192.168.31.100
LAN 网段192.168.31.0/24
IPv4 网关192.168.31.1
Pi-hole IPv4192.168.31.53
当前 IPv6 前缀240e:3a6:1e18:a160::/64
Pi-hole IPv6240e:3a6:1e18:a160::1000
IPv6 网关240e:3a6:1e18:a160:9e47:82ff:fe88:2809
Docker IPv4 网络pihole_macvlan
Docker IPv6 网络pihole_ipv6

IPv6 前缀由运营商分配,可能随 PPPoE 重新拨号而变化。上述 IPv6 地址不能视为永久不变。

3. Docker 部署

3.1 目录结构

Compose 文件:

/vol1/1000/Docker/pihole/compose.yaml

数据目录:

/vol1/1000/Docker/pihole/etc-pihole

管理页面:

http://192.168.31.53/admin

容器名称:

pihole

3.2 Docker 版本

部署时环境:

组件版本
Docker28.5.2
Docker Composev2.40.3
Pi-hole 镜像pihole/pihole:latest

3.3 IPv4 Macvlan 网络

原有 IPv4 Docker 网络:

pihole_macvlan

配置为外部网络,Compose 不负责创建或管理它。

检查网络:

docker network inspect pihole_macvlan

应确认网络驱动为 macvlan,Parent interface 为 enp1s0,IPv4 地址池和网关与家庭 LAN 一致。

3.4 创建 IPv6 Macvlan 网络

执行:

docker network create \
  --driver macvlan \
  --ipv4=false \
  --ipv6 \
  --subnet=240e:3a6:1e18:a160::/64 \
  --gateway=240e:3a6:1e18:a160:9e47:82ff:fe88:2809 \
  --opt parent=enp1s0 \
  pihole_ipv6

说明:

  • --ipv4=false:该网络只负责 IPv6。
  • --ipv6:启用 IPv6。
  • --subnet:当前家庭 LAN 的 IPv6 前缀。
  • --gateway:TP-Link 路由器在该网段的 IPv6 地址。
  • --opt parent=enp1s0:使用 NAS 实际连接家庭 LAN 的物理网卡。

检查:

docker network inspect pihole_ipv6

重点确认:

EnableIPv4: false
EnableIPv6: true
Subnet: 240e:3a6:1e18:a160::/64
Gateway: 240e:3a6:1e18:a160:9e47:82ff:fe88:2809
Parent: enp1s0

注意:如果网络已经创建,不要重复执行创建命令。修改已有网络的网段或网关通常需要重新创建网络,可能影响容器连接。

3.5 Compose 配置文件

当前使用的 compose.yaml:

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    hostname: pihole

    networks:
      pihole_macvlan:
        ipv4_address: 192.168.31.53
      pihole_ipv6:
        ipv6_address: "240e:3a6:1e18:a160::1000"

    environment:
      TZ: Asia/Shanghai
      FTLCONF_webserver_api_password: "替换为自己的管理密码"
      FTLCONF_dns_upstreams: "223.5.5.5;119.29.29.119"

    volumes:
      - /vol1/1000/Docker/pihole/etc-pihole:/etc/pihole

    restart: unless-stopped

networks:
  pihole_macvlan:
    external: true
    name: pihole_macvlan

  pihole_ipv6:
    external: true
    name: pihole_ipv6

配置说明:

  • IPv4 和 IPv6 使用两个独立的 Macvlan 网络。
  • IPv4 固定地址为 192.168.31.53。
  • IPv6 固定地址为 240e:3a6:1e18:a160::1000。
  • Pi-hole 配置数据通过目录挂载保存。
  • FTLCONF_dns_upstreams 指定上游 DNS。
  • restart: unless-stopped 使容器在 Docker 服务重启后自动恢复。

注意:上面的 Compose 示例中上游 DNS 应使用已经实际验证的地址。当前部署原始配置为:

223.5.5.5
119.29.29.119

请以原配置为准,不要因为示例中的其他地址而擅自更改。

密码安全: 管理密码不要公开粘贴到日志或交流内容中。此前曾在排查过程中暴露过一次明文密码,建议更换为新的强密码。

3.6 Compose 配置检查

进入目录:

cd /vol1/1000/Docker/pihole

检查 YAML 配置:

docker compose config -q

没有输出且返回成功,表示 Compose 配置语法通过。

查看容器:

docker compose ps

查看容器网络:

docker inspect pihole \
  --format '{{json .NetworkSettings.Networks}}'

应同时看到:

  • pihole_macvlan:IPv4 192.168.31.53
  • pihole_ipv6:IPv6 240e:3a6:1e18:a160::1000

3.7 当前容器的 IPv6 接入记录

首次配置过程中,曾通过以下命令将正在运行的容器接入 IPv6 网络:

docker network connect \
  --ip6 240e:3a6:1e18:a160::1000 \
  pihole_ipv6 \
  pihole

这是本次部署过程中使用的临时接入操作。现在 Compose 文件已经声明了两个网络,后续应由 Compose 管理容器网络配置。

应用 Compose 时使用过:

docker compose up -d --no-recreate

随后检查:

docker inspect pihole \
  --format '{{.State.Status}} {{.State.Health.Status}}'

实际结果:

running healthy

重要: --no-recreate 不会重建现有容器,因此它只能证明当前容器没有因 Compose 操作而中断,不能证明删除并重建容器后 IPv6 网络一定会自动恢复。

当前双栈运行正常,重建后的持久性尚未实测。不要为了验证而随意执行 docker compose down 或 docker compose up -d --force-recreate,否则会造成 DNS 服务短暂中断。

4. TP-Link 路由器 DNS 配置

Pi-hole 不承担 DHCP 服务,继续由 TP-Link 路由器负责 DHCP。

4.1 DHCPv4

设置:

项目配置
DHCP 服务开启
首选 DNS192.168.31.53
备用 DNS留空

不要设置公共 DNS 作为备用 DNS,否则部分客户端可能直接使用备用 DNS,绕过 Pi-hole。

4.2 DHCPv6

设置:

项目配置
DHCPv6 服务开启
首选 DNS240e:3a6:1e18:a160::1000
备用 DNS留空
IPv6 地址池240e:3a6:1e18:a160:: 至 ...::ff
地址租期120 分钟

Option16、Option52 等其他选项没有为了本次部署而修改。

注意:不要仅凭 Option52 的显示值推断它就是 DNS 服务器地址。DHCPv6 的 DNS 服务器标准选项是 Option 23。

5. Windows 客户端验证

以 Windows 11 为例。

5.1 查看 DNS 配置

PowerShell:

Get-DnsClientServerAddress -InterfaceAlias "Ethernet"

预期:

IPv4: 192.168.31.53
IPv6: 240e:3a6:1e18:a160::1000

如果 IPv6 还出现其他 DNS 地址,应进一步确认来源,不要直接假定它一定能够绕过或一定不能绕过 Pi-hole。

5.2 测试正常域名解析

Resolve-DnsName www.baidu.com -Type A

预期返回正常的公网 IPv4 地址。

5.3 测试抖音拦截

Resolve-DnsName www.douyin.com -Type A

预期:

0.0.0.0

5.4 查看 Pi-hole Query Log

进入:

http://192.168.31.53/admin

查看 Query Log。

本次实际验证结果:

  • 百度域名请求到达 Pi-hole,并正常解析。
  • 请求来源包含 Windows 客户端的 IPv6 地址。
  • www.douyin.com 命中 regex 规则。
  • Pi-hole 返回 0.0.0.0。

这证明 Windows 的上述 DNS 测试确实经过 Pi-hole,而不是仅仅显示了 DNS 配置地址。

6. Pi-hole 广告过滤清单

6.1 基础清单

保留 Pi-hole 默认的 StevenBlack 清单。

6.2 添加中文 DNS 清单

建议使用适用于 DNS 层的规则文件,而不是浏览器专用规则。

① anti-AD

项目:privacy-protection-tools/anti-AD

Pi-hole 专用域名清单:

https://gcore.jsdelivr.net/gh/privacy-protection-tools/anti-AD@master/anti-ad-domains.txt

其他 CDN:

https://cdn.jsdelivr.net/gh/privacy-protection-tools/anti-AD@master/anti-ad-domains.txt

https://testingcf.jsdelivr.net/gh/privacy-protection-tools/anti-AD@master/anti-ad-domains.txt

https://fastly.jsdelivr.net/gh/privacy-protection-tools/anti-AD@master/anti-ad-domains.txt

项目主页:

https://github.com/privacy-protection-tools/anti-AD

② AdRules DNS

项目:Cats-Team/AdRules

DNS 规则:

https://gcore.jsdelivr.net/gh/Cats-Team/AdRules@main/dns.txt

其他 CDN:

https://cdn.jsdelivr.net/gh/Cats-Team/AdRules@main/dns.txt

https://testingcf.jsdelivr.net/gh/Cats-Team/AdRules@main/dns.txt

https://fastly.jsdelivr.net/gh/Cats-Team/AdRules@main/dns.txt

项目主页:

https://github.com/Cats-Team/AdRules

注意:

  • dns.txt 是 DNS 专用规则,不要误选 adblock.txt。
  • CDN 缓存可能导致更新略有延迟。
  • 订阅地址如果将来失效,应先检查项目主页的文件路径和分支。
  • 不要把多个 CDN 镜像地址同时添加为多个清单,否则相同规则会被重复下载。

6.3 添加清单的操作

在 Pi-hole 管理页面:

  1. 进入 Lists(或 Settings → Lists,具体取决于版本)。
  2. 添加订阅 URL。
  3. 保存清单。
  4. 进入 Gravity 更新页面:
http://192.168.31.53/admin/gravity
  1. 点击 Update 或 Update Gravity。
  2. 等待下载、解析及数据库更新完成。

重要:添加 URL 不等于下载清单。

Pi-hole 的流程是:

添加订阅地址
      │
      ▼
保存 URL
      │
      ▼
更新 Gravity
      │
      ▼
下载清单
      │
      ▼
解析域名、去重
      │
      ▼
生成实际生效的拦截数据库

也可以在 NAS 终端手动执行:

docker exec -it pihole pihole -g

查看容器日志:

docker logs --tail 100 pihole

如果清单下载失败,应检查 URL、CDN 可访问性和 Gravity 输出,不要反复添加相同地址。

7. 自定义广告过滤规则

对于抖音、快手等应用,可以在 Pi-hole 中增加自定义正则规则。

当前候选规则:

(^|\.)douyin\.com$
(^|\.)iesdouyin\.com$
(^|\.)douyinvod\.com$
(^|\.)douyincdn\.com$
(^|\.)kuaishou\.com$
(^|\.)gifshow\.com$
(^|\.)yximgs\.com$
(^|\.)ksapisrv\.com$

建议逐条验证,不要一次性封锁大量共享域名。

特别注意:

  • amemv.com:先观察 Query Log,再决定是否封锁。
  • 不要直接封锁 snssdk.com。
  • 不要直接封锁 pstatp.com。
  • 不要直接封锁 byteimg.com。
  • 不要直接封锁 bytedance.net。
  • 微信相关域名应通过实际请求日志判断,避免影响微信聊天、登录、支付和其他功能。

微信视频号的过滤需要先观察真实请求域名,再逐项测试,不能简单地把所有腾讯域名封锁。

8. 日常维护与故障检查

8.1 查看容器状态

docker compose ps

8.2 查看健康状态

docker inspect pihole \
  --format '{{.State.Status}} {{.State.Health.Status}}'

正常状态:

running healthy

8.3 查看容器日志

docker logs --tail 100 pihole

8.4 更新 Gravity

docker exec -it pihole pihole -g

8.5 检查网络连接

docker inspect pihole \
  --format '{{json .NetworkSettings.Networks}}'

重点检查两个网络及其 IP 地址。

8.6 备份

建议定期备份:

/vol1/1000/Docker/pihole/etc-pihole
/vol1/1000/Docker/pihole/compose.yaml

其中:

  • etc-pihole 保存 Pi-hole 的配置及相关数据。
  • compose.yaml 保存容器部署配置。
  • 备份时不要把管理密码明文发送到公开位置。

9. 已知限制与后续注意事项

9.1 IPv6 前缀变化

当前 IPv6 网络使用:

240e:3a6:1e18:a160::/64

如果运营商重新分配 IPv6 前缀,需要检查并同步更新:

  1. Docker IPv6 网络 subnet。
  2. Docker IPv6 gateway。
  3. Pi-hole IPv6 地址。
  4. TP-Link DHCPv6 下发的 DNS 地址。
  5. Windows 客户端获得的 IPv6 DNS 地址。

目前尚未实现自动检测和更新。建议后续单独设计前缀变化监测方案。

9.2 DNS 绕过

Pi-hole 只能控制经过它的 DNS 请求。

以下情况仍可能绕过:

  • 浏览器启用 DNS over HTTPS(DoH)。
  • 应用内置 DNS。
  • DNS over TLS(DoT)。
  • VPN 或代理软件自行处理 DNS。
  • 设备手动设置其他 DNS。

因此,当前部署能够实现家庭网络的常规 DNS 过滤,但不能保证所有应用、所有协议都无法绕过。

9.3 容器重建

目前已经完成:

  • Compose 双网络声明。
  • Compose 语法检查。
  • 现有容器双栈连接检查。
  • docker compose up -d --no-recreate。
  • 容器健康状态检查。

尚未完成:

  • 停止并重建容器后 IPv6 是否自动恢复的实际测试。

未来如需验证,应先准备维护窗口和备用 DNS 方案,避免家庭网络 DNS 服务中断。


10. 当前部署状态总结

项目状态
Pi-hole Docker 部署已完成
IPv4 Macvlan正常
IPv6 Macvlan正常
Compose 双网络声明已配置
Compose 语法检查通过
容器运行状态running
容器健康状态healthy
TP-Link DHCPv4 DNS已配置
TP-Link DHCPv6 DNS已配置
Windows IPv4 DNS 测试通过
Windows IPv6 DNS 测试通过
百度正常解析通过
抖音 DNS 拦截通过
中文清单已添加,需以 Gravity 更新结果确认下载情况
容器重建后的 IPv6 持久性尚未实测
IPv6 前缀变化自动处理尚未实现

当前结论: Pi-hole 已经在家庭网络中正常提供 IPv4 + IPv6 双栈 DNS 服务,Windows 客户端的正常解析和抖音拦截均已验证。后续重点是确认中文清单下载成功、观察误拦截情况,以及规划 IPv6 前缀变化的处理方案。

#!/bin/bash
# update hysteria
wget https://github.com/apernet/hysteria/releases/latest/download/hysteria-linux-amd64
chmod +x hysteria-linux-amd64
systemctl stop hysteria-server
mv hysteria-linux-amd64 /usr/local/bin/hysteria
systemctl start hysteria-server

hysteria version

# update naiveproxy server
wget https://github.com/klzgrad/forwardproxy/releases/latest/download/caddy-forwardproxy-naive.tar.xz
tar -vxf caddy-forwardproxy-naive.tar.xz
systemctl stop naive
mv caddy-forwardproxy-naive/caddy /usr/bin/caddy
systemctl start naive
rm -r caddy-forwardproxy-naive
rm caddy-forwardproxy-naive.tar.xz

caddy --version

备注:

  1. naiveproxy server是caddy forward server,跟客户端不是一码事
  2. AI虽然能解决不少事,但也经常出错。hysteria的最新版静态下载链接,Gemini给的是对的,但对naiveproxy server怎么都给不出。
  3. 更新naiveproxy client的脚本

    curl -s https://api.github.com/repos/klzgrad/naiveproxy/releases/latest | grep "browser_download_url" | grep "linux-x64.tar.xz" | cut -d '"' -f 4 | wget -qi -

最近在youtube上看经济学人的讲解,比如下面这个:
https://www.youtube.com/playlist?list=PLFOmDh7i7tWbblLXydFKQ6oGqTiNACDYN
youtube提供了podcast,打算批量下载下来,开车的时候听。
过程中有几个问题记录一下。

  1. 音频格式选择与下载
    yt-dlp本身提供了查看可选择音视频格式的选项:--list-formats或者-F,可以查看youtube提供的格式,用-f选择合适的格式下载即可。但是列表中的部分选集的格式不一样,批量下载的时候可能出现失败。

    最好使用-f 'bestaudio'选择下载最优音频格式,通常是webm格式;再用-x --audio-format mp3通过ffmpeg转换为常用的mp3格式。

  2. 导出并使用cookies
    一次下载的集数比较多是,可能出现限制下载的情况,需要通过使用浏览器cookies来进行认证。
    参考yt-dlp提供的说明即可。
    由于yt-dlp不支持我使用的thorium浏览器,需要使用Get cookies.txt LOCALLY插件导出后再使用,选项为--cookies PATH_TO_COOKIES.TXT
  3. 使用deno解决javascript challenges
    youtube为了限制下载,采用了javascript challenges,需要安装外部js运行时来解决,最简单的方案是使用deno。
    yt-dlp也提供了说明,按照说明:
    先安装deno运行时,我使用scoop install deno直接安装。
    再增加选项--js-runtimes "deno:PATH_TO_DENO.exe"。

    总的命令行如下:

    yt-dlp -f `bestaudio` -x --audio-format mp3 --cookies PATH_TO_COOKIES.TXT --js-runtimes "deno:PATH_TO_DENO.exe" YOUTUBE_URL
  4. 缩短文件名
    由于yt-dlp默认下载的文件名是视频标题,比较长。上传到NAS时会因为文件名过长而不给保存,需要通过删除末尾的重复文字来缩短文件名。
    我使用Total Commander的批量重命名功能,删除最后的“|TheEconomist”和后续的视频标识字符串。
    正则表达式为|TheEconomist.*,其中.*表示任意字符串。
    PixPin_2026-05-05_00-28-29.png

万象拼音是基于rime的拼音输入法,支持各种辅码。
在我常用的自然码拼音输入法基础上,更支持了自然码辅助码,效率提高了不少。

  1. 部署与定制化
    直接下载最新的自然码pro方案即可,定制化的内容也不多,只有更换输入法切换快捷键到F3、逗号/句号翻页两项。
    default.custom.yaml内容

    patch:
      "switcher/hotkeys":
     - F3
      "key_binder/bindings":
     - { when: paging, accept: comma, send: Page_Up }
     - { when: has_menu, accept: period, send: Page_Down }
  2. 自然码辅码
    键位图
    自然码辅助码键位图.jpg

    自然码辅助码在线查询工具

    自然码辅助码入门教程

  3. 参考资料
    https://zhuanlan.zhihu.com/p/1921900866975274411
    https://meta.appinn.net/t/topic/76426
    万象输入方案.png

Hysteria 是一个强大、快速、抗封锁的代理工具,对比naiveproxy在速度上有明显优势。

hysteria的服务端和客户端程序一样,最新版本为2.6.4, 下载地址:
Linux amd64版:https://github.com/apernet/hysteria/releases/download/app%2Fv2.6.4/hysteria-linux-amd64
Windows amd64版:https://github.com/apernet/hysteria/releases/download/app%2Fv2.6.4/hysteria-windows-amd64.exe

- 阅读剩余部分 -

飞牛fnOS上安装Transmission时忘记修改登录用户名和密码了。
最近想起来要更改,记录如下:

  1. 到应用中心里停用Transmission
  2. 登录ssh,切换到root,编辑配置文件

    # 切换到root
    sudo -i
    
    # 编辑Transmission的配置文件
    # `vol1`为应用安装的存储空间,根据实际情况对应修改
    # `rpc-username`为用户名
    # `rpc-password`为密码,不用管他加密,直接修改为明文密码即可;重新登录后会更新为加密文本。
    vim /vol1/@appdata/transmission/settings.json
  3. 到应用中心里启用Transmission,用新用户名和密码登录
  4. 参考
    https://blog.xqlee.com/article/544.html

  1. 生成新密钥,并上传公钥到服务器

    # 生成新密钥
    ssh-keygen -t rsa -m PEM -b 4096 -C "邮箱"
    # 提示可以输入密码,今后认证时服务器和本地用密钥认证,密码用来验证密钥
    
    # 上传公钥到服务器
    scp ~/.ssh/id_rsa.pub 用户名@服务器:~/.ssh/authorized_keys
  2. PowerShell中ssh连接

    ssh 用户名@服务器
    # 可见提示的密码认证是认证本地密钥

    PixPin_2025-08-31_21-42-22.png

  3. Putty中连接
    puttygen打开私钥,提示格式太老,菜单key \ 保存参数设置一下,另存为ppk格式的putty密钥。
    PixPin_2025-08-31_21-35-39.png
    putty中打开保存的会话,connection \ SSH \ Auth \ Credentials,打开之前保存的ppk密钥,重新保存会话。
    PixPin_2025-08-31_21-46-43.png
  4. 参考
    https://blog.csdn.net/black_cat7/article/details/139457572
    https://zhuanlan.zhihu.com/p/587082161
    https://www.dell.com/support/kbdoc/zh-cn/000217157/connectrix-b-series-how-to-use-putty-for-ssh-key-based-authentication
    https://blog.csdn.net/chenzhengfeng/article/details/125827015
    https://blog.csdn.net/knight_zhen/article/details/47001449

  1. socks5代理转http代理
    安装scoop需要代理翻墙,且只能走http代理,不支持socks5代理。
    naiveproxy只有新版本才能同时设置socks5代理,但新版本却不支持Windows 8.1, 只能通过privoxy来中转。
    privoxy配置文件config.txt中修改一句、新增一句配置

    listen-address  127.0.0.1:1090
    forward-socks5t   /               127.0.0.1:1080  .
  2. https问题
    安装scoop时出现错误Invoke-WebRequest : The request was aborted: Could not create SSL/TLS secure channel.

    如果客户端尝试使用TLS 1.0协商请求,但只支持TLS 1.1和1.2,则会出现此错误。
    在向您的服务发出请求之前,尝试通过将以下代码添加到客户端应用程序来强制客户端使用TLS1.2。
    Powershell

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
  3. Powershell版本过低
    下载并安装Windows管理框架5.1
    https://tips.pfrlju.com/tech/jacki/updating-powershell-version-on-windows.html

    这里看貌似Windows 7也是一样的操作
    https://www.cnblogs.com/heenhui2016/p/11037607.html