手机显示隧道已连接,客户端也报告了一个私有地址,可第一个页面仍然卡在加载中途。这种组合常把大多数人引向加密设置和 CPU 温度,而那里其实没有任何问题。隧道已经建立,说明协商完成了;失败的是下一步,服务器把客户端的数据包交给互联网。沿着这些数据包走过的同一条路径排查,问题通常就明明白白写在一行 NAT 表里。

从客户端能到达和不能到达的地方入手

在已连接的客户端上打开一个公网页面,留意它是立刻失败还是中途卡住。然后打开 VPN 服务器自身私有地址上的资源,比较两种结果。

公网站点超时、隧道地址却能响应 ping,这是转发或地址转换问题的特征,而不是握手坏了。客户端自带的状态面板无法区分这两种情况,因为它只知道控制通道是通的。在服务器上用下面的命令检查隧道接口:ip -br addr show tun0,并确认分配给客户端的地址落在你配置的地址池内。如果地址池和客户端地址不一致,先修正它,因为下面的每条规则都按地址池匹配。

接着问服务器:它要用哪个接口才能到达一个公网地址。ip route get 203.0.113.9 会在第一行打印选中的设备和源地址。把这个设备名记下来,因为 NAT 规则里必须写它。

读懂决定数据包能否离开的那条规则

只有当数据包从规则中指定的接口离开时,MASQUERADE 才会改写它。限定在以太网设备上的规则对走 Wi-Fi 出去的流量毫无作用,数据包会一路带着私有源地址直到上游路由器。那台路由器没有回到你隧道地址池的路由,于是丢弃回程数据包,客户端看到的就是连接建立后立刻死掉。症状的轻重取决于页面在需要第一次回包之前已经到了多少。

列出活动表,读 out-interface 列,而不是只搜 MASQUERADE 这个词。追加形式的输出比格式化清单更容易对照:

ip -br addr show tun0
ip route get 203.0.113.9
sudo iptables -t nat -S POSTROUTING

在一台曾经用有线、现在用 Wi-Fi 的树莓派上,过时的设备名几乎就是全部原因。安装程序记录的是装机时存在的设备,保存的规则集每次开机都会重放它。在改动别的之前,先拿路由查询得到的设备名和规则里的设备名做对比。两者一致,接口就不是你的问题,应当跳到最后一节的计数器。两者不同,修法就是在持久化文件里改一个词。

修正保存的规则集,而不只是正在运行的那份

只改活动表,撑到下一次重启就失效,而这恰好长到足以让你相信问题已经解决。开机时回来的规则住在防火墙持久化包会重新加载的文件里。在基于 Debian 的树莓派镜像上,这个文件通常是 /etc/iptables/rules.v4。

动手前先备份,然后把 MASQUERADE 行里的 out-interface 改成你记下的设备,例如把 -o wlan0 换成 -o eth0。保留源地址范围不变,除非客户端地址池变了。重新加载,并确认规则现在指向正确的设备:

sudo cp /etc/iptables/rules.v4 /root/rules.v4.bak
sudo iptables-restore < /etc/iptables/rules.v4
sudo iptables -t nat -L POSTROUTING -v -n

相邻的两个设置很容易被忘掉。sysctl net.ipv4.ip_forward 必须报告 1,上游路由器也不能自行过滤私有源地址。

证明规则确实命中,再分离出还慢在哪里

计数器是规则命中与否唯一诚实的证据。先跑详细清单,在客户端发起下载,再跑一次。规则旁边的包和字节列应该上涨,始终为零的规则仍然没有命中。如果计数器在动但页面还是失败,用下面的命令把源范围与实际地址池对照 grep -n "^server " /etc/openvpn/server.conf。如果计数器在动、页面也能打开,但吞吐很差,说明转换已经完成,剩下的问题在别处。

从同一客户端比较两次传输:一次到局域网内的主机,一次经隧道到同一台主机。两种都慢,指向的是树莓派的上行链路或 Wi-Fi,而不是 VPN。只有经隧道才慢,指向 MTU 与重传,可以用下面的命令查看 ip -s link show tun0,再改动任何加密设置。

要撤销这次实验,把备份还原并重新加载,再确认原规则和它的计数器都回来了。把出口设备和重新加载命令写进服务器笔记,因为下一次上行链路变更会再次发现同一个不一致。指向错误设备的规则,在流量真正用到它之前一直隐形。

相关文章