技术指南

WireGuard 大包卡住:定位 MTU 与 PMTU 黑洞

从握手成功但大传输卡住出发,用分档探测区分外层路径与隧道 MTU,再做单变量修正和可验证回滚。

WireGuard 已握手、短 ping 或小请求正常,但 SSH 交互停顿、HTTPS 上传下载卡住、文件只传一小段时,先验证是否存在按包大小触发的路径故障。不要直接抄一个 MTU 数字:要分别证明外层 UDP 路径、隧道接口和隧道内业务在哪个尺寸开始失败,再只调整拥有该封装边界的一层。

用现象先区分五条路径

观察优先解释下一步
没有近期握手,小包也不通端点、密钥、监听、防火墙或基础路由故障先恢复 WireGuard 基本连通,不进入 MTU 调整
小包双向成功,超过某一尺寸稳定失败PMTU、封装开销或 Packet Too Big 反馈异常固定地址族与方向,分档收敛失败边界
外层受控目标也在同一尺寸失败VPS 到端点之间的承载路径有更小 MTU核对云网络、上游隧道、PPPoE/VLAN 与 ICMP 返回路径
外层路径正常,只有 wg0 内层失败隧道接口 MTU 或嵌套封装预算不匹配临时降低一个接口,双向复测后再持久化
定长探测都成功,只有某个应用失败应用、代理、TLS、拥塞、重传或协议自身问题用真实业务请求取证,不把所有卡顿归因于 MTU

先保存接口、路由和握手现场

替换接口和隧道内对端地址;wg show 会暴露公钥、端点、流量和握手时间,按网络拓扑证据保护,分享前脱敏
tunnel=wg0
peer_inner=10.0.0.2
date --utc --iso-8601=seconds
uname -r
wg --version
ip -details link show dev "$tunnel"
ip -s link show dev "$tunnel"
ip route get "$peer_inner"
sudo wg show "$tunnel"
sysctl net.ipv4.tcp_mtu_probing

先确认失败流量确实经过预期接口。`ip route get` 输出的是内核解析后的单条路径;策略路由、网络命名空间、容器或应用绑定源地址时,应从实际发起请求的环境重复查询。近期握手只证明控制报文有往返,不能证明更大的隧道内数据包可用。

用总包长分档复现,而不是猜一个魔法值

数值只是低频诊断阶梯,不是推荐 MTU。这里按无 IPv4 选项/IPv6 扩展头的 ICMP Echo 计算:-s 是数据字节,另加 ICMP 8 字节和 IPv4 20 或 IPv6 40 字节头
target4=10.0.0.2
for total in 1280 1320 1360 1400 1420; do
  payload=$((total - 28))
  printf '\nIPv4 total=%s payload=%s\n' "$total" "$payload"
  ping -4 -n -c 2 -W 2 -M do -s "$payload" "$target4"
done

target6=fd00::2
for total in 1280 1320 1360 1400 1420; do
  payload=$((total - 48))
  printf '\nIPv6 total=%s payload=%s\n' "$total" "$payload"
  ping -6 -n -c 2 -W 2 -M do -s "$payload" "$target6"
done

iputils 的 `-M do` 会设置禁止分片并让内核执行 PMTU 检查,过大的包可能在本机就被拒绝;`-s` 只计算 ICMP 数据字节。分别记录成功、超时和本地 `message too long`,在两端、两个方向和实际使用的地址族重复。找到相邻的成功/失败尺寸即可,不需要用大量探测追求单字节精度。

把外层承载和隧道内层分开

应固定的对象可回答的问题
外层承载WireGuard 端点地址、出口接口、云路由和中间封装UDP 封装包能否到达对端;基础路径是否已经小于预期
WireGuard 接口wg0 的 MTU、AllowedIPs 与实际解析路由内层 IP 包在加上 WireGuard/UDP/IP 开销后是否超出承载能力
隧道内业务真实 TCP/UDP 协议、方向、请求大小和时间窗应用是否真的按尺寸失败,修正后是否恢复

封装开销取决于外层 IPv4/IPv6 和是否还叠加其他隧道、VLAN 或云网络,不能永远按一个固定差值计算。当前 `wg-quick` 在未显式设置 MTU 时会根据端点路由或默认路由自动推导;显式 `MTU =` 会覆盖自动选择。旧发行版可能打包不同实现,因此要同时记录 `wg --version`、实际接口值和配置管理器。

用 tracepath 交叉检查,不把沉默当结论

替换为受控的隧道内对端;某些版本用 tracepath -4/-6,先查看本机 tracepath --help。UDP 探测可能受策略过滤,结果必须与分档 ping 和真实业务相互印证
tracepath -4 -n 10.0.0.2
tracepath -6 -n fd00::2

tracepath 使用 Linux 错误队列观察路径与 PMTU 变化,输出中的 `pmtu N` 对应收到的 message-too-long 线索。没有显示更小 PMTU 不等于路径支持当前尺寸:Packet Too Big 可能在回程被过滤,路径可能不对称,或探测协议与业务走了不同策略。

修复 Packet Too Big 返回路径,而不是全面放行或全面丢弃

