连接 WireGuard 后,有时只希望内网域名通过隧道中的 DNS 查询,其他域名仍使用公共 DNS。对于已经使用 systemd-resolved 的 Linux 系统,可以直接配置 DNS 路由域,再通过 wg-quick 的 PostUp 自动应用,无须额外安装 DNS 转发服务。
文中的内网地址使用文档专用网段,example.com 和 example.net 是保留示例域名。部署时请换成自己的地址和域名。
目标与适用环境
本文使用以下示例:
| 项目 | 配置 |
|---|---|
| WireGuard 接口 | wg0 |
| 隧道内 DNS | 198.51.100.53 |
| 默认 DNS | 223.5.5.5 |
| 经内网 DNS 查询的域名 | home.arpa、example.com、example.net 及其子域名 |
example.com 和 example.net 是示例域名,按需替换或删除。这里配置的是域名后缀,不限于顶级域名,也可以是 corp.example.com 这样的子域。
适用于由 wg-quick 管理 WireGuard、systemd-resolved 管理系统 DNS 的 Armbian、Debian 或 Ubuntu。NetworkManager 等工具直接管理的 WireGuard 连接不一定执行这些钩子,应使用对应管理工具的配置方式。
先检查实际环境:
resolvectl --version
wg --version
systemctl is-active systemd-resolved
resolvectl status
ls -l /etc/resolv.conf
cat /etc/resolv.conf
如果 /etc/resolv.conf 包含以下内容,通常表示程序通过本地存根访问 systemd-resolved:
nameserver 127.0.0.53
options edns0 trust-ad
search .
保留该文件即可,不要把它改成两个上游 DNS。多个 nameserver 本身不能表达按域名分流。本文使用的是已有的 DNS 路由能力;若系统缺少 resolvectl 或服务未运行,应先确认本机的 DNS 管理方式。
1. 设置默认 DNS
创建配置目录并编辑文件:
sudo mkdir -p /etc/systemd/resolved.conf.d
sudo vim /etc/systemd/resolved.conf.d/90-split-dns.conf
写入:
[Resolve]
DNS=
DNS=223.5.5.5
FallbackDNS=
Domains=
Domains=~.
空的 DNS= 和 Domains= 清除前面累积的全局列表,再设置本文所需的值。FallbackDNS= 清空备用列表;它不是按域名分流规则。
~. 是匹配所有域名的路由域。稍后为 wg0 设置更具体的域名后缀后,这些后缀将优先匹配。
sudo systemctl restart systemd-resolved
这一步修改的是全局设置,不会清除其他网卡上的 DNS 路由域。如果其他网卡已经配置 ~. 或相同、更加具体的域名规则,需要先在其所属的网络管理配置中解决冲突。
2. 在 WireGuard 中添加 DNS 钩子
编辑现有配置:
sudo vim /etc/wireguard/wg0.conf
在已有的 [Interface] 段内添加:
PostUp = resolvectl dns %i 198.51.100.53
PostUp = resolvectl domain %i '~home.arpa' '~example.com' '~example.net'
PostUp = resolvectl default-route %i no
保留原有的地址、密钥、Peer 和路由配置。如果原来有 DNS = ...,删除该项,避免 wg-quick 同时通过 resolvconf 设置另一套 DNS。不要另建重复的 [Interface] 段。
各行的作用如下:
| 配置 | 作用 |
|---|---|
resolvectl dns %i 198.51.100.53 | 设置该接口的 DNS 服务器 |
resolvectl domain %i ... | 设置该接口负责的 DNS 路由域 |
resolvectl default-route %i no | 不把该接口用作未匹配域名的默认 DNS 路径 |
wg-quick 会将 %i 替换为接口名称,例如 wg0。多个 PostUp 按配置顺序执行。
default-route no 只影响 DNS 服务器选择,不修改 IP 默认路由,也不能覆盖显式配置的 ~. 路由域。这里的分流主要由全局 ~. 与接口上的具体后缀实现。
正常执行 wg-quick down 时,接口会被删除,相应的 per-link DNS 设置也会消失,因此不必额外添加 PostDown = resolvectl revert %i;接口删除后再执行 revert 反而可能找不到接口。
DNS 服务器必须通过该隧道可达。确认 Peer 的
AllowedIPs覆盖198.51.100.53,例如已包含198.51.100.0/24。若需补充,应追加适当网段或198.51.100.53/32,不要覆盖原有路由。DNS 能解析也不代表业务地址可达,业务网段仍需相应路由。
3. 立即应用,无须断开隧道
如果 wg0 当前已经运行,保存文件后执行:
sudo resolvectl dns wg0 198.51.100.53
sudo resolvectl domain wg0 '~home.arpa' '~example.com' '~example.net'
sudo resolvectl default-route wg0 no
sudo resolvectl flush-caches
这些命令更新当前运行状态,配置文件里的 PostUp 则负责下次启动时自动设置。仅执行 wg syncconf 不会重新执行 PostUp。
如果接口尚未启动,则使用原来的管理方式启动,例如:
sudo systemctl start wg-quick@wg0
如果使用了 SaveConfig = true,注意它可能在关闭接口时以运行状态覆盖配置文件;修改前应处理好该选项,避免文件改动丢失。
4. 验证分流
查看实际配置:
resolvectl status
应能在全局设置中看到 223.5.5.5 和 ~.,在 wg0 中看到 198.51.100.53 以及指定的三个路由域。
将以下内网域名替换成实际存在的记录:
resolvectl query nas.home.arpa
resolvectl query www.baidu.com
预期规则如下,以下是配置目标,并非实机测试输出:
| 查询 | DNS 服务器 |
|---|---|
home.arpa、nas.home.arpa | 198.51.100.53 |
example.com、git.example.com | 198.51.100.53 |
example.net、a.b.example.net | 198.51.100.53 |
www.baidu.com | 223.5.5.5 |
如需确认实际发包,可在一个终端运行:
sudo tcpdump -ni any 'port 53 and (host 198.51.100.53 or host 223.5.5.5)'
在另一个终端清除缓存后重新查询。直接执行 dig @198.51.100.53 ... 只能验证该 DNS 是否可用,不能证明系统分流规则生效。
路由域如何匹配
~home.arpa 表示仅用于选择 DNS 的路由域:匹配 home.arpa 本身及其所有子域名,但不会为短名称自动追加后缀。例如查询 nas,不会因此自动变成 nas.home.arpa。
如果确实需要短名称补全,可以使用不带 ~ 的 home.arpa 搜索域;搜索域同时参与 DNS 路由。本文使用完整域名,统一采用 ~。
systemd-resolved 优先选择匹配标签数最多的域。因此 ~home.arpa 比 ~. 更具体。如果多个接口拥有同样最佳的匹配域,查询可能并行发往多个接口,不能把配置重复的接口理解为简单的主备关系。
一次命令传入多个域名,用空格分隔:
sudo resolvectl domain wg0 '~home.arpa' '~example.com' '~example.net'
该命令会替换接口原有的域名列表,并非追加。新增域名时,应在同一条命令中写全,并同步修改 PostUp。
使用边界与排查
- 接口删除后规则消失。 隧道断开后,原本的私有域名可能转由全局 DNS 查询。这套配置不是“隧道断开时禁止私有域名外发”的策略。
- DNS 分流与业务路由是两回事。 设置公共 DNS 为
223.5.5.5,不保证访问它的 IP 流量走物理网卡;全隧道或策略路由仍可能让它经过 WireGuard。 - 应用可能绕过系统 DNS。 浏览器自带的 DoH、代理软件独立的 DNS 配置或直接指定 DNS 的程序,不一定遵循这些规则。
- 代理劫持仍可能改变实际路径。 如果 sing-box TUN 或防火墙规则截获 53 端口,需要结合其规则与抓包结果检查。
- 运行时配置可能需要重设。 单独重启 systemd-resolved 或其他网络管理工具重写接口 DNS 后,检查
resolvectl status,必要时重新执行三条命令。
若无法解析,先检查路由及服务状态:
ip route get 198.51.100.53
resolvectl status wg0
journalctl -u systemd-resolved -n 50 --no-pager
同时确认隧道对端的 DNS 监听地址及防火墙允许来自客户端的 UDP/TCP 53 查询。若之前使用过额外的 DNS 转发方案,应先移除其冲突配置,例如指向本机其他端口的全局 DNS。
参考文档
- systemd-resolved:查询路由规则
- resolved.conf:全局 DNS 与路由域
- resolvectl:接口 DNS、domain 与 default-route
- WireGuard 官方 wg-quick 手册
不同发行版的软件版本及默认网络管理器可能不同,部署时可结合本机 man resolvectl、man resolved.conf 和 man wg-quick 核对。
补充:Debian 不使用 WireGuard 时的 DNS 分流
内网 DNS 可以直接通过 Debian 的网卡访问时,把路由域设在该网卡上。以下用 eno1 举例。
| 查询域名 | 上游 DNS |
|---|---|
home.arpa、example.com 及其子域名 | 192.0.2.53 |
| 其他域名 | 192.0.2.1 |
安装并配置 systemd-resolved
先用 ip route get 192.0.2.53 查看输出中的 dev,然后用实际接口名替换下文的 eno1。
如果 Debian 12 或 13 提示 resolvectl: command not found,可安装 systemd-resolved。该包会接管 /etc/resolv.conf,先备份当前配置。已经在使用 systemd-resolved 时可跳过安装。参见 Debian 12 软件包说明和 Debian 13 软件包说明。
sudo cp -L /etc/resolv.conf /etc/resolv.conf.before-resolved
sudo apt install systemd-resolved
创建 /etc/systemd/resolved.conf.d/,在其中的 90-split-dns.conf 写入:
[Resolve]
DNS=
DNS=192.0.2.1
Domains=
Domains=~.
应用全局配置,再设置当前接口的 DNS 路由域:
sudo systemctl restart systemd-resolved
sudo resolvectl dns eno1 192.0.2.53
sudo resolvectl domain eno1 '~home.arpa' '~example.com'
sudo resolvectl default-route eno1 no
~home.arpa 和 ~example.com 比全局的 ~. 更具体,因此优先匹配。用 resolvectl status 检查其他接口是否也配置了相同或更具体的路由域,以及 eno1 是否只有预期的内网 DNS。
持久化并保留 IPv6
以上三条接口命令修改的是运行时状态。若使用 systemd-networkd,用 networkctl status eno1 查看 Network File。例如文件叫 10-eno1.network,就在 /etc/systemd/network/10-eno1.network.d/90-split-dns.conf 写入:
[Network]
DNS=
DNS=192.0.2.53
Domains=
Domains=~home.arpa ~example.com
DNSDefaultRoute=no
[DHCPv4]
UseDNS=no
UseDomains=no
[DHCPv6]
UseDNS=no
UseDomains=no
[IPv6AcceptRA]
UseDNS=no
UseDomains=no
执行 sudo networkctl reload,再用 resolvectl status eno1 确认生效。上述设置只过滤 DHCP 和 IPv6 RA 下发的 DNS 服务器及域名,IPv6 地址和路由仍由现有配置决定。IPv4 地址的 DNS 服务器也能返回 IPv6 的 AAAA 记录。参见 systemd.network 手册。
若使用 ifupdown,在 /etc/network/interfaces 中保留实际的静态地址、掩码和网关,并将三条 post-up 放到现有的 iface eno1 inet static 段。以下是完整示例。
auto eno1
iface eno1 inet static
address 192.0.2.25
netmask 255.255.255.0
gateway 192.0.2.1
post-up resolvectl dns "$IFACE" 192.0.2.53
post-up resolvectl domain "$IFACE" '~home.arpa' '~example.com'
post-up resolvectl default-route "$IFACE" no
已有 auto eno1 或 allow-hotplug eno1 时,保留原有的启动声明。全局默认 DNS 已由 resolved.conf.d 设置,请删除该接口段中原有的 dns-nameservers 行,以免 resolvconf 钩子再次注册接口 DNS。gateway 负责 IP 默认路由,resolvectl default-route 控制 DNS 的默认选择。
如果还有其他服务向 systemd-resolved 注册 DHCP 或 RA 学到的 DNS,需在对应服务中关闭自动 DNS 或调整其配置,再检查实际生效的接口 DNS 列表。
验证
把 nas.home.arpa 换成内网中实际存在的记录。如果该域名未配置 AAAA,用公网查询验证 IPv6 记录解析,并通过内网的 A 记录验证分流。
resolvectl status
resolvectl query --type=A nas.home.arpa
resolvectl query --type=AAAA nas.home.arpa
resolvectl query --type=AAAA www.debian.org
如果还需要确认发包目标,先执行 sudo resolvectl flush-caches,再边查询边抓包:
sudo tcpdump -ni any 'port 53 and (host 192.0.2.53 or host 192.0.2.1)'