将 VPN 服务器迁移到新的公网 IP:首先该检查什么
就地更换与并行切换的故障点不同。先检查配置、NAT 与证书,再确认每个客户端如何解析该名称。
重新分配一个地址只需一分钟。问题往往出现在接下来的一周,而且很少在服务商控制台提示的那个位置。新的公网 IP 会在四个地方被引用:守护进程监听的套接字、客户端校验的信任锚、每一条点名旧地址的规则,以及把它们串起来的 DNS 记录。两种迁移从控制面板上看完全一样,行为却截然不同:在你自己运维的机器上重新分配地址,或者另起一个端点并把客户端迁过去。下面的检查把代价低的故障排在前面,每一节都会说明它适用于哪种迁移。
就地更换与并行切换是两件不同的事
就地更换保留主机、密钥、路由表和用户列表,只有地址改变。浮动 IP 的重新分配就是如此,在不少服务商那里访客根本察觉不到,因为地址转换发生在实例之前。重建或由服务商重新分配则更粗暴:访客能看到变化,所有缓存了旧值的东西会在同一刻得知。
并行端点是承担同样工作的第二台主机。把它建起来,用一个配置文件测试,让旧端点继续应答,直到新端点在实际路径上证明自己。代价是状态。没有共享的对等体记录、吊销和日志,你得到的是两个恰好同名的网络。
| Question | In-place swap | Parallel endpoint |
|---|---|---|
| Rollback in one step? | Only if you can get the old address back | Point DNS back; old host still up |
| Blast radius | Every client at once | Only the clients you moved |
| Best when | The address is yours to reassign | The old address is gone for good |
找出旧地址被写下的每一处
先从文本扫描开始,因为配置文件是容易的一半。搜索守护进程配置、防火墙片段、监控目标以及磁盘上任何生成的客户端包。如果你发布了 IPv6 地址也要一并搜索;只跟随 A 记录的迁移会把双栈客户端留在旧路径上。
OLD=203.0.113.10
grep -RIn -- "$OLD" /etc /root
ss -lunpt | grep -F "$OLD"
nft list ruleset | grep -F "$OLD"
iptables-save | grep -F "$OLD"
wg show all endpoints
然后扫内核,因为运行中的系统会把地址保存在任何文件都没有提到的位置。静态源 NAT 规则、ipset 条目、绑定地址和 conntrack 条目比删掉它们的配置修改活得更久,有些还能熬过重启,因为它们从保存的规则集里回来了。再往上一层,服务商的安全组、负载均衡目标和监控检查根本不在你的文件系统里。
在改动任何东西之前先把清单写下来;它同时可以当作回滚脚本。
用主机名的客户端会自行恢复;用字面 IP 的客户端则会静默失效
如果客户端通过主机名访问服务器,切换主要是 DNS 问题,而你昨天设置的 TTL 决定了它会有多糟。解析器会缓存,stub 解析器还会再缓存一层,许多客户端只在新连接时查询名字,因此已建立的隧道会保留起始地址。
如果端点是一个字面地址,就什么都不会重新解析,也不会有人记录抱怨。WireGuard 保存的是解析后的套接字地址:Endpoint = vpn.example.net:51820 在 wg-quick up 运行的那一刻变成 IP,并在你修改之前一直保持这个 IP。OpenVPN 更宽容:它在连接时解析 remote 主机名,并且在配置了 resolv-retry infinite 时会在重连时再次尝试 DNS。给定字面 IP,两者都会继续拨打一台已不存在的机器。
真正误导人的是镜像情形。一个已经指向新地址的客户端,在旧监听仍应答时,会通过你在自己桌面上做的每一次测试。我也上过这个当:新端点在手机上一次就通了,而一个使用旧配置的客户端,直到很久之后关掉旧监听才暴露出来。
信任并不随地址一起迁移
WireGuard 把身份与可达性分开,这使得地址迁移几乎免费。对等体由公钥识别,端点只是数据包当前去往的地方;主机会根据最近一次通过认证的数据包源地址更新对等体的端点。空闲的对等体仍然需要一个理由去和新位置通信,而它只有在会话老化、握手重试在某个可见位置失败之后才会学到地址。WireGuard 快速入门涵盖了端点字段。
基于 TLS 的服务器则是相反的情形。证书绑定在名字上,而按地址拨号的客户端会把自己拨的地址与主体备用名称比较。用 IP 连接一张只带 DNS SAN 的证书,校验就会失败:客户端使用的名字不在证书里。改用 IP SAN 重新签发能修好那一次连接,却让下一次迁移更糟。在配置里保留主机名、并让 verify-x509-name 保持原样,能在底层地址变化时让校验保持严格。
接着检查守护进程绑定在哪里;钉在旧地址上的套接字会静默失败。以 local 203.0.113.10 启动的 OpenVPN 服务器在该地址消失后就拒绝启动,而监听在 0.0.0.0 上的进程则免费跟随变化。NAT 也以同样的方式分裂:MASQUERADE 会跟随机器当前的地址,而静态的 SNAT --to-source 203.0.113.10 会继续把地址改写成你已不再拥有的那个,于是回程流量消失。如果新地址伴随不同的上游网关,检查 rp_filter:反向路径过滤会丢弃从内核未曾预期的接口进来的回程流量。
切换顺序以及它确实生效的证据
提前一天降低 TTL,搭起新的监听,并用一份只有你持有的配置来证明它。从同一网络内部做的测试几乎证明不了什么,所以用一部蜂窝网络的手机,测试隧道本该承载的东西,而不是对端点做 ping。
在整个窗口期内观察两个地址。新主机上的 wg show all latest-handshakes,或 OpenVPN 的状态文件,会告诉你实际有多少对等体迁移过来。当新端点拥有你预期的对等体、旧端点只剩掉队者时,让旧监听退役、删除过期的 NAT 规则,并把地址从服务商防火墙里移除。删除旧监听是最常被跳过的一步,它堵上了旧配置仍能到达旧网络的那个缺口。
在开始前把回滚触发条件写下来:如果在约定窗口之后新端点没有任何一个真实客户端的握手,就恢复旧地址并停止分发配置。之后重跑扫描,确认没有监听仍绑定在已退役的地址上。有两样东西会带到下一次迁移:客户端配置里的主机名,让下一次变更只是一次 DNS 编辑;以及存放在服务器恢复笔记旁边的清单。