[f44] kvm qemu vm 直通宿主机的 tailscale exit-node
05 Sep, 2026 10:17 PM +08:00
全文由 Gemini 3.8 Flash 生成。
将虚拟机流量通过宿主机的 Tailscale Exit-Node 导出,最稳定、免维护的方案是在宿主机侧完成所有转发与 MSS 钳制。这样无论新建多少台虚拟机,虚拟机内部无需安装 Tailscale,也不需要每次手动修改 MTU。
核心架构
-
虚拟机:保持默认 NAT(
192.168.122.0/24),默认网关指向宿主机。 -
宿主机:开启内核转发、放宽反向过滤(
rp_filter)、开启tailscale0接口的 NAT 伪装、通过 firewalld 开启跨区转发与 TCP MSS 钳制(规避 1280 MTU 黑洞)。
第一步:宿主机内核与系统参数(永久生效)
在宿主机上创建 sysctl 配置文件,放行数据转发并防止路由非对称丢包:
sudo tee /etc/sysctl.d/99-tailscale-kvm.conf << 'EOF'
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
EOF
# 立即应用配置
sudo sysctl --system
第二步:宿主机防火墙策略(firewalld)
在宿主机配置 firewalld,完成网卡分配、NAT 伪装、跨区域放行和 MTU 钳制:
# 1. 将 tailscale0 划入 trusted 区域并开启 NAT 伪装
sudo firewall-cmd --permanent --zone=trusted --add-interface=tailscale0
sudo firewall-cmd --permanent --zone=trusted --add-masquerade
# 2. 建立转发策略:允许 libvirt 网桥 (virbr0) 流量流向 trusted 区域 (tailscale0)
sudo firewall-cmd --permanent --new-policy=libvirt-to-tailscale
sudo firewall-cmd --permanent --policy=libvirt-to-tailscale --add-ingress-zone=libvirt
sudo firewall-cmd --permanent --policy=libvirt-to-tailscale --add-egress-zone=trusted
sudo firewall-cmd --permanent --policy=libvirt-to-tailscale --set-target=ACCEPT
# 3. 核心:开启 TCP MSS 钳制,自动将数据包限制在 Tailscale 的 1280 MTU 内(防止 TLS 握手卡死)
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
# 4. 重载防火墙
sudo firewall-cmd --reload
第三步:宿主机 Tailscale 启动参数
宿主机连接 Exit-Node 时,必须带上 --exit-node-allow-lan-access=true,否则 Tailscale 会阻断一切局域网/网桥的转发流量:
# 将 <EXIT_NODE_NAME_OR_IP> 替换为你的目标出口节点(例如 mdev)
sudo tailscale up --exit-node=<EXIT_NODE_NAME_OR_IP> --exit-node-allow-lan-access=true --accept-routes=true
如果更倾向于直接固定虚拟机的 MTU,Fedora 虚拟机通过 NetworkManager 管理网络:
在虚拟机执行:
# 查看当前活跃连接名(通常如 'Wired connection 1' 或网卡名)
nmcli connection show --active
# 将其 MTU 设为 1280 并重新连接(替换 "Wired connection 1" 为实际名字)
sudo nmcli connection modify "Wired connection 1" 802-3-ethernet.mtu 1280
sudo nmcli connection up "Wired connection 1"
验证:运行 ip link show,确认虚拟机重启或重连后网卡 MTU 依然保持为 1280。
第四步:虚拟机内配置(只需处理 DNS)
得益于宿主机开启了 MSS 钳制,虚拟机网卡保持默认的 1500 MTU 即可正常通信。但由于宿主机启用了全局出口节点,虚拟机的默认 DNS 可能无法解析,建议将虚拟机 DNS 改为公共 DNS:
Bash
# 在虚拟机内执行:配置为公共 DNS(以实际网卡名 enp1s0 为准)
sudo resolvectl dns $(ip -o -4 route show to default | awk '{print $5}') 1.1.1.1 8.8.8.8
# 验证网络与外网出口
curl -I https://www.google.com
curl -s https://ifconfig.me # 应显示 Exit-Node 的公网 IP
快速排错清单
-
虚拟机 ping 不通宿主机网桥:检查宿主机
sysctl net.ipv4.ip_forward是否为1。 -
能 ping 通 IP 但打不开网页、
curl -v卡在 TLS 握手:检查宿主机防火墙直连规则中的--clamp-mss-to-pmtu是否已生效(sudo firewall-cmd --direct --get-all-rules)。 -
报错
Could not resolve host:虚拟机内部 DNS 没配好,使用resolvectl status确认当前 upstream DNS 是有效的外部 IP(如1.1.1.1)。