WireGuard隧道已连接但DNS无法解析?三种故障修复
隧道已建立但出现“connection timed out”或域名解析失败?本文区分解析器无响应、DNS绕过隧道、客户端配置被覆盖三种情况,并给出对应修复方法。
WireGuard 隧道建立后 DNS 为什么会立即失效
通过 WireGuard 使用 DNS 时,通常有三种失败方式,每种都有对应的解决方法。可能是完全无法解析,可能是名称可以解析但查询流量绕过隧道从本机发出,也可能是客户端自身的解析器管理器在接口启动几秒后覆盖设置。问题几乎从来不在隧道本身,而在于客户端向哪个解析器发送查询的那一行配置,以及决定解析器数据包如何传输的路由。
WireGuard 负责传输 IP 数据包,不了解 DNS(域名系统,即将 example.com 等名称转换为 IP 地址的服务)。客户端 [Interface] 块中的 DNS = 行不是 WireGuard 设置。启动接口的 shell 包装器 wg-quick 会读取它,wg-quick 随后在隧道运行期间修改客户端的解析器配置,并在隧道关闭时通过 wg-quick down 恢复配置。因此,下面的所有问题都是路由问题或 wg-quick 问题,而不是密码学问题。如果隧道尚未建立,请先阅读在自己的 VPS 上搭建自托管 WireGuard VPN,然后再返回本页。
在处理 DNS 之前,先确认隧道运行正常。
sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1wg show 应列出具有最新 latest handshake 的对等端,并且两个 ping 都应收到响应。如果 ping 1.1.1.1 超时,说明存在转发或 NAT(网络地址转换)问题,而不是 DNS 问题;调整解析器配置无法解决此问题。如果 ping 有响应,但开始传输实际流量后吞吐量骤降,这是另一个独立问题。请参阅WireGuard 速度慢几乎总是 MTU 导致的,而不是查看本页内容。本文所有示例都使用 10.8.0.0/24 作为隧道子网,并使用 10.8.0.1 作为服务器的隧道地址。请替换为您自己的值。
故障一:无法解析任何域名,因为解析器没有响应
现象很明确。ping 1.1.1.1 可以正常工作,而 curl https://example.com 返回以下内容:
curl: (6) Could not resolve host: example.com直接从客户端向隧道解析器发起查询。Ubuntu 和 Debian 中的 dig 来自 dnsutils 软件包。
dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.com第一条命令返回地址,说明数据包可以通过隧道到达互联网。第二条命令没有返回结果,并显示 ;; communication timed out; no servers could be reached。诊断结果就是:客户端指向 10.8.0.1,而 10.8.0.1 没有在 UDP 端口 53 上响应。
原因有两个。服务器上可能没有运行解析器,也可能是服务器防火墙在查询到达前将其丢弃。请在服务器上检查这两项。
sudo ss -ulnp | grep ':53'
sudo nft list ruleset正在运行且绑定正确的解析器会显示包含 10.8.0.1:53 或 0.0.0.0:53 的行。在 Ubuntu 上,通常容易忽略的是 127.0.0.53:53:它是 systemd-resolved 的存根监听器,绑定到回环地址,其他机器无法访问。将 VPN 客户端指向一台唯一解析器是该存根监听器的服务器,就会产生完全相同的超时。
解决方法是让解析器监听隧道地址,并添加一条允许对等端访问它的防火墙规则。
sudo apt update && sudo apt install -y unbound
printf 'server:\n interface: 10.8.0.1\n access-control: 10.8.0.0/24 allow\n' \
| sudo tee /etc/unbound/unbound.conf.d/wireguard.conf
sudo systemctl restart unbound
sudo ss -ulnp | grep '10.8.0.1:53'然后仅允许隧道流量访问该端口。使用 nftables 时,将以下两行添加到 /etc/nftables.conf 中的 input 链,并使用 sudo systemctl reload nftables 重新加载。
udp dport 53 iifname "wg0" accept
tcp dport 53 iifname "wg0" accept使用 ufw 时,sudo ufw allow in on wg0 to any port 53 可以完成相同的操作。不要将端口 53 对公网开放。扫描器会在数天内发现开放的递归解析器,并将其用于放大拒绝服务攻击;服务提供商通常会先于您发现相关流量。
在客户端重新运行 dig +short @10.8.0.1 example.com。如果输出中出现地址,说明解析器路径正常,客户端现在只需使用该解析器。将该行添加到客户端的 [Interface] 块中,然后使用 sudo wg-quick down wg0 && sudo wg-quick up wg0 重启接口。
[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1故障二:DNS 泄漏,因为分流隧道不会路由解析器
这个问题更严重,因为表面上一切正常。名称可以解析,页面可以加载,但查询会以明文形式经过您原本不想信任的本地网络。
两种配置会导致此问题。第一种是客户端配置了 AllowedIPs = 0.0.0.0/0, ::/0,但没有 DNS = 行。wg-quick 会将默认路由安装到自己的路由表中,并通过 suppress_prefixlength 0 添加规则。这样做是为了有意保留更具体的本地路由,使计算机仍能访问打印机。客户端通过 DHCP 获取的解析器通常是 192.168.1.1 处的路由器,它会匹配其中一条本地路由。您的流量会经过隧道,但本地网络仍会收到您查询的完整域名列表。
第二种是分流隧道:配置了 AllowedIPs = 10.8.0.0/24 和 DNS = 9.9.9.9。由于 9.9.9.9 不在 AllowedIPs 中,客户端没有通过隧道访问它的路由,因此查询会像第一种情况一样通过本地链路发出。
确认实际响应的解析器。whoami.akamai.net 是一个公共测试名称。它会返回发起查询的递归解析器的 IP 地址,因此您可以将其响应与服务器的公网地址进行比较。
resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53resolvectl status 会为每条链路输出一个区块。如果以太网或无线链路对应的区块仍显示 Current DNS Server: 192.168.1.1,而 wg0 区块没有显示任何内容,这就是泄漏。dig +short whoami.akamai.net 返回家庭宽带地址而不是服务器地址,则从远端确认了这一点。tcpdump 行可以最终证明问题:正常输出会将所有目标端口为 53 的数据包放到 wg0 上;发生泄漏时,这些数据包会经过 wlan0 或 enp3s0。
修复分为两部分,缺一不可。将 DNS 设置为隧道内部的地址,并确保该地址位于 AllowedIPs 内。
[Interface]
Address = 10.8.0.2/32
DNS = 10.8.0.1
[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.8.0.0/24, 10.20.0.0/1610.8.0.1 位于 10.8.0.0/24 内,因此查询会加密后发送到服务器。如果您坚持在分流隧道中使用公共解析器,请将其添加为主机路由:AllowedIPs = 10.8.0.0/24, 9.9.9.9/32。这样数据包会经过隧道,但本地网络仍可从之前的会话中看到您选择了该服务提供商。自行运行解析器可以避免这个问题。
解析器分配是手动构建 WireGuard 与由协调系统管理的网状网络之间的一个明显差异,这也是 WireGuard 与 Tailscale 的比较 中需要权衡的一点。运行 自托管 Headscale 控制服务器 可以在不将密钥材料交给第三方的情况下提供这种协调能力。如果最后这句话正是您担心的问题,请注意,Tailscale 从不持有用于加密网络流量的密钥;更值得关注的问题是,遭入侵的协调服务器或被窃取的身份账户可能对您的网络造成哪些额外影响。
Linux 客户端上的故障三:resolvconf 与 systemd-resolved 冲突
macOS、Windows、iOS 和 Android 客户端通过官方应用应用 DNS =,通常不会造成太多问题。Linux 的情况不同,因为该设置由 shell 脚本应用,而脚本必须判断系统运行的是多个 resolver manager 中的哪一个。
第一种故障会直接报错。sudo wg-quick up wg0 停止运行,并显示:
resolvconf: command not foundwg-quick 会调用 resolvconf,但系统中未安装该二进制文件。请安装与 systemd-resolved 通信的实现,然后重新启动该接口。
sudo apt install -y openresolv
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0第二种故障不会直接报错,但它最容易浪费排查时间。接口已启动,resolvectl status wg0 正确显示 DNS Servers: 10.8.0.1,但查询仍发送到旧的 resolver。systemd-resolved 会为每个链路维护独立的 resolver 列表,并为每次查询选择一个链路。除非将某个链路标记为名称解析的默认路由,否则它会继续使用无线链路的 resolver,因为该链路配置了搜索域,而当前链路没有。
请在同一步中设置 resolver 并声明默认路由。%i 会展开为接口名称,因此下面的代码块可直接用于任何接口。
[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %i以这种方式使用 PostUp 时,请删除 DNS = 行。否则,两个机制会同时写入 resolver 状态,但之后只有其中一个会执行清理。~. 参数是关键部分:它会将 wg0 标记为所有名称的路由域,因此 systemd-resolved 会将所有查询发送到该链路,而不是逐次查询选择链路。请验证设置。
resolvectl status wg0正常输出包含 DNS Servers: 10.8.0.1 和 Default Route: yes。如果 Default Route 读取为 no,则 resolvectl domain 部分没有执行,系统又回到了链路选择模式。
还有一种情况需要特别说明。如果 /etc/resolv.conf 是普通文件,而不是指向 /run/systemd/resolve/stub-resolv.conf 的符号链接,则说明它由其他组件管理,通常是 NetworkManager 或容器运行时。在进行其他排查前先运行 ls -l /etc/resolv.conf,因为会在每次网络变化时重写该文件的工具,可能在最不合适的时候撤销你的修改。
隧道上的进阶方案:运行您自己的过滤 DNS 解析器
查询能够稳定通过隧道传输后,远端的解析器就成为一个控制点。在那里运行 AdGuard Home,即可为所有已连接设备提供屏蔽列表过滤和查询日志,无需安装客户端软件,也无需逐台设备配置。经核对,官方安装脚本截至 July 2026 只有一行。
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v首次运行时,设置向导会监听 3000 端口。通过隧道访问 http://10.8.0.1:3000,不要将该端口公开开放;然后在向导中将 DNS 监听地址和管理界面监听地址都设置为 10.8.0.1。如果故障一中的 unbound 仍占用同一个地址,请先使用 sudo systemctl disable --now unbound 停止它,因为同一个地址上的 UDP 53 端口不能同时由两个进程绑定,后启动的进程会以 listen udp 10.8.0.1:53: bind: address already in use 退出。
如果客户端配置中已经写有 DNS = 10.8.0.1,则无需修改。现在,查询日志会显示每个对端发出的所有查询。这是一个实际的隐私决策,并非无条件获益:您将信任从互联网服务提供商转移给自己,也需要负责及时为该主机安装补丁。面向互联网开放的服务器必须先完成基本安全配置,新 VPS 上线后的前十分钟对此进行了说明。
FAQ
为什么 WireGuard 隧道可以连接,但域名无法解析?
隧道只传输数据包,完全不处理域名。因此,隧道正常但查询失败,说明您指定的解析器没有响应。在客户端使用 dig +short @10.8.0.1 example.com 进行测试。收到 communication timed out 响应,通常表示该隧道地址上没有解析器监听,常见原因是 systemd-resolved 存根解析器只绑定到 127.0.0.53;也可能是服务器防火墙丢弃了到达 wg0 的 UDP 端口 53 流量。先修复监听问题,再仅为 wg0 开放该端口。
如何检查 DNS 是否通过 WireGuard 泄漏?
在客户端运行 sudo tcpdump -ni any -c 10 port 53,并在浏览网页时查看接口列。所有数据包都应通过 wg0。如果数据包出现在无线或以太网接口上,说明查询正在以明文方式传输。dig +short whoami.akamai.net 可以提供第二个验证结果,因为它会返回发起查询的递归解析器的公网地址。因此,如果返回的地址不是您服务器的地址,就可以确认存在泄漏。
使用分流隧道时,是否仍需要 DNS = 行?
需要,并且解析器地址也必须位于 AllowedIPs 内,否则客户端没有到达该地址的路由。使用 AllowedIPs = 10.8.0.0/24 时,10.8.0.1 中的解析器地址会被覆盖,查询也会经过加密。诸如 9.9.9.9 这样的公共解析器不在覆盖范围内,因此查询会通过本地链路发出,即使 DNS 行看起来配置正确。
为什么 resolvectl 显示了正确的服务器,但查询仍然发往其他位置?
systemd-resolved 会为每个链路维护一组解析器,并为每次查询选择一个链路。因此,即使 wg0 上的条目正确,只要另一个链路为域名查询持有默认路由,该条目仍会被忽略。在客户端的 [Interface] 块中添加 PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.,并删除 DNS = 行。之后,resolvectl status wg0 应报告 Default Route: yes。
多个客户端出现问题时,应先修复哪个客户端?
先修复一个 Linux 客户端,因为只有 Linux 客户端能显示具体工作机制。resolvectl status 和 tcpdump 会告诉您哪个解析器返回了响应,以及数据包通过哪个接口传输。手机和桌面应用会使用相同的 DNS 和 AllowedIPs 值,但不会显示底层配置。因此,Linux 客户端配置正确后,您复制的就是一套已经验证过的配置。