在宿主机上还是虚拟机内运行 VPN?决策手册
隧道的归属决定覆盖范围。选择宿主机或客户机放置方式,然后用客户机内的路由、DNS 和出口检查来确认。
在客户机内建隧道和在宿主机上建隧道都会改变浏览器报告的地址,而相似之处也到此为止。客户机自有的隧道把密钥、默认路由和解析器都留在客户机内核里,宿主机只是把加密包转发到一个远端地址。宿主机自有的隧道正好相反:宿主机上的客户端持有会话并应用路由和策略,客户机借用的只是出去的结果。选错归属,之后每一个症状都会把你带到错误的机器上。两条命令大约一分钟就能定论,本手册剩下的部分就是拿到答案后该做什么。
在碰客户端之前先定归属
规则关心的是密文在哪里产生,而不是哪台机器显示 VPN 图标。如果密文由客户机产生,客户机只需要一条能通到 VPN 服务器的路由,不需要宿主机提供别的。如果密文由宿主机产生,客户机就必须让经宿主机的这条路活下来,无论宿主机客户端对本地流量施加什么策略。
三个问题通常就替你选定了放置位置。客户机的流量是否需要穿过宿主机上的企业客户端?那就把隧道放在客户机里。多个客户机是否需要共用一个凭据和一个出口地址?那就放在宿主机上,并刻意配置转发。客户机的流量是否应当完全不出宿主机 VPN?那就只有客户机内的隧道能在结构上做到这一点。
把答案写在 VM 名字旁边的一行里:guest-owned 或 host-owned。在六台机器的实验环境里,这行笔记比下面任何一步都省时间,因为它能阻止你去排查一条根本不在你登录的那台机器里的隧道。
WSL1 与 WSL2 是相反的两个例子
WSL1 不是虚拟机,所以放置问题基本消失。它的 Linux 二进制通过一个翻译层跑在 Windows 网络栈上,Linux VPN 客户端没有可独立配置的接口。真正有效的是 Windows 一侧的隧道,发行版只使用结果而什么都不拥有。
WSL2 恰恰相反。它在一个 Hyper-V 虚拟交换机后面的轻量工具 VM 里跑真正的内核,地址空间通过宿主机侧的适配器做 NAT。所以发行版内的 Linux 客户端行为就像在物理 Linux 机器上:它创建 tun0 或 wg0,装自己的路由,然后正常工作。故障出在宿主机一侧。当 Windows 的 VPN 客户端以阻止本地网络流量的策略连接时,它会把 WSL2 子网当成不可信的本地网络,切断 NAT 通路。于是发行版丢掉 DNS 和外网访问,而它自己的隧道还是好的:wg show 报告握手,ip route 看着正常,curl 却卡住。
能用哪种修法取决于 Windows 版本。较旧的一种是在宿主机客户端里为 WSL 子网加例外,加在客户端的本地网络或分割隧道设置下面。较新的一种,在支持它的 Windows 11 版本上,是镜像网络:把 networkingMode=mirrored 放进 %UserProfile%\.wslconfig 的 [wsl2] 段,运行 wsl --shutdown,发行版就会共享宿主机的接口,而不是用一个私有 NAT 子网。镜像模式还会改变 localhost 和入站端口的行为,所以应当把它当成一次迁移而不是一个开关。
NAT、桥接,以及宿主机能看到什么
在 NAT 之下,客户机的隧道包被送到 VPN 服务器的公网地址,并以加密的 UDP 或 TCP 从宿主机适配器出去。宿主机只能看到一个流和它的字节数,看不到里面去了哪里。在桥接适配器之下,客户机在物理 LAN 上有自己的第 2 层身份,自己拿 DHCP 租约,对任何基于 MAC 的策略来说都像第二台设备。两种模式都不让宿主机读隧道载荷;桥接的客户机只是对周围的网络显眼得多。
隔离也有下限。客户机躲不开拥有它内存的那台机器,控制宿主机的人可以从客户机内存里读密钥。客户机隧道给你的是路由边界和恶意软件边界,而不是对拿着笔记本那个人的防护。文档里的适配器模式在选择时值得开着,因为模式同时改变宿主机看到什么和 LAN 看到什么。
手册:放置、配置、证明
在新的客户机 shell 里按顺序跑这四项检查,遇到第一个与所记归属不符的就停下来。
ip route get 1.1.1.1返回tun0或wg0表示归客户机;返回带私有下一跳的eth0表示归宿主机。resolvectl query example.com,或在客户机不跑解析服务的地方读/etc/resolv.conf。只带流量不带 DNS 的隧道,是最常见的半配置状态。- 比较出口:客户机里跑
curl -4 -s https://ifconfig.me,宿主机上跑curl.exe -4 -s https://ifconfig.me。地址不同说明客户机拥有隧道;宿主机在 VPN 上而客户机显示家庭运营商,就是什么都没继承到的那种情况。 - 用
-6把两者各再跑一遍。只有 v4 的隧道会漏 v6,除非客户端封掉或路由它,而不少客户端默认把 v6 留在物理接口上。
在多个客户机共用一个隧道的宿主机网关方案里,宿主机必须转发和翻译。Linux 宿主机上这是三块,缺任何一块客户机都会悄悄退回普通路由:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
iptables -A FORWARD -i virbr0 -o wg0 -j ACCEPT
iptables -A FORWARD -i wg0 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
WireGuard 这边,宿主机对端的 AllowedIPs 必须包含客户机子网,例如 192.168.122.0/24,否则回程包永远到不了,整套配置看起来像是防火墙问题。Windows 宿主机可以用 Internet 连接共享或 Hyper-V 交换机上的 NAT 规则取得同样结果,同样需要检查回程路径。
在布局还没定的时候,这张表覆盖最常出现的情况:
| Situation | Owner | Check first |
|---|---|---|
| One VM, host also on a corporate VPN | Guest | Does the host client block local networks? |
| Six lab VMs, one exit address | Host plus forwarding | ip_forward, NAT rule, server AllowedIPs |
| Malware or research VM | Guest, NAT | Snapshot age and resolver state |
| Bridged VM on an office LAN | Guest | DHCP lease and port security |
两条隧道、两个客户机,以及它们之间的冲突
需要同时有两个出口时,站得住的做法是一个客户机一条隧道。每个 VM 保留自己的默认路由和解析器,宿主机留在普通网络上,两条隧道永远不会争同一张路由表。把两个客户机桥接在一起也不会合并它们的路由:虚拟网络提供的是一条路,仍然要告诉每个客户端这段本地流量可以绕过隧道。
同时跑一条宿主机隧道和一条客户机隧道是正当的,刻意嵌套有时正是你要的——客户机从自己的隧道出去,那条隧道再从宿主机的隧道出去。把它变成故障的,是没人写清楚哪个端点该从哪一层到达。维护一张两列的表,写清目的和归属,路由冲突就变成一次查表,而不是一下午的摸查。
验证,然后把恢复留在归属方手里
从客户机内部测试,用新的应用进程:流量、名字解析、两个地址族,以及隧道断开时会发生什么。宿主机的 VPN 图标对客户机的覆盖什么也说明不了,这也是这一整块里最常见的假确认。
恢复同样归归属方。客户机自有的隧道由客户机自己的客户端和它写下的路由恢复。宿主机自有的方案由宿主机的启动顺序恢复,转发规则不会熬过重启,除非有 unit 或启动任务重新应用它们。恢复的快照是一次部署而不是撤销,因为它连同磁盘一起把旧凭据和旧路由带回来。在宣布活儿干完之前,确认归属仍与写下的一致,DNS 和两个地址族在客户机内能解析,死掉的隧道留下的是可用的网络而不是黑洞,并且重启或快照恢复能复现同样的状态。