← 返回笔记列表
● 运维 · IPv6

IPv6 开关实录:关掉,再打开

这台 VPS 的 IPv6 被关过一次,后来又打开了。两次操作都踩到同一个坑:改 IPv6 时 SSH 会掉。 文章记录当前实际参数、两次切换的完整步骤,以及那个掉线的原因。

当前的 IPv6 参数

项目值
地址2602:f656:101:18::e129:7f20
前缀长度/48(2602:f656:101::/48)
默认网关2602:f656:101::1(on-link)
链路本地地址fe80::5054:ff:fe5c:7d0b/64
配置方式静态,写在 /etc/network/interfaces
网卡 / MTUens3 · 1500
DNS8.8.8.8 · 1.1.1.1(rotate)
状态disable_ipv6 = 0,双栈监听 80 / 443

关闭时做了什么

cat > /etc/sysctl.d/99-disable-ipv6.conf <<'EOF'
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF

sysctl -w net.ipv6.conf.all.disable_ipv6=1
sysctl -w net.ipv6.conf.default.disable_ipv6=1
sysctl -w net.ipv6.conf.lo.disable_ipv6=1

效果是立刻的:ip -6 addr 里的全局地址与默认路由消失,curl -6 会报 Cannot assign requested address,IPv4 完全不受影响。

重新打开时踩的坑

直觉是把 sysctl 设回 0 就完事,但地址不会自己回来 —— disable_ipv6=1 只是移除了地址, ifupdown 的"已配置"状态还停在旧值,所以把 sysctl 放开之后必须手动补地址与路由, 否则 ip -6 addr 依旧是空的:

rm -f /etc/sysctl.d/99-disable-ipv6.conf
sysctl -w net.ipv6.conf.all.disable_ipv6=0
sysctl -w net.ipv6.conf.default.disable_ipv6=0
sysctl -w net.ipv6.conf.lo.disable_ipv6=0
sysctl -w net.ipv6.conf.ens3.disable_ipv6=0

# 补回静态地址与默认路由(不要 ifdown/ifup,会把 IPv4 一起断掉)
ip -6 addr add 2602:f656:101:18::e129:7f20/48 dev ens3
ip -6 route add default via 2602:f656:101::1 dev ens3

地址加进去后会短暂处于 tentative 状态(DAD 重复地址检测),几秒后变成 preferred 才开始转发。验证标准是三条:

ip -6 addr show ens3          # 出现 inet6 ... scope global preferred
ping -6 -c2 2602:f656:101::1  # 网关 0% 丢包
curl -6 -s -o /dev/null -w '%{http_code}\n' https://www.cloudflare.com/cdn-cgi/trace   # 200

重启后无需手动干预:/etc/network/interfaces 里的 iface ens3 inet6 static 会在 auto ens3 拉起时一起配置。

为什么每次切换 IPv6 都掉 SSH

查看连接后发现关键细节:SSH 会话是由 sshd 的 [::]:51439 双栈套接字接受、 以 v4-mapped 形式承载的 IPv4 连接(ss -tnp 里对应 sshd fd=4, 对端显示为 207.57.74.47:57590)。

一旦 disable_ipv6 被改写,内核会重置这批双栈套接字上的连接 —— 于是 IPv4 的 SSH 跟着断。 这跟"IPv6 关掉会影响 IPv4"没关系,纯粹是套接字族的问题。

下次要在生产机上动 IPv6,先把 sshd 收敛到只监听 IPv4(AddressFamily inet 或显式 ListenAddress 0.0.0.0),再操作;或者直接用云厂商的 VNC 控制台兜底。

域名侧:AAAA 记录

机器开启双栈只是第一步,域名解析里还必须有一条 AAAA 记录,客户端才会尝试 IPv6:

speedtest.heodiy.com.   A     207.57.74.47
speedtest.heodiy.com.   AAAA  2602:f656:101:18::e129:7f20

只有 A 记录时,curl -6 与浏览器都会直接走 IPv4; 想强制验证 IPv6,可以不经过 DNS,直接命中字面量地址:

curl -k -H 'Host: speedtest.heodiy.com' -o /dev/null \
     -w '%{http_code}\n' 'https://[2602:f656:101:18::e129:7f20]/st/ping.txt'
证书注意:Let's Encrypt 证书只覆盖域名,直接用 IPv6 字面量访问会有名称不匹配告警, 用 -k 跳过即可;正常通过域名访问不受影响。