经典 IPv4 PMTUD 依赖 ICMP Destination Unreachable/fragmentation needed,IPv6 PMTUD 依赖 ICMPv6 Packet Too Big。RFC 8201 明确描述了反馈丢失时 TCP 三次握手成功、传输阶段挂起的黑洞现象。核对云防火墙、主机规则、容器/转发链和对端策略是否允许相关错误返回,并保留限速与状态边界;不要把允许必要 ICMP 误写成对公网开放所有控制面。

先做一个临时接口 MTU 变更

在两端分别保存原值;若接口承担当前远程管理流量,先准备独立恢复路径。只改隧道接口,不同时修改物理网卡、路由 MTU 和 MSS
tunnel=wg0
old_mtu=$(cat "/sys/class/net/${tunnel}/mtu")
candidate=1380  # 仅示例:替换为双向分档测试得到的候选值
printf 'old_mtu=%s candidate=%s\n' "$old_mtu" "$candidate"
sudo ip link set dev "$tunnel" mtu "$candidate"
ip link show dev "$tunnel"

# 验收失败时立即恢复
# sudo ip link set dev "$tunnel" mtu "$old_mtu"

候选值应不高于已稳定成功的内层总包长,并通过两个方向、真实地址族和真实业务验证。降低过多虽然可能掩盖黑洞,却会增加包数与协议开销;一次成功传输也不能证明长期最优。先把临时变更作为因果实验,确认失败边界随接口 MTU 移动且业务恢复,再决定是否持久化。

按真正的接口所有者持久化

若接口由 `wg-quick` 管理,在受控的 `/etc/wireguard/<interface>.conf` 的 `[Interface]` 中写入已经验证的 `MTU =`,保护包含私钥的配置,并在维护窗口按该管理器的停启流程验证。NetworkManager、systemd-networkd、容器编排和云代理有各自的配置入口;不要同时让两个管理器争用接口,也不要只修改运行时后假定重启会保留。`SaveConfig = true` 还可能在关闭时覆盖文件,变更前必须核对。

TCP MTU probing 只是一条受限缓解路径

Linux 当前语义:0 关闭;1 默认关闭、检测到 ICMP 黑洞时启用;2 始终启用并从 tcp_base_mss 开始。不要顺手修改 tcp_base_mss
before=$(sysctl -n net.ipv4.tcp_mtu_probing)
printf 'tcp_mtu_probing_before=%s\n' "$before"
sudo sysctl -w net.ipv4.tcp_mtu_probing=1

# 只用新建 TCP 连接验证;失败或无收益时恢复
# sudo sysctl -w net.ipv4.tcp_mtu_probing="$before"

这个 sysctl 控制 Linux TCP 的 Packetization-Layer PMTU Discovery,不修复 WireGuard 的 UDP 封装,也不能帮助不具备相应探测机制的 UDP 应用。只有实际失败集中在 TCP、接口与 ICMP 边界暂时不能立刻修复,并且新连接的对照测试显示收益时,才把值 1 当临时缓解;值 2、MSS clamp 和路由级 MTU 都会扩大影响面,应单独评审。

用双向尺寸和真实业务共同验收

  • 两端都保存原始接口 MTU、版本、路由和 UTC 时间;候选变更只有一个变量。
  • 分档 ICMP 探测在实际 IPv4/IPv6 与两个方向达到预期边界,没有新的本地 message-too-long 或稳定超时。
  • 真实 SSH、HTTPS 上传/下载和实际 UDP 业务按使用项完成大于原失败点的传输,并核对内容完整性与应用错误。
  • WireGuard 握手、transfer 计数、接口丢包/错误和业务延迟在观察窗内没有退化;路径切换或漫游后重复检查。
  • 重启接口或主机后,配置管理器恢复同一 MTU,独立管理入口仍可用,回滚值和操作人保持可追溯。

回滚 MTU 与配置,不同时撤销证据

候选导致吞吐下降、其他地址族失败、路径切换后复发或业务仍卡住时,先恢复两端保存的接口 MTU 和对应持久配置,再用相同矩阵复测。若同时临时启用了 `tcp_mtu_probing`,恢复原值并用新连接验证。不要用删除日志、清空路由缓存或重启所有网络服务替代精确回滚。

把 MTU 当作路径属性持续复验

云网络、家庭宽带、移动网络、对端地址族、嵌套 VPN 和 WireGuard 工具版本变化都可能改变可用 PMTU。监控应保留真实业务失败、地址族、方向、端点与包长相关性,而不是只看隧道是否握手。发生迁移、增加一层封装或升级网络管理器后,重新执行低频分档和真实业务验收。

本文命令在 2026-08-18 按 WireGuard tools、Linux 内核、iproute2、iputils 与 IETF 当前上游文档完成语义和语法审阅,没有在读者的 VPS、WireGuard 对端或生产网络上执行。BSD/macOS/Windows、旧版 iputils、用户态 WireGuard、容器网络和托管 VPN 的命令与自动 MTU 逻辑可能不同;执行前先确认本机版本、帮助文本、实际接口所有者和独立恢复路径。

返回知识库