帮客户远程排查 Vultr WireGuard 无握手无法上网问题(完整实录)
前言
前几天,一位读者在微信上找到我,发来这样一条消息:
“你好,我按照你博客文章按流程操作了一下服务器,服务器防火墙也开了,但是手机修改端口还是没有握手提示,也上不了网,这是哪里出问题了吗?”

他参考的是我博客上的两篇文章:
按理说,如果再多参考一篇《WireGuard 自建 VPN 偶发不可用 全程复盘》,他应该也能自行解决。不过既然客户找上门,我就顺手帮他远程排查一下,也把整个过程完整记录下来,供遇到类似问题的朋友参考。
第一步:拿到服务器权限,开始排查
我向客户要了 SSH 登录信息,先看看服务器上到底什么情况。

登录后,首先检查 WireGuard 服务状态和当前生效的 iptables 规则。
1. 查看 WireGuard 状态
wg show
输出:
interface: wg0
public key: Mz1875giVsx4VO2HCLp2muoKPvxRzqaAskxpdHPkkWc=
private key: (hidden)
listening port: 51820
peer: oGifzA+TPY7W1AmqEc0R18Wv4dr/sFHguP7kCr81gX8=
preshared key: (hidden)
allowed ips: 10.66.66.2/32, fd42:42:42::2/128
peer: zFHZ//qIYRmK2rxO2JeZYON2JPo/Mni9J2kaeUIVfxk=
preshared key: (hidden)
allowed ips: 10.66.66.3/32, fd42:42:42::3/128
WireGuard 服务本身是正常的,有 peer 配置,监听 51820 端口,但没有 latest handshake(上次握手时间),说明手机根本没有与服务器完成握手。
2. 查看 PREROUTING 端口转发规则
iptables -t nat -L PREROUTING -n -v --line-numbers
输出:
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 330 59076 REDIRECT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpts:20000:60000 redir ports 51820
2 0 0 REDIRECT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpts:20000:60000 redir ports 51820
这里发现了两条完全相同的 REDIRECT 规则,有一条 pkts=0(从未被命中),这是之前重复执行命令导致的,不影响功能但不够干净。顺手删掉一条:
iptables -t nat -D PREROUTING 2
再次查看,只剩一条了:
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 330 59076 REDIRECT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpts:20000:60000 redir ports 51820
3. 保存规则
netfilter-persistent save
输出:
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
4. 确认 iptables-persistent 已安装
dpkg -l iptables-persistent
||/ Name Version Architecture Description
+++-===================-============-============-=====================================================
ii iptables-persistent 1.0.16 all boot-time loader for netfilter rules, iptables plugin
ii 表示已安装,没问题。
第二步:定位核心问题 —— INPUT 链默认 DROP
接下来检查 INPUT 链(入站流量过滤):
iptables -L INPUT -n -v --line-numbers
输出:
Chain INPUT (policy DROP 237K packets, 13M bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:54712
2 1009K 477M ufw-before-logging-input all -- * * 0.0.0.0/0 0.0.0.0/0
3 1009K 477M ufw-before-input all -- * * 0.0.0.0/0 0.0.0.0/0
4 237K 13M ufw-after-input all -- * * 0.0.0.0/0 0.0.0.0/0
5 237K 13M ufw-after-logging-input all -- * * 0.0.0.0/0 0.0.0.0/0
6 237K 13M ufw-reject-input all -- * * 0.0.0.0/0 0.0.0.0/0
7 237K 13M ufw-track-input all -- * * 0.0.0.0/0 0.0.0.0/0
问题找到了!
- INPUT 链默认策略是 DROP(丢弃所有入站流量)
- 当前只放行了
udp dpt:54712(可能是某个临时端口),没有放行 UDP 20000-60000 或 51820 - 虽然 Vultr 后台防火墙(截图4)已经正确放行了 UDP 20000-60000,但服务器内部的 iptables INPUT 链直接把包丢弃了

这就是手机始终无握手的根本原因。
修复:放行 UDP 20000-60000
iptables -I INPUT 1 -p udp --dport 20000:60000 -j ACCEPT
验证规则已生效:
iptables -L INPUT -n -v --line-numbers | head -5
Chain INPUT (policy DROP 237K packets, 13M bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpts:20000:60000
2 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:54712
3 1009K 477M ufw-before-logging-input all -- * * 0.0.0.0/0 0.0.0.0/0
第一条规则已经正确插入,优先放行。
保存规则
netfilter-persistent save
第三步:解决上网问题 —— IP 转发 + FORWARD + NAT
放行 INPUT 后,手机应该能完成握手了,但可能还无法上网(访问 Google 等)。还需要配置 IP 转发、FORWARD 链放通和 NAT 伪装。
开启 IP 转发
sysctl -w net.ipv4.ip_forward=1
grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf || echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
放通 FORWARD 链
iptables -P FORWARD ACCEPT
iptables -A FORWARD -i wg0 -j ACCEPT
iptables -A FORWARD -o wg0 -j ACCEPT
添加 NAT 伪装(SNAT/MASQUERADE)
让手机流量从服务器公网 IP 出去,才能访问外网。
自动获取公网网卡和 WireGuard 子网:
PUBLIC_IFACE=$(ip route | grep default | awk '{print $5}')
WG_SUBNET=$(grep -oP 'Address\s*=\s*\K[0-9.]+/[0-9]+' /etc/wireguard/wg0.conf 2>/dev/null | head -1 | cut -d/ -f1 | sed 's/\.[0-9]*$/.0\/24/')
WG_SUBNET=${WG_SUBNET:-10.0.0.0/24}
PUBLIC_IFACE=${PUBLIC_IFACE:-eth0}
iptables -t nat -A POSTROUTING -s ${WG_SUBNET} -o ${PUBLIC_IFACE} -j MASQUERADE
输出:
已添加 NAT 伪装 (子网: 10.66.66.0/24, 网卡: enp1s0)
保存所有规则
netfilter-persistent save
重启 WireGuard 服务
systemctl restart wg-quick@wg0
第四步:验证修复结果
查看 WireGuard 状态:
wg show
输出:
interface: wg0
public key: Mz1875giVsx4VO2HCLp2muoKPvxRzqaAskxpdHPkkWc=
private key: (hidden)
listening port: 51820
peer: zFHZ//qIYRmK2rxO2JeZYON2JPo/Mni9J2kaeUIVfxk=
preshared key: (hidden)
endpoint: 117.176.187.98:24535
allowed ips: 10.66.66.3/32, fd42:42:42::3/128
latest handshake: 1 minute, 4 seconds ago
transfer: 28.48 KiB received, 40.54 KiB sent
peer: oGifzA+TPY7W1AmqEc0R18Wv4dr/sFHguP7kCr81gX8=
preshared key: (hidden)
allowed ips: 10.66.66.2/32, fd42:42:42::2/128
latest handshake: 1 minute, 4 seconds ago —— 握手成功了!
手机端验证
我把自己手机上的 WireGuard 配置导入后,截图5显示:

- 上次握手时间:18 秒钟之前
- 接收:22.55 MiB,发送:4.17 MiB
流量已经在正常传输了。
然后打开浏览器访问 Google:

Google 正常打开,问题彻底解决!
问题根因总结
| 检查项 | 状态 | 说明 |
|---|---|---|
| WireGuard 服务 | ✅ 正常 | 监听 51820,有 peer 配置 |
| Vultr 后台防火墙 | ✅ 正确 | 已放行 UDP 20000-60000 |
| PREROUTING REDIRECT | ✅ 正确 | 将 20000-60000 重定向到 51820 |
| iptables-persistent | ✅ 已安装 | 规则可持久化 |
| INPUT 链放行 UDP 20000-60000 | ❌ 缺失 | INPUT 默认 DROP 导致握手包被丢弃 |
| IP 转发 (net.ipv4.ip_forward) | ❌ 未开启 | 无法路由 VPN 流量 |
| FORWARD 链放通 wg0 | ❌ 未配置 | 无法转发 VPN 数据包 |
| NAT 伪装 (MASQUERADE) | ❌ 未配置 | 手机流量无法从公网 IP 出去 |
核心问题: 客户只配置了 PREROUTING 重定向,但忽略了 INPUT 链的放行规则。虽然 Vultr 后台防火墙放行了端口,但服务器内部的 iptables INPUT 链默认策略为 DROP,直接把所有入站包丢弃了。
次要问题: 未开启 IP 转发和 NAT 伪装,导致即使握手成功也无法上网。
完整修复命令汇总
如果你也遇到类似问题(无握手、无法上网),在确保 PREROUTING 规则已配置的前提下,执行以下命令即可修复:
# 1. 放行 UDP 端口范围(解决 INPUT DROP 导致无握手)
iptables -I INPUT 1 -p udp --dport 20000:60000 -j ACCEPT
# 2. 开启 IP 转发
sysctl -w net.ipv4.ip_forward=1
grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf || echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
# 3. 放通 FORWARD 链
iptables -P FORWARD ACCEPT
iptables -A FORWARD -i wg0 -j ACCEPT
iptables -A FORWARD -o wg0 -j ACCEPT
# 4. 添加 NAT 伪装(自动获取网卡和子网)
PUBLIC_IFACE=$(ip route | grep default | awk '{print $5}')
WG_SUBNET=$(grep -oP 'Address\s*=\s*\K[0-9.]+/[0-9]+' /etc/wireguard/wg0.conf 2>/dev/null | head -1 | cut -d/ -f1 | sed 's/\.[0-9]*$/.0\/24/')
WG_SUBNET=${WG_SUBNET:-10.0.0.0/24}
PUBLIC_IFACE=${PUBLIC_IFACE:-eth0}
iptables -t nat -A POSTROUTING -s ${WG_SUBNET} -o ${PUBLIC_IFACE} -j MASQUERADE
# 5. 保存规则
netfilter-persistent save
# 6. 重启 WireGuard
systemctl restart wg-quick@wg0
避坑要点
- Vultr 后台防火墙 ≠ 服务器内部 iptables
后台放行端口只是“允许流量到达服务器网卡”,但服务器内部的iptables INPUT链仍然可能丢弃流量。务必检查INPUT链策略,如果是DROP,必须显式放行所需端口。 PREROUTINGREDIRECT 只做端口转换,不负责放行nat表的PREROUTING链在路由决策之前生效,但如果INPUT链丢弃了包,重定向后的流量仍然到不了 WireGuard 服务。- 手机上网需要 IP 转发和 NAT
如果手机需要访问外网(Google、ChatGPT 等),必须开启net.ipv4.ip_forward=1,放通FORWARD链,并添加MASQUERADE规则。 - 检查 WireGuard 配置文件中的子网
NAT 伪装时需要使用正确的子网(如10.66.66.0/24),否则流量无法正确路由。
结语
这位客户遇到的问题其实很典型:配置了端口转发,但忽略了入站放行和路由转发。在排查过程中,只需要一条一条检查 iptables 规则,就能快速定位问题。
希望这篇记录能帮到遇到类似问题的朋友。如果你也想自建 WireGuard VPN 但不想折腾,欢迎联系我获取专属解决方案。