Cloudflare Tunnel QUIC 被 ISP 干扰?强制 HTTP2 协议 + IPv4 的排坑实录

2026-06-17

引子

加一个新域名到 Cloudflare Tunnel,发现旧域名访问要 10 秒,新域名只要 2.7 秒。一样的架构、一样的路径,差别只在于——新旧域名走的 Tunnel 连接协议不同。

这篇文章记录排查和修复的全过程,以及过程中踩的坑。

现象:同一条 Tunnel,两个域名速度差 3 倍

现有架构是 Cloudflare Tunnel + Caddy 反向代理,Tunnel 用通配符域名指向 Caddy,Caddy 按 Host 头分发到各个服务。这套架构跑了很久,一直没觉得慢。

直到加了一个新域名,顺手测了一圈:

域名 状态 耗时
旧域名 ✅ 200 10.3s
vault.旧域名 ✅ 200 4.6s
新域名 🆕 ✅ 200 2.7s
vault.新域名 🆕 ✅ 200 1.7s

10 秒和 2.7 秒,差了一个数量级。而且慢的是已经跑了好几个月的旧域名,不是新配的。

排查:问题出在 Tunnel 协议

我的第一反应是 Caddy 配置有问题——会不会新旧域名走了不同 upstream?检查后发现 Caddy 配置完全一致,新旧域名指向同一个 IP。

接着怀疑 DNS 解析,新旧域名都在 Cloudflare DNS 代理下,TTL 一样,解析路径大同小异。

最后看 cloudflared 日志:

2026-06-15T16:18:59Z INF precheck component="UDP Connectivity"
  details="QUIC connection successful" run_id=... status=pass

Precheck 显示 QUIC 连接成功,但这只是说 UDP 端到端可达。实际延迟 10s 说明 ISP 对 QUIC 流量做了降质(throttling),而不是完全阻断。

Cloudflare Tunnel 默认使用 QUIC 协议(基于 UDP/443)与 Cloudflare 边缘节点通信。在中国网络环境下,QUIC (UDP) 流量面临多重问题:

  • 2024 年 4 月起,GFW 开始基于 SNI 阻断指定域名的 QUIC 连接(USENIX Security 2025 论文已确认)
  • 多家国内运营商对 UDP 流量进行限速或降优
  • 在有 NAT / CGNAT 的环境中,QUIC 长连接容易超时

社区验证也印证了这一点。Cloudflare Community #792558 和 GitHub Issue #617/#688 中,俄罗斯、中国等地区的用户普遍遇到 QUIC 连接失败的问题。官方推荐的解法很简单——强制使用 HTTP2 协议。

解决方案:两个参数

知道问题出在 QUIC 上,修复就很简单了。cloudflared 的两个关键参数:

参数 取值 说明
--protocol auto(默认) / http2 / quic auto 优先 QUIC,失败回退 HTTP2
--edge-ip-version 4(默认) / 6 连 Cloudflare 边缘用 IPv4 还是 IPv6

Docker 方案

如果你用 Docker 部署 cloudflared,完整重建命令:

# 停止旧容器
docker stop cloudflared && docker rm cloudflared

# 以 HTTP2 + IPv4 模式启动新容器
docker run -d \
  --name cloudflared \
  --restart unless-stopped \
  --network host \
  -v /path/to/config:/etc/cloudflared:ro \
  cloudflare/cloudflared:latest \
  tunnel --protocol http2 --edge-ip-version 4 --config /etc/cloudflared/config.yml run

Docker Compose 方案

如果你用 Docker Compose,配置对应部分:

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./config:/etc/cloudflared:ro
    command: tunnel --protocol http2 --edge-ip-version 4 --config /etc/cloudflared/config.yml run

验证

改造后的日志显示全线 HTTP2:

2026-06-15T16:19:00Z INF Registered tunnel connection ...
  ip=198.41.200.53 location=lax01 protocol=http2
2026-06-15T16:19:02Z INF Registered tunnel connection ...
  ip=198.41.192.107 location=lax09 protocol=http2
2026-06-15T16:19:02Z INF Registered tunnel connection ...
  ip=198.41.192.37 location=lax09 protocol=http2
2026-06-15T16:19:03Z INF Registered tunnel connection ...
  ip=198.41.200.73 location=sjc10 protocol=http2

4 条 HTTP2 连接全部注册成功(之前 QUIC 时只有 1-2 条),分布到洛杉矶和圣何塞三个数据中心。延迟数据也大幅改善:

域名 改造前 改造后
旧域名 10.3s 2.7s
vault.旧域名 4.6s 1.7s

踩坑记录

坑 1:--force-ipv4 参数不存在

我第一反应是 --force-ipv4,结果 cloudflared 报错:

unknown flag: --force-ipv4

输出了一整屏帮助信息。正确参数名是 --edge-ip-version 4。cloudflared 的参数取名不是直觉式的 --force-* 风格,改参数之前先用 --help 确认。

坑 2:QUIC 无声降质

最坑的一点:Precheck 全部通过("QUIC connection successful"),但实际延迟高达 10s。

ISPs 对 QUIC 做的是降质(throttling)而非阻断。Precheck 确认的只是 UDP 端到端可达,不是实际服务质量。不能因为 Precheck 通过就认为 QUIC 没问题——要实测响应时间。

坑 3:API Token 权限差异

配置过程中发现,用 Cloudflare API 查询隧道连接信息(GET /cfd_tunnel)时 Token 权限不足,返回 0 条连接。但用同一个 Token 更新 Tunnel ingress 配置(PUT /configurations)却能成功。

这说明不同 API 端点对 Token 权限的要求不同——展示连接信息比更新配置需要的权限更高。如果遇到 API 403,不要假设是全局权限不够,先确认具体端点需要的 scope。

坑 4:旧版协议名称迁移

如果你用的是旧版 cloudflared,协议参数可能叫 h2mux 而不是 http2。新版 cloudflared 统一为 http2。如果参数报错,用 cloudflared tunnel --help 确认当前版本的协议支持列表。

总结

Cloudflare Tunnel 默认走 QUIC(UDP),对国内用户来说这是个性能陷阱。加两个参数——--protocol http2--edge-ip-version 4——把协议切到 HTTP2(TCP) 并用 IPv4 连接边缘节点,延迟从 10 秒降到 2.7 秒,效果立竿见影。

如果你也在国内用 Cloudflare Tunnel 感觉慢,先查查你的 Tunnel 走的是什么协议。可能只需要改一行参数。