从 499 到 200:解决 Telegram Webhook 经过 WireGuard 隧道的超时与黑洞问题

2026年1月22日 · 610 字 · 2 分钟

问题现象

在通过 Nginx 转发 Telegram Webhook 到家庭内部服务器(通过 WireGuard 连接)时,遇到了以下奇怪的现象:

  1. Nginx 日志频繁报错:出现大量 499 Client Closed Request 和 504 Gateway Timeout。
  2. Curl 测试具有欺骗性:使用简单的 curl 发送测试小包时响应极快,但真实的 Telegram 请求却始终无法到达后端 Python 程序。
  3. Webhook 积压:使用 getWebhookInfo 接口查询发现 pending_update_count 持续增加。

深度分析:MTU 黑洞

经过排查,问题的根源在于 MTU (Maximum Transmission Unit) 不匹配导致的“黑洞效应”。

  • WireGuard 限制:WireGuard 协议由于增加了封装头,默认 MTU 通常为 1420。
  • 数据包膨胀:Telegram 的 POST 请求数据包加上 HTTP Header 后,很容易超过 1420 字节。
  • 静默丢弃:由于 TCP 请求通常带有 DF (Don’t Fragment) 标志,当 Nginx 尝试转发大包进入 wg0 接口时,数据包被内核直接丢弃。

解决方案

1. 调整网卡 MTU (服务端与客户端)

将 WireGuard 网卡的 MTU 降低到 1280。这是最保险的值,预留了足够的空间给隧道封装。

在 wg0.conf 的 [Interface] 部分添加:

[Interface]
MTU = 1280
PostUp = ip link set dev %i mtu 1280

2. Nginx 配置优化

确保 Webhook 路径不被全局的 deny 规则拦截,并开启针对超时的优化参数。

location = /tg-webhook/your-uuid-path {
    allow all;
    proxy_pass http://10.8.0.5:9527;
    
    proxy_ignore_client_abort on;
    proxy_read_timeout 90s;
    
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

3. 重置 Webhook 状态

网络链路修复后,必须重置 Webhook 以清空积压的错误。

# 第一步:删除 Webhook 并清空积压
curl -X POST https://api.telegram.org/bot<TOKEN>/deleteWebhook?drop_pending_updates=true

# 第二步:重新绑定 Webhook 地址
curl -X POST https://api.telegram.org/bot<TOKEN>/setWebhook \
     -d "url=https://https://yourdomain.com/tg-webhook/your-uuid-path" \
     -d "drop_pending_updates=true"

验证方法

在 Nginx 服务器上执行禁止分片的大包 Ping 测试:

# 如果 mtu 已锁定为 1280,发送 1400 字节负载应提示 message too long
ping -M do -s 1400 10.8.0.5

总结

在公网服务器与私有内网通过隧道连接的架构中,MTU 不一致是导致“小包能过、大包卡死”的元凶。锁定 MTU 并重置 Webhook 连接是解决此类问题的关键。