被 CloudCone 强制换 IP 邮件支配的夜晚:说好的自动化无缝丝滑切换呢
收到 CloudCone 的邮件通知要换IPv4
今天收到 CloudCone 的邮件通知,提醒我机房正在进行 IPv4 的变更,我名下的服务器 IP 需要进行更换:

因为之前在其他服务商那里有过类似的换IP经验,通常流程非常自动化——在控制台确认切换后,服务器会自动做好临时映射,我进入系统确认无误后,在控制台选择重启即可。所以我是抱着轻松愉快的心情操作的,觉得是个几分钟就能搞定的小调整。

登录后台后发现,有两台部署了业务的 Ubuntu 24.04 服务器都在变更名单中(截图时我已经换了一台了)。

开始更换服务器的IPv4
按照面板的提示,这个过程是完全自动化的,只需要点击「Auto Configure New IP」按钮,系统就会自动为我配置服务器内的新IPv4地址,并且在48小时内,旧的IPv4地址和新的IPv4地址都可以使用。这还有啥好说的,看起来是个无脑点按钮的操作,我点。

很快啊,很快,页面就提示我
新的IPv4地址已经在你的服务器内部配置好,并且很快就可以访问。如果从外部
ping不通新IP,请尝试通过旧IP连入VPS,执行ping 103.232.95.1
行,那我先通过尚未失效的旧 IP 连接进 SSH,在系统内部对新网关 103.232.95.1 进行了测试:
ping 103.232.95.1
PING 103.232.95.1 (103.232.95.1) 56(84) bytes of data.
64 bytes from 103.232.95.1: icmp_seq=1 ttl=255 time=0.882 ms
网关响应正常,延迟很低。说明上游路由策略服务商已经下发。但当我尝试在本地直接用新 IP 建立新的 SSH 连接时,终端却还是无响应,最终提示超时:
ssh: connect to host 103.232.95.122 port 22: Connection timed out
从内部能 ping 通网关,但是外部 ping 不通也连不上,既然现在旧 IP 的SSH连接依然在,那我从内部往外 ping 就没啥意义,现在的感觉是系统内部有地方阻断了新 IP 的入站。诶,这就有点头秃了,趁着旧 IP 还有 48 小时的回收缓冲期,开始排查网络状态。
1. 排查服务器网卡路由:说好的自动化更换呢
首先那肯定是排查网卡怎么配置的。运行 ip route show 后,丝毫不意外呢:
default via 142.171.126.1 dev eth0 proto dhcp src 142.171.126.132
显示出来的只有旧网关,不是啥玩意啊,不是说自动换好 IP 了吗?我那么大的新 IP 去哪里了?得,还是要手动换,强行塞入新 IP(注意我的网卡名就是默认的 eth0, 请根据实际情况替换)先用 ip 命令绑个临时的配置试试水
# 给网卡绑上新IP
sudo ip addr add 103.232.95.122/24 dev eth0
# 把新网关也设置上
sudo ip route add 103.232.95.1 dev eth0
再运行ip route show看看情况
default via 142.171.126.132 dev eth0 onlink
default via 103.232.95.1 dev eth0 metric 10
103.232.95.0/24 dev eth0 proto kernel scope link src 103.232.95.122
142.171.126.132/26 dev eth0 proto kernel scope link src 142.171.126.132
我都不好吐槽 Ubuntu 这波算智能还是不智能了,新网关的路由虽然自动给我带了 metric 10,但原本由 cloud-init 生成的旧网关路由(via 142.171.126.132)并没有指定 metric 值啊。在 Linux 的缺省规则下,未指定 metric 的路由会是最高优先级(相当于 metric 0)。
这意味着当本地的连接请求到达新 IP 时,服务器尝试进行返回封包,但路由表强制将所有默认流量传给了旧网关。由于跨网段且上级链路已经变更,旧网关无法正确转发新 IP 的返回封包,导致网络表现为现在这样的状态,单向连通,外部连接超时。
明确原因后,首先在终端里删除旧的默认路由:
sudo ip route del default via 142.171.126.132 dev eth0
唯一的默认路由已正确指向新网关。按理说这时候 CloudCone 更换 IP 的系统层面操作就该结束了,可现实又给我浇了一盆冷水……在本地再次尝试 SSH 连接新 IP,依然提示超时。我去,这我就有点坐不住了,按说这时候服务器该配置的都配置了,为啥啊。
2. 外部依旧超时?原来是上级交换机 ARP 缓存延迟在作妖
现在网卡的路由正确却依旧无法连通,一般是意味着流量在进入服务器之前就被拦截了。
难道我之前设置了什么奇怪的安全配置?我又检查了UFW防火墙和iptables规则,诶,也没啥毛病呀。
我这时候突然想起来,我其实根本没试过能不能用新IP作为出入口访问外网呢。
于是直接ping 8.8.8.8 完犊子,超时了,这可咋整……
诶,之前自动切换完IP时,后台页面提示过我,「如果从外部ping不通新IP,请尝试通过旧IP连入VPS,执行ping 103.232.95.1」他这个操作是在做什么?激活网关?让网关知道我的存在?
灵光一闪,懂了,这应该是想让我手动刷新上级路由吧,这时候虽然新 IP 已经被分配了,但机房上级交换机的 ARP 缓存可能并没有实时刷新,导致流量进入上级路由后,上级路由还不知道 103.232.95.122 此时对应哪一台主机。
为了强制刷新上级路由,最直接的选择就是从服务器内使用 -I 参数,强行指定新 IP 作为源地址持续向外发送数据包,督促上级路由:
ping -I 103.232.95.122 8.8.8.8
前两分钟里,数据包全部超时,直到持续运行到大概第 3 分钟左右,终端开始接收到来自 8.8.8.8 的返回封包了。
经过2分多钟的由内向外的持续请求,终于成功触发了上级交换机的路由刷新。现在从本地电脑再次测试 SSH 连接新 IP,顺利登录。
3. 别指望自动化了,静态配置防止服务器重启后新 IP 失效
之前的改动都是通过 ip 命令临时生效的,如果此时直接重启,那配置就全部丢了。
由于CloudCone使用的是 cloud-init 动态接管,导致 /etc/netplan/ 目录下是空的,真实的动态配置文件躺在内存目录 /run/netplan/ 中。
为了让配置未来在重启后生效,需要写一个高优先级的静态配置文件:
sudo vim /etc/netplan/99-custom-config.yaml
将新 IP 和网关信息静态写入(我这里用的vim,你可以换成你喜欢的编辑器)。
network:
version: 2
renderer: networkd
ethernets:
eth0: # 注意替换为你实际网卡名称
dhcp4: no
addresses:
- 103.232.95.122/24
routes:
- to: default
via: 103.232.95.1
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
由于 Netplan 对权限有严格限制,顺手修改权限为 600 以免应用时弹出安全警告,随后正式应用配置:
sudo chmod 600 /etc/netplan/99-custom-config.yaml
sudo netplan apply
执行完毕无报错,运行 sudo reboot 重启服务器。
系统重启后,新 IP 依然能够秒连。
搞定,网络层面的切换就算全部完成啦。
总结与后续
这次换个 IP 如此折腾一次就踩了 Ubuntu Netplan 配置 和机房 ARP 缓存延迟 两个巨坑。
网络通了只是第一步,由于旧 IP 会在 48 小时内彻底失效,后续还需要迁移 Cloudflare 的 DNS 记录、更新 Docker 容器内部的网络绑定,以及修改第三方 API 和另一台服务器上 Telegram 机器人的 IP 访问白名单。明天起床再折腾吧,晚安。

