WireGuard 中继节点转发排查
这次网络故障的表现很怪:VPS 能 ping 通家里的 OpenWrt,OpenWrt 也能 ping 通 VPS;我的 Fedora 电脑同样能 ping 通 VPS,但就是 ping 不通 OpenWrt。
最后发现不是 WireGuard 握手、路由或 OpenWrt 本身的问题,而是 VPS 上一条历史遗留的转发规则把 WireGuard peer 之间的流量直接丢掉了。删掉旧规则、改成显式允许同接口转发后,问题解决。
这篇把排查过程写下来。这个场景适合一个 VPS 作为 WireGuard 中继,多个客户端通过同一个隧道网段互访的组网。
环境
拓扑如下:
Fedora 电脑10.0.0.3 │ │ WireGuard ▼VPS 中继10.0.0.1wg-nesoriel │ │ WireGuard ▼家中 OpenWrt10.0.0.20VPS 运行 Ubuntu 22.04,WireGuard 接口名为 wg-nesoriel,监听 UDP 51820。WireGuard 配置由宿主机的 wg-quick@wg-nesoriel.service 启动,WGDashboard 容器只负责管理配置和 peer。
客户端配置中,Fedora 到 VPS 的 peer 使用:
[Peer]AllowedIPs = 10.0.0.0/24Endpoint = <VPS 公网地址>:51820PersistentKeepalive = 21这意味着访问 10.0.0.0/24 的流量会进入 WireGuard 隧道。
现象
先分别测试三个节点:
# Fedora 电脑ping -c 2 10.0.0.1ping -c 2 10.0.0.20
# VPSping -c 2 10.0.0.20
# OpenWrtping -c 2 10.0.0.1当时结果是:
Fedora → VPS:通VPS → OpenWrt:通OpenWrt → VPS:通Fedora → OpenWrt:不通Fedora 上的路由是正确的:
ip route get 10.0.0.20输出类似:
10.0.0.20 dev wg-nesoriel src 10.0.0.3再看 tracepath:
tracepath -n -m 5 10.0.0.20第一跳能到 VPS 的 10.0.0.1,后续没有响应。这说明数据已经进入隧道并到达中继,问题应该在 VPS 转发路径或 OpenWrt 回程。
排查过程
确认 VPS 知道两个 peer 的去向
在 VPS 上查看 WireGuard 运行态:
sudo wg show wg-nesoriel关键是确认两个 peer 都存在,并且 AllowedIPs 没有重叠:
Fedora peer: 10.0.0.3/32OpenWrt peer: 10.0.0.20/32这一步决定 WireGuard 是否知道该把加密包交给哪个 peer。VPS 可以 ping 通 OpenWrt,说明 10.0.0.20/32 的 peer 映射和握手本身没问题。
确认内核开启 IPv4 转发
sysctl net.ipv4.ip_forward预期结果:
net.ipv4.ip_forward = 1如果这里是 0,VPS 即使能分别与两个 peer 通信,也不会替它们转发三层流量。可以临时开启:
sudo sysctl -w net.ipv4.ip_forward=1长期配置应写到 /etc/sysctl.d/ 或发行版已有的网络配置中,再用 sysctl --system 加载。
本次故障里,IPv4 转发已经开启,所以继续检查防火墙规则。
检查 FORWARD 链,而不只看 UFW 列表
VPS 上执行:
sudo iptables-save | grep -E 'wg-nesoriel|FORWARD|10\.0\.0\.'发现了一条旧规则:
-A FORWARD -i wg-nesoriel -o wg-nesoriel -j DROP它的含义很直接:所有从 wg-nesoriel 进入、又需要从 wg-nesoriel 发出的包都被丢弃。
Fedora 到 OpenWrt 的流量正好符合这个条件:
Fedora peer → VPS wg-nesoriel → VPS FORWARD → VPS wg-nesoriel → OpenWrt peer因此 VPS 自己 ping OpenWrt 正常:本机发出的包走 OUTPUT,不经过 FORWARD。而客户端 peer 到另一个 peer 的包必经 FORWARD,所以失败。
这也是这个问题容易拖很久的原因:只做“客户端到服务器”和“服务器到客户端”的连通性测试,无法覆盖 peer-to-peer 转发路径。
根因
WireGuard 服务端的旧配置里曾经有下面的规则:
PostUp = ...; iptables -I FORWARD -i wg-nesoriel -o wg-nesoriel -j DROPPreDown = ...; iptables -D FORWARD -i wg-nesoriel -o wg-nesoriel -j DROP这类规则有时被用来禁止 VPN 客户端彼此访问。但当前需求是让 Fedora、OpenWrt 等 peer 经 VPS 中继互通,它与现有组网目标相反。
UFW 中虽然已经允许了:
Anywhere on wg-nesoriel ALLOW IN51820/udp ALLOW IN但这只解决了进入 VPS 的流量和 UDP 监听端口问题,不会覆盖被 iptables 明确 DROP 的同接口转发流量。
修复
修改前先备份 WireGuard 配置和当前规则:
stamp=$(date +%Y%m%d-%H%M%S)backup="/root/wireguard-forward-fix-$stamp"
sudo mkdir -p "$backup"sudo cp -a /etc/wireguard/wg-nesoriel.conf "$backup/"sudo iptables-save > "$backup/iptables.rules"先删除运行态中的旧 DROP:
sudo iptables -D FORWARD \ -i wg-nesoriel -o wg-nesoriel -j DROP然后允许新连接和已建立连接返回:
sudo iptables -I FORWARD 1 \ -i wg-nesoriel -o wg-nesoriel \ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -I FORWARD 1 \ -i wg-nesoriel -o wg-nesoriel \ -m conntrack --ctstate NEW -j ACCEPT不要只改运行态。wg-quick 重启后会重新执行 PostUp,旧规则可能回来。因此还要修改 /etc/wireguard/wg-nesoriel.conf:
[Interface]PostUp = iptables -t nat -I POSTROUTING 1 -s 10.0.0.1/24 -o eth0 -j MASQUERADE; iptables -I FORWARD 1 -i wg-nesoriel -o wg-nesoriel -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -I FORWARD 1 -i wg-nesoriel -o wg-nesoriel -m conntrack --ctstate NEW -j ACCEPTPreDown = iptables -t nat -D POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE; iptables -D FORWARD -i wg-nesoriel -o wg-nesoriel -m conntrack --ctstate NEW -j ACCEPT; iptables -D FORWARD -i wg-nesoriel -o wg-nesoriel -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT这里的 NAT 规则沿用原服务端配置。是否需要 NAT 取决于目标网段和回程路由;本例中保留它是为了不改变已经工作的对外访问行为。对 peer 之间互访,关键变化是删除 DROP 并允许同接口转发。
如果服务器使用的是 nftables 原生规则、firewalld 或云防火墙,应该按实际防火墙栈调整,不要把 iptables 命令直接套过去。
验证
先确认 VPS 上的规则顺序和计数器:
sudo iptables -nvL FORWARD | grep wg-nesoriel预期能看到:
ACCEPT ... wg-nesoriel → wg-nesoriel ... ctstate NEWACCEPT ... wg-nesoriel → wg-nesoriel ... ctstate RELATED,ESTABLISHED然后从 Fedora 测试:
ping -c 4 10.0.0.20本次结果:
4 packets transmitted, 4 received, 0% packet lossrtt min/avg/max ≈ 47/48/50 ms再确认服务和隧道状态:
sudo systemctl is-active wg-quick@wg-nesoriel.servicesudo wg show wg-nesoriel latest-handshakes最后检查重启后的持久性。维护窗口内可以重启 WireGuard 服务后重复 ping;如果不方便中断现网,至少确认 PostUp 和 PreDown 中已经不再包含旧 DROP 规则,并把这项测试放进下次维护清单。
总结
WireGuard 中继节点要让 peer 相互访问,需要同时满足:
客户端路由指向隧道+ 服务端 peer AllowedIPs 不重叠+ net.ipv4.ip_forward = 1+ FORWARD 链允许 wg-nesoriel → wg-nesoriel+ 目标 peer 的回程仍经 WireGuard这次故障的关键不是 WireGuard 本身,而是一个与现有需求相反的旧防火墙规则。排查时不要只验证“每台机器能否 ping VPS”;还要直接验证 peer 到 peer 的路径,并查看中继节点的 FORWARD 链和规则计数器。
把接口名统一为 wg-nesoriel 后,配置、服务名、监控和排查命令也更容易对应,不会再被历史命名拖进额外变量。