WireGuard 隧道已连接但 DNS 失效:3 种故障修复
WireGuard 隧道正常但域名无法解析或 DNS 查询泄漏到本地路由器?按症状区分 3 种故障,检查路由、UDP 53 端口与解析器覆盖并完成修复。
WireGuard 隧道建立后 DNS 为什么会立即失效
WireGuard 上的 DNS 会以 3 种方式失效,每种情况都有对应的修复方法。可能是完全无法解析,也可能是名称可以解析,但查询流量从隧道外的网络接口离开本机;还可能是客户端自身的解析器管理器在接口启动几秒后覆盖设置。问题几乎从来不在隧道本身。问题在于用于告知客户端应向哪个解析器发起查询的那一行,以及决定发往该解析器的数据包如何传输的路由。
WireGuard 传输 IP 数据包,不了解 DNS(域名系统,即将 example.com 等名称转换为 IP 地址的服务)。客户端 [Interface] 块中的 DNS = 行不是 WireGuard 设置。它由 wg-quick 读取;wg-quick 是用于启动接口的 shell 包装器,而 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 问题;仅修改解析器配置无法解决该问题。本页的所有示例都使用 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 控制服务器 可以提供这种协调,而无需将密钥材料交给第三方。
故障三:Linux 客户端上的 resolvconf 与 systemd-resolved 发生冲突
macOS、Windows、iOS 和 Android 客户端通过官方应用应用 DNS =,通常不会引发问题。Linux 的问题在于,设置由 shell 脚本应用,而脚本必须猜测系统运行的是多个解析器管理器中的哪一个。
第一个故障会直接报错。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,但查询仍然发送到旧解析器。systemd-resolved 会为每个链路维护单独的解析器列表,并为每个查询选择一个链路。除非将某个链路标记为名称解析的默认路由,否则它会继续使用无线链路的解析器,因为该链路包含搜索域,而您的链路没有。
在同一步中设置解析器并声明默认路由。%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 = 行。否则,两个机制会同时写入解析器状态,但之后只有其中一个会执行清理。~. 参数是关键部分:它将 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,再排查其他问题,因为每次网络变化都会重写该文件的工具,可能在最不合适的时候撤销您的修改。
升级:通过隧道运行您自己的过滤解析器
查询可以稳定地通过隧道传输后,远端的解析器就成为一个控制点。在那里运行 AdGuard Home,可以为所有已连接设备提供阻止列表过滤和查询日志,无需客户端软件,也无需逐台设备配置。截至2026年7月,官方安装脚本只需一行命令。
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 传输。如果数据包出现在无线或 ethernet 接口上,查询就会以明文离开。dig +short whoami.akamai.net 可以提供第二个结果,因为它会返回发起查询的递归解析器的公网地址。因此,如果返回的地址不是您服务器的地址,就可以确认发生了泄漏。
使用 split tunnel 时是否需要 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 客户端,因为只有它能显示具体工作机制。resolvectl status 和 tcpdump 会告诉您哪个解析器返回了响应,以及数据包通过哪个接口传输。手机和桌面应用会应用相同的 DNS 和 AllowedIPs 值,但不会显示底层配置。因此,Linux 客户端正确后,您就可以复制一套已经验证过的配置。