侧边栏壁纸
  • 累计撰写 9 篇文章
  • 累计创建 3 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

FRP 反向代理重启后神秘失效的排查之旅-MTU

Administrator
2025-11-03 / 0 评论 / 0 点赞 / 9 阅读 / 0 字

记一次由 MTU 引发的“血案”:FRP 反向代理重启后神秘失效的排查之旅

引言:风平浪静下的“意外”

对于我们这些热衷于 Self-Hosted 的玩家来说,一个稳定运行的家庭服务器集群是最大的慰藉。我的 PVE 平台上,通过 Docker 和 1Panel 管理着一系列服务,并使用 FRP (Fast Reverse Proxy) 将部分 Web 应用安全地暴露到公网。一切都完美运行,直到我进行了一次再普通不过的操作——重启了 frpc 客户端容器。

瞬间,所有通过公网域名访问的服务全部瘫痪。浏览器无情地展示着 ERR_HTTP2_PROTOCOL_ERROR,仿佛在嘲笑我的天真。然而,通过局域网 IP 访问一切正常。直觉告诉我,问题出在了 FRP 或反向代理的链路上。一场耗时数小时的“破案”之旅,就此拉开序幕。

排查之旅:层层迷雾,柳暗花明

第一站:怀疑“嫌疑人”—— FRP 与后端服务

按照常规思路,我首先检查了最明显的“嫌疑人”:

  1. FRP 客户端 (frpc.toml) 配置:反复检查了代理规则,特别是 web-reverse-proxy 相关的部分,type 确实是 tcplocalIPlocalPort 也都指向了我的 OpenResty 网关。配置无懈可击。
  2. 后端服务 (1Panel/OpenResty):通过局域网 IP https://192.168.0.x 访问,服务完全正常。这排除了后端服务崩溃的可能。

初步排查陷入僵局。配置正确,服务正常,那问题出在哪?

第二站:关键线索 —— ERR_HTTP2_PROTOCOL_ERROR 与 MTU

这个错误码通常指向网络协议层面的问题,特别是与 HTTPS (SSL/TLS) 协商有关。一个资深的技术专家 AI 助手提示我,这很可能与 MTU (Maximum Transmission Unit, 最大传输单元) 有关。

我立刻在运行 frpc 的服务器上执行了 ping 测试:

ping -D -s 1472 公网IP  # -D: 不分片, -s 1472 + 28 头部 = 1500 字节

结果立刻出现了关键线索:

From 192.168.0.1 icmp_seq=1 Frag needed and DF set (mtu = 1480)

翻译:我的路由器 (192.168.0.1) 明确告诉我,它无法在不分片的情况下发送 1500 字节的数据包,它到公网的路径 MTU 只有 1480

理论:HTTPS 握手时的数据包较大,当 frpc 发送一个接近 1500 字节的握手包时,在路由器处因超出 MTU 限制而被丢弃,导致握手失败,浏览器报出协议错误。

第三站:悖论出现 —— 为什么是“现在”?

找到了 MTU 问题,似乎离真相只有一步之遥。但我立刻向 AI 提出了一个无法回避的悖论:“如果 MTU 问题一直存在,为什么我的服务在重启前是好的,偏偏在重启后才出问题?

一个静态的网络问题,不应该因为一个应用重启而突然显现。这个疑问,将我们引向了问题的真正核心——Docker 网络

第四站:深入 Docker —— network_mode: host 的“背刺”

我最初的猜测是 Docker 的 bridge 网络 MTU 设置问题。我准备修改 docker-compose.yml 为 Docker 网络指定 MTU,但就在这时,我检查了 1Panel 为我生成的 frpc 容器配置,一个关键设置映入眼帘:

services:
  frpc:
    # ...
    network_mode: host
    # ...

network_mode: host!这意味着 frpc 容器没有使用 Docker 隔离的虚拟网络,而是直接共享了宿主机的网络栈

这瞬间让所有线索都串联了起来:

  1. 共享网络:容器的网络配置(包括 MTU)完全等同于宿主机。
  2. 宿主机 MTU:我的 PVE 宿主机,其物理网卡 MTU 默认是 1500
  3. 重启触发:重启 frpc 容器后,进程重新初始化,它从宿主机环境读取到 MTU 为 1500,于是放心地发送大数据包。
  4. 冲突发生:这个 1500 的数据包在路由器处遇到了 1480 的瓶颈,被丢弃。

真相大白:一直存在的网络 MTU 缺陷,被一次 Docker 容器的重启“激活”了。容器在 host 模式下,忠实地继承了宿主机错误的 MTU “认知”,导致了这场“血案”。

最终解决方案:校准源头

既然问题根源在宿主机,那么解决方案也必须在宿主机上。我的宿主机是 Proxmox VE (PVE),它基于 Debian。

原则:只修改那个配置了通往路由器网关(192.168.0.1)的网桥。在我的环境中,它是 vmbr0

操作

  1. 登录 PVE Web UI。
  2. 导航到 数据中心 -> 节点 -> 系统 -> 网络
  3. 选中 vmbr0,点击 编辑
  4. MTU 字段中,填入 1480
  5. 保存后,点击顶部的 应用配置 按钮,让更改热生效。

配置应用后,PVE 主机知道了通往外界的“门”只有 1480 那么宽,它会自动调整所有从这里发出的数据包尺寸。此时,重启 frpc 应用,再次访问公网域名,一切恢复正常!

总结与启示

这次看似离奇的故障,实际上是一堂生动的网络实战课。它带给我几个深刻的启示:

  1. 相信证据,但要追问“为什么”ping 测试很快暴露了 MTU 问题,但“为什么重启后才出问题?”这个追问,才是找到根本原因的关键。
  2. 魔鬼在细节中network_mode: host 是一个常见的 Docker 配置,但必须深刻理解它与宿主机网络的共生关系。
  3. 网络是端到端的木桶:整个通信链路的性能,取决于最窄的那块板(MTU)。校准源头,才能一劳永逸。
  4. 不要害怕底层:从应用层(FRP)到容器层(Docker),再到宿主机虚拟化层(PVE),最后到物理网络层(路由器),逐层排查,问题终将无所遁形。

希望这次的排查经历,能为同样在 Self-Hosted 道路上探索的你,提供一份有价值的参考。

博主关闭了所有页面的评论