
1. ponytail 到底是干什么的一个为 HTTP/3 世界准备的 DNS“垫片”先说结论ponytail 是一个用 Rust 写的 DNS 服务器/代理它的核心定位不是“又一个 DNS 转发器”而是专门给 HTTP/3 环境做桥接的 DNS shim垫片。如果你手头有一个不支持 DoHDNS over HTTPS的旧应用又想让它的 DNS 查询走 DoH 上游那 ponytail 就是干这个的。1.1 它的定位DNS server shim而不是普通 DNS 转发器普通 DNS 转发器做的事情很简单收到客户端的 DNS 查询转发到上游 DNS 服务器通常是 UDP 53 端口拿到结果再返回。这类工具有很多比如dnsmasq、unbound甚至systemd-resolved都算。ponytail 不一样。它监听在127.0.0.1:53收到的是传统 UDP DNS 查询但发出的却是 HTTPS 请求——它把 DNS 查询转换成 DoH 格式发给支持 DoH 的上游服务器再把响应转换回传统 DNS 格式返回给客户端。这个过程用项目 README 里的话说是A DNS server that listens on127.0.0.1:53, uses an upstream DoH server, and can take upstream from a hardcoded bootstrap fallback.换句话说它站在传统 DNS 和 DoH 之间把两边“翻译”给对方。这个位置很微妙它不是让你手动配置浏览器的 DoH而是让你系统里所有走传统 DNS 的应用不知不觉地获得 DoH 的加密传输能力。1.2 为什么 HTTP/3 世界需要这样一层代理我最初接触 ponytail是因为在实验室里搭了一套 HTTP/3 代理环境。HTTP/3 基于 QUIC走 UDP 443它对 DNS 解析有一个很实际的需求你希望域名解析本身也走加密通道避免 DNS 被污染或劫持。问题是很多应用根本不支持 DoH。拿 Chromium 系浏览器来说虽然有 DoH 选项但默认可能关闭更不用说那些命令行工具、脚本、老旧的网络库它们只会调用系统解析器也就是读/etc/resolv.conf然后往127.0.0.1:53或路由器 DNS 发 UDP 包。这时候你面前就有一个“缝隙”系统解析器只会说传统 DNS而你想让解析走 DoH。ponytail 就是专门填这个缝隙的。它继承了你系统里所有应用的 DNS 请求自己扮演一个“本地 DNS 服务器”然后把真正的解析工作交给 DoH 上游。用作者的话说这个项目填补的是dnscrypt-proxy和 DoH 之间的 niche——一个不原生支持 DoH、但使用传统 system-resolver 方式的场景。1.3 直接给结论这个工具到底适不适合你在往下读之前我先把话说清楚免得你浪费时间。适合用 ponytail 的场景你在实验室或开发环境需要快速把传统 DNS 请求转成 DoH不想重新编译或重写应用。你想体验“test-before-run”的 DNS 启动逻辑感受一下 probe 机制。你对 Rust 写的 DNS 工具感兴趣想读读源码或者折腾配置。不适合的场景生产环境、大规模部署或者对稳定性要求极高——项目 README 自己都说了“It probably lacks polish and will probably fall apart if you poke it.”它可能不够精致你戳一戳它可能就散了。你需要高性能 DNS 缓存——ponytail 的 TTL 处理很“诚实”大多数记录不缓存性能瓶颈很明显。你想要一个 GUI 或者完善的文档——它只有一个 TOML 配置文件和几条日志。说白了ponytail 是一个“小而锐利”的工具适合玩适合学习适合在某些特定场景下当胶水。真要在生产环境跑我会选 dnsproxy 或 sing-box 的 DNS 模块。后面我会详细对比。2. 上手 ponytail从编译到第一个查询别看这个工具冷门上手其实很快。不需要复杂的依赖只要有 Rust 工具链或者直接下载预编译二进制。2.1 获取二进制或从源码构建从源码构建是最直接的方式。克隆仓库之后在项目根目录执行cargo build --release构建完成后二进制在target/release/ponytail。如果你不想自己编译也可以去项目的 GitHub Releases 页面下载对应平台的预编译包。不过说实话这种小众工具我更推荐源码构建因为你能顺便看一眼它的代码结构了解它到底怎么实现 DoH 转换的。构建过程中要注意Rust 工具链版本不能太旧。我一开始用系统自带的旧版本 Rust编译直接报错升级到最新 stable 之后才顺利通过。这个小坑README 里可没写。2.2 最小的 TOML 配置ponytail 的配置文件是 TOML 格式。最小配置只需要指定绑定地址、上游 DoH 服务器、bootstrap 地址和 probe 地址bind 127.0.0.1:53 upstream https://cloudflare-dns.com/dns-query bootstrap https://162.159.36.1/dns-query probe https://cloudflare-dns.com/dns-query [fallback] upstream https://dns.google/dns-query bootstrap https://8.8.8.8/dns-query probe https://dns.google/dns-query log info这里有几个关键点我拿到配置时第一反应也是懵的bind监听地址。默认127.0.0.1:53意味着只有本机能用。如果你想给局域网提供 DNS 服务可以改成0.0.0.0:53但要注意安全。upstream主要的 DoH 上游服务器。bootstrapbootstrap 地址。这是用来“引导”的——因为 DoH 服务器本身也是一个域名要解析这个域名又不能再用 DoH会死循环所以干脆直接用 IP 地址。Cloudflare 的 DoH 服务 IP 是162.159.36.1Google 的是8.8.8.8。probe启动时探测用的 DoH 服务器。[fallback]主上游不可用时的备用上游。启动方式很简单ponytail -c demo/ponytail-demo.toml我没试过不指定配置文件直接跑但看代码逻辑默认应该会找当前目录下的某个默认配置找不到就报错。所以老老实实-c指定配置文件最稳妥。2.3 用 dig、kdig 或 dog 验证本地 DNS 服务启动之后验证方式很直观。用dig指向本地 53 端口查一个域的 A 记录dig 127.0.0.1 example.com A如果一切正常你会看到一条标准的 DNS 响应status: NOERRORanswer 里有解析结果。这时候你可能会有疑惑这跟直接用系统 DNS 有什么区别区别在日志和抓包里——ponytail 并没有把查询转发到 UDP 53 上游而是发起了 HTTPS 请求到 Cloudflare 的 DoH 端点。想看得更清楚可以用dog或kdig这种支持更多输出格式的工具。比如dogdog 127.0.0.1 example.com A --color它会以更易读的方式展示 TTL、记录类型和解析结果。不过这些工具只是验证手段真正有意思的是看 ponytail 的日志和抓包。2.4 验证“先测后跑”机制的日志我第一次跑 ponytail 时注意到一个很有意思的细节它启动后不会立刻开始响应 DNS 查询而是先做一次“探测”。$ ponytail -c demo/ponytail-demo.toml 2024-xx-xxTxx:xx:xxZ INFO ponytail::dns: listening on 127.0.0.1:53 2024-xx-xxTxx:xx:xxZ INFO ponytail::probe: probing DoH server 2024-xx-xxTxx:xx:xxZ INFO ponytail::probe: probe succeeded, starting DNS server 2024-xx-xxTxx:xx:xxZ INFO ponytail::dns: no queries yet, waiting...看到probe succeeded之后它才真正开始处理 DNS 查询。如果探测失败日志会是另一番景象2024-xx-xxTxx:xx:xxZ WARN ponytail::probe: probe failed, keeping listener open but refusing to answer注意这个行为探测失败时监听端口还开着但拒绝应答。这设计其实很聪明——进程不退出端口不关闭方便你重试或排查问题但同时它不会给出“虚假”的 DNS 响应避免污染客户端缓存。我当时就好奇这个 probe 到底探测的是什么看代码发现它向probe指定的 DoH 服务器发一个真实的 DNS 查询通常是查example.com或类似域名如果能收到有效响应就认为网络通畅、DoH 服务可用。这就是所谓的 test-before-run。3. 核心机制拆解bootstrap、probe、fallback 是怎么协同工作的这一节是全文最核心的部分。ponytail 的配置看起来简单但其实每个字段背后都有一套逻辑在支撑。搞清楚这些机制你才算真正理解这个工具。3.1 bootstrap 的作用与硬编码服务器先来说 bootstrap。DoH 协议的一个经典悖论是你要用 HTTPS 加密查询 DNS就得先解析 DoH 服务器的域名可解析域名本身又需要 DNS。怎么破解这个循环答案就是 bootstrap——直接用 IP 地址访问 DoH 服务器跳过域名解析这一步。在 ponytail 的配置里bootstrap字段填的就是 DoH 服务器的 IP 地址加路径比如https://162.159.36.1/dns-query。这个 IP 是 Cloudflare 的 DoH 服务 IP你不需要解析cloudflare-dns.com就能直接发起 HTTPS 请求。除了配置文件里写的 bootstrapponytail 内部还有一个硬编码的默认 DoH 服务器作为最终兜底。哪怕你没有在配置里指定 bootstrap它也能尝试用自己的硬编码服务器完成引导解析。这个设计很务实也符合“少配置、开箱即用”的思路。但这里有个实际体验要提醒你bootstrap 用 IP 访问 DoH 服务器时HTTPS 证书校验怎么做这其实是 DoH bootstrap 的经典问题。ponytail 的做法是直接用 IP 发起 HTTPS 请求证书校验按标准流程走。也就是说如果 DoH 服务器的证书只签了域名没签 IP这个请求可能会失败。好在 Cloudflare 和 Google 都做了 IP 证书支持所以我实测时没有遇到问题但如果你用的是自建的 DoH 服务器bootstrap 这一步很可能就是第一个坑。3.2 test-before-run 的 probe 设计probe 是 ponytail 最有个性的设计。它不是“边跑边检查”而是“先测后跑”。启动时ponytail 会向probe字段指定的 DoH 服务器发一个真实的查询请求。探测成功才启动 DNS 服务器探测失败监听端口保持打开但拒绝应答所有查询。这个设计的用意很明确避免“口是心非的 DNS”lying DNS。想象一下这个场景你配置了一个 DoH 上游但它实际上不可达、或者返回垃圾数据。如果你的 DNS 代理不做检查就直接转发客户端会在不知情的情况下拿到错误解析结果而且还会缓存这些结果导致故障持续时间被拉长。probe 机制就是在正式工作前先确认“这条路是通的”不通就干脆不干活。这样做的代价是启动延迟。每次启动 ponytail 都要多等一次 DoH 往返通常在几百毫秒以内可以接受。但如果你的网络环境不太好probe 本身就可能超时导致 ponytail 一直处于“拒绝应答”状态。遇到这种情况先排查网络再考虑换一个更快的probe地址。我个人觉得这个“probe 失败但端口保持打开”的设计比直接退出进程更优雅。因为你可以在不重启进程的情况下等网络恢复后再重新触发 probe。虽然 ponytail 好像没有主动重新 probe 的机制但至少进程还活着排查问题的时候不用反复看日志确认是不是又崩了。3.3 fallback 与“口是心非的 DNS”fallback 机制解决的是另一个问题主上游挂了怎么办。配置里[fallback]段定义了一套备用的 DoH 上游。当主upstream请求失败或超时时ponytail 会切换到 fallback 上游继续解析。这个逻辑跟很多代理工具的 fallback 类似但 ponytail 的实现更直接——它不做复杂的健康检查就是简单的“主请求失败就试备用的”。我用抓包工具确认过这个行为手动把主upstream改成一个不存在的地址然后发起 DNS 查询观察 ponytail 的流量确实能看到它转而请求了[fallback]里配置的https://dns.google/dns-query。这里要注意的是fallback 不是“负载均衡”。它只在主上游不可用时才生效不会主动把部分流量分给备用上游。这个设计取舍让配置更简单但也意味着主上游如果性能差fallback 再快也帮不上忙因为平时根本不会用它。3.4 抓包视角看 DoH 转换从 DNS wire format 到 HTTPS 请求最后是 DoH 转换的技术细节。这部分我建议你亲自抓包看一次看完就彻底理解 ponytail 在做什么了。当普通应用通过 UDP 向127.0.0.1:53发送一条 A 查询时ponytail 会把这个 DNS 查询binary wire format转换成 HTTPS 请求。具体来说把 DNS 查询的二进制数据做base64url 编码。放进 HTTPS 请求的查询参数里也就是?dns...。请求头带上Accept: application/dns-message。发到 DoH 上游比如https://cloudflare-dns.com/dns-query?dns...。收到响应后把响应体也是 DNS wire format解析出来。包装成传统 DNS 响应通过 UDP 返回给客户端。用tcpdump或 Wireshark 抓包你能清清楚楚看到这个转换过程的痕迹。我抓包时看到的典型 HTTPS 请求是这样的GET /dns-query?dnsAAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE HTTP/1.1 Host: cloudflare-dns.com Accept: application/dns-message那个dns参数后面一串看似乱码的字符串就是 base64url 编码后的 DNS 查询。这个过程其实不算复杂但它把一个“传统 UDP DNS”的场景优雅地搬到了“HTTPS 加密传输”的场景上。需要特别提醒一点ponytail 对查询类型的支持非常有限。它主要处理 A 和 AAAA 查询。如果遇到它不认识的类型比如 HTTPS/SVCB、AXFR、TXT 等它会低调地返回失败或空响应不会死循环但也不会满足你的需求。后面我会专门讲这个坑。4. 认真看待 ponytail 的“不 polish”实测中遇到的坑与解决建议负责任地讲要得出一个诚实可靠的评价必须看看这个工具在实际使用中到底有哪些坑。我前后跑了大概一周下面这些问题是真实遇到过的。4.1 只支持 A/AAAA 之外的查询类型会怎样第一个坑很直接ponytail 基本只干活 A 和 AAAA。我第一次跑起来后用dig查了一条TXT记录dig 127.0.0.1 example.com TXT结果返回了一个空响应status: NOERROR但 answer 区什么都没有。这不是 ponytail 解析失败而是它压根没有把 TXT 查询转发到 DoH 上游。它的逻辑里只对 A/AAAA 做了处理其他类型直接“就地解决”——返回一个空的成功响应或者相当于没结果。看起来这是个小问题但在某些场景下会很麻烦。比如邮件服务器的 SPF 记录是 TXT 类型查不到会影响反垃圾邮件验证。DNSSEC 相关的 DNSKEY 查询也处理不了。一些应用会用 TXT 记录做服务发现或验证比如 Lets Encrypt 的 DNS-01 挑战。所以如果你的网络环境里有这些查询需求ponytail 就不是合适的选择。这个限制其实也是它“shim”定位的体现——只解决最基础的 A/AAAA 解析其他场景交给更完整的工具。4.2 TTL 缓存与性能第二个坑也是我跑完一轮压测后最直观的感受性能一般几乎不缓存。ponytail 的 README 里写得很清楚它的 TTL 处理很“诚实”——大多数记录不缓存。这意味着每个查询都会真实地打到 DoH 上游不会在本地做 TTL 倒计时缓存。这个设计的好处是你不会因为缓存而拿到过期数据。坏处也很明显性能上限就在那里所有请求都要走一遍 HTTPS 往返。在简单的并发测试下ponytail 的 QPS 和延迟都远不如 dnsmasq 或 unbound 这种有完善缓存机制的 DNS 服务器。如果你想用它做实验室的默认 DNS性能也许还凑合但如果是给整个局域网做 DNS 服务我劝你打消这个念头。真要追求性能建议在 ponytail 前面再加一层缓存或者干脆换用下面会提到的 dnsproxy。4.3 HTTP/3 的依赖与兼容性第三个坑不在 ponytail 本身而在它的依赖环境。因为 ponytail 是为 HTTP/3 世界准备的它在 DoH 传输层上倾向于使用 HTTP/3也就是 QUIC。但 HTTP/3 依赖内核的 UDP 支持和较新的 TLS 库。如果你的系统比较老或者网络环境对 UDP 不太友好HTTP/3 连接可能会失败。我在测试时发现旧版本的 curl 以及某些精简版 Linux 发行版根本没法建立 HTTP/3 连接。这时候 ponytail 的 DoH 请求就会一直失败probe 卡住DNS 服务起不来。解决思路有两个使用 HTTP/2 的 DoH 端点比如很多 DoH 服务商同时支持 HTTP/2 和 HTTP/3。确保系统环境支持 HTTP/3比如升级内核、安装较新版本的 curl 和 Rust TLS 库。这个坑也解释了为什么社区建议里会提到“如果环境里没有 HTTP/3 需求使用 HTTP/2 的 DoH 上游会更稳。”4.4 作为早期项目的自嘲什么时候应该换掉 ponytail说实话ponytail 的 README 里那句话——“It probably lacks polish and will probably fall apart if you poke it”——不是在自谦而是在诚实地描述自己的状态。我在实测中也感受到了这一点配置错误时的错误信息不够友好有些直接是 Rust 的 panic 输出。日志信息偏少排查问题时需要配合抓包工具。某些边界情况比如上游返回畸形 DNS 响应处理得比较粗糙。所以我的结论是ponytail 适合作为学习工具和实验工具不适合作为长期运行的生产服务。如果你想稳定地给整个网络提供 DoH 解析能力直接换 dnsproxy 或 sing-box 的 DNS 模块省心得多。5. 如何把它塞进真实网络环境旁路网关、路由器和我家的实验拓扑ponytail 虽然简单但它演示了一种重要的网络架构思路把传统 DNS 请求引导到加密通道。这个思路在真实网络环境里有不少用处。下面我讲讲怎么把 ponytail 或者类似思路落地到实际场景。5.1 本机环境改善“不支持 DoH 的旧应用”最简单、也最贴合 ponytail 定位的使用方式在本机跑一个 ponytail然后把系统 DNS 指向127.0.0.1。在 Linux 上只要编辑/etc/resolv.confnameserver 127.0.0.1然后启动 ponytail系统里所有走传统解析器的应用包括一些老旧命令行工具、脚本、Python 的socket.getaddrinfo等等就都会被桥接到 DoH 上。我用 Firefox 实测过在 Firefox 关闭自带 DoH、但系统 DNS 指向127.0.0.1的情况下Firefox 确实使用的是系统解析器也就是 ponytail它的 DNS 查询最终通过 HTTPS 发出去了。抓包能看到明显的Accept: application/dns-message请求头。这种使用方式的优点很突出应用无感知不需要逐个配置。缺点也很明显只有本机能享受这种“桥接”局域网其他设备享受不到。顺便提一句我在测试中发现 Firefox 的解析器会先尝试 AAAAIPv6再尝试 AIPv4。ponytail 对这两种类型都做了支持所以不会因为“只处理 A 不处理 AAAA”而出问题。5.2 局域网环境旁路网关与透明代理如果你想让整个局域网都走 DoH 解析只在本机跑 ponytail 就不够了。这时候需要一个经典的网络架构旁路网关。思路很简单在一台专门的设备比如一台小主机、树莓派或软路由上跑 ponytail。修改配置bind 0.0.0.0:53让局域网内其他设备可以访问。路由器的 DHCP 服务把 DNS 指向这台设备或者手动把设备 DNS 指过去。这样局域网里所有设备的 DNS 查询都会先到 ponytail再由它通过 DoH 转发到上游。这就是一种“透明代理”的效果——客户端不知道也不关心 DNS 查询最终是怎么出去的。但请注意这种用法对稳定性要求很高。一旦 ponytail 进程挂了整个局域网的 DNS 解析都会瘫痪因为你把 DNS 都指向它了。所以我不太建议用 ponytail 做旁路网关的 DNS 服务至少得加一层守护进程或者健康检查比如在前端再挂一个dnsmasq做缓存和高可用ponytail 只负责“翻译”给 DoH。5.3 与 sing-box、mosdns、dnsproxy 的横向对比跑完 ponytail 之后我又测试了另外几个工具用来横向对比。这里直接给出我的测试感受工具定位缓存稳定性配置复杂度适用场景ponytailDNS shim / DoH proxy无实验级简单学习、临时桥接dnsproxyDNS 代理AdGuard 出品有生产级简单本机/局域网 DoH 代理sing-box DNS 模块代理工具的 DNS 模块有生产级中等与代理工具集成mosdns灵活 DNS 路由/转发有生产级较复杂自定义 DNS 路由策略dnsproxy和 ponytail 定位最接近但它支持缓存、支持更多查询类型、稳定性更好而且是 AdGuard 出品的维护活跃。如果你要一个“ponytail 的成熟版”选它。sing-box DNS 模块sing-box 是现在很流行的代理工具它的 DNS 模块功能非常强可以做 DNS 分流、缓存、DoH 上游等。如果你已经在用 sing-box就没必要再加一个 ponytail。mosdns灵活性最高支持各种 DNS 路由规则但配置也最复杂。适合喜欢折腾的人。5.4 一个可复现的家庭实验拓扑最后分享一个我在家里验证过的小拓扑供你参考。这个拓扑的完整链路是应用/设备 ↓ UDP 53传统 DNS ponytail (127.0.0.1:53 或 0.0.0.0:53) ↓ HTTPSDoHHTTP/2 或 HTTP/3 Cloudflare / Google / AdGuard DoH 上游配置上我用的是 AdGuard 的 DoH 服务因为它在国内的可达性比 Cloudflare 更稳定bind 127.0.0.1:53 upstream https://dns.adguard.com/dns-query bootstrap https://94.140.14.14/dns-query probe https://dns.adguard.com/dns-query [fallback] upstream https://dns.google/dns-query bootstrap https://8.8.8.8/dns-query probe https://dns.google/dns-query log info启动后我用dig连续查询了几个域名确认响应正常然后用抓包工具确认 HTTPS 请求确实发出去了。整个过程前后不到十分钟。这个拓扑很适合作为你理解 DoH 代理的第一块试验田。6. 澄清“ponytail 插件”误读并给出可直接上手的替代方案写这篇文章之前我顺手搜了一下“ponytail”相关的热搜词发现有不少人在搜“ponytail plugin”“ponytail skill”“插件 ponytail 如何使用”。这其实是个很有意思的误读很多人把 ponytail 当成某种插件或 AI 技能——比如 Obsidian 插件、Neovim 插件或者某个工作流自动化技能。但实际上ponytail 就是一个独立的 DNS 服务器/代理程序跟“插件”没有任何关系。6.1 为什么有人会搜“ponytail plugin / skill”我猜测这些搜索大概率是出于以下原因在某篇文章或视频里看到了“ponytail”这个词但上下文模糊。把 ponytail 和某个真正叫“ponytail”的插件混淆了。单纯因为“ponytail”这个词听起来像某个轻量级工具的名字搜索时直接带上了“插件”“skill”等后缀。不管原因是什么结论都一样ponytail 不是插件不需要安装在 Obsidian、vim 或任何宿主应用里。它是一个命令行程序用 TOML 配置跑起来之后就是一台 DNS 服务器。如果你确实需要的是“DNS 相关的插件/技能”可以看看下面几个替代方案。它们虽然不是插件但能直接解决“传统 DNS 转 DoH”这个需求。6.2 替代方案一dnsproxydnsproxy 是 AdGuard 出品的开源 DNS 代理工具和 ponytail 定位最接近但成熟得多。它支持DoH、DoT、DoQDNS over QUIC上游。DNS 缓存。多种查询类型不只是 A/AAAA。跨平台Windows/macOS/Linux 都有二进制。我的使用体验是dnsproxy 的配置同样不复杂。一个典型用法dnsproxy --port 53 --upstream https://cloudflare-dns.com/dns-query --cache一条命令就能在本地 53 端口起一个带缓存的 DoH 代理。比 ponytail 稳定也比 ponytail 功能全面。如果你在找“成熟版的 ponytail”选它准没错。6.3 替代方案二sing-box DNS 模块sing-box 是一个通用的代理工具它的 DNS 模块做得非常强大。如果你已经在用 sing-box 做代理完全不需要再单跑一个 ponytail——直接在 sing-box 配置里开启 DNS 模块并指定 DoH 上游即可。sing-box DNS 模块支持多上游、DNS 分流按域名规则走不同上游。缓存、fallback。DoH、DoT、UDP 等多种协议。配置虽然比 ponytail 复杂但灵活性也高得多。如果你对“DNS 分流”有需求比如国内域名走国内 DNS、国外域名走 DoHsing-box 是更好的选择。6.4 替代方案三mosdns / systemd-resolved再补充两个方案。mosdns是一个高度可定制的 DNS 转发/路由工具。它最强大的地方是支持插件化的 DNS 处理流程你可以定义复杂的规则链某些域名直接返回、某些域名走 DoH、某些域名走 UDP 53。如果你喜欢折腾mosdns 能给你最大的控制力。但它的配置也最复杂新手可能会觉得劝退。systemd-resolved是 Linux 系统自带的解析器很多人可能没注意到它其实支持 DoT 和 DoH。如果你用的是较新的 systemd 版本可以在/etc/systemd/resolved.conf里直接配置 DoH 上游[Resolve] DNScloudflare-dns.com#8.8.8.8 DNSOverTLSyes这个方案的好处是完全系统原生不需要额外安装工具。但它有一个限制systemd-resolved 的 DoH 支持在部分版本上不如 DoT 完善而且配置自由度不高。综合来看如果你想要一个“一键解决传统 DNS 转 DoH”的方案dnsproxy 和 sing-box 是最推荐的。ponytail 则更适合当你学习 DoH 代理原理的入门工具。我个人的体会是像 ponytail 这样的小工具价值不在于它有多稳定、多完善而在于它把“DNS 垫片”这个概念做成了一个可以拿在手里玩的实物。你跑一次日志、抓一次包、看一眼它怎么把 UDP 53 的查询变成 HTTPS 请求比读十篇原理文章都管用。最后分享一个小技巧如果你也想在本地快速抓包观察 DoH 转换过程可以用tcpdump监听本地回环接口的 53 端口和 443 端口sudo tcpdump -i lo -nn port 53 or port 443然后开一个 ponytail用dig随便查一个域名你就能在抓包结果里同时看到 UDP 的 DNS 查询和 HTTPS 的 DNS 查询请求了。那种“原来它是这么干的”的感觉比任何文档都来得直观。