家里那台电视盒子改造的小服务器已经跑了大半年,7 个容器,2G 内存。所有服务都在内网,出门就访问不到。
家宽没有公网 IPv4,这事没法绕:端口映射做不了,DDNS 也没意义。能选的方案就那么几个,最后用了 Cloudflare Tunnel——盒子主动往外连,不需要任何入站端口,也不需要在路由器上开洞。
装完之后能用了,但中间有一段折腾了很久,因为它的自检在骗人。
这篇文章只讲调参,不讲怎么装。如果你也在没有公网 IP 的环境下用 Tunnel,这几个坑大概率会踩到。
赶时间的话看这张表,后面是推导过程。
配置 | 结果 |
|---|---|
默认(QUIC + 双栈) | 唯一可用,注册 2 条连接 |
| 隧道彻底连不上,一条都注册不了 |
| 没有收益,反而 502 |
| 掐掉唯一可用的通路 |
面板显示 Degraded | 正常现象,不是故障 |
precheck 显示 FAIL | 可能完全正常,别信 |
核心结论只有一句:不要动默认参数。
cloudflared 启动时会跑一段连通性预检,输出大概是这样:
UDP Connectivity region1.v2.argotunnel.com FAIL QUIC connection failed
TCP Connectivity region1.v2.argotunnel.com FAIL HTTP/2 connection is blocked
SUMMARY: Environment has critical failures.Environment has critical failures 这个措辞很吓人,看起来隧道彻底废了。
搜索这个报错,绝大多数答案都指向同一句话:
你的网络屏蔽了 UDP 7844,加
--protocol http2走 TCP 就行。
听起来非常合理——UDP 被墙了就换 TCP,这是标准排查思路。于是我照着做了。
加完参数重启,结果是更彻底地连不上:
ERR Failed to dial a quic connection error="failed to dial to edge with quic: timeout: no recent network activity"
ERR Unable to establish connection with Cloudflare edge error="TLS handshake with edge error: EOF"
INF Retrying connection in up to 2s无限重试,一条连接都注册不上。
这才回头去做正经的连通性测试。
三个候选路径,逐个测:
协议 | 端口 | 实测结果 |
|---|---|---|
QUIC(默认) | UDP 7844 | 可用,能注册连接 |
HTTP/2( | TCP 7844 | 完全不可用,全部 |
普通 HTTPS | TCP 443 | 正常 |
结论明确:这条宽带上 TCP 7844 是死的,UDP 7844 反而活着。
也就是说 precheck 报的「UDP FAIL」本身就不可靠,而它建议的替代方案(TCP 7844)才是真正不通的那条。
所以那句 Environment has critical failures 的正确理解是:它在几秒内测了两条路,两条都没测通过,但它不告诉你哪条实际上能用。
/dev/tcp 说通,握手还是超时排查过程中我用过这个土办法:
timeout 5 bash -c '</dev/tcp/198.41.200.13/7844' && echo "通" || echo "不通"返回「通」。
但 cloudflared 那边依然是 TLS handshake ... i/o timeout。两边结论直接打架。
原因在于 /dev/tcp 只完成 TCP 三次握手——那都是小包。而 TLS 握手要收 ServerHello 和证书链,那是多个满包。中间链路如果对这种「握手成功后的大包」静默丢包,就会得到「连接建立成功,但数据全部丢失」的诡异状态。
所以
/dev/tcp只能证明「对端回了 SYN-ACK」,不能证明「这条链路可用」。 用它判断端口通不通,在这个场景下是无效的。
这条经验对所有「握手能过、数据不通」的排查都适用。
--edge-ip-version 的两个方向都试过了既然默认走 IPv6 边缘,那强制走 IPv4 行不行?
--edge-ip-version 4 → 掐掉了唯一可用的 IPv6 通路,隧道断
--edge-ip-version 6 → 没有任何收益,反而开始出现 502两个方向都是负收益。
隧道连上之后,Cloudflare 面板显示 Degraded,连接数是 2。
一度以为是不稳定,反复重启。后来发现:
这条链路的连接数上限就是 2 条,而 Cloudflare 面板对少于 4 条连接的健康隧道会标记为 Degraded。
这是面板的判定阈值问题,不是你的隧道有问题。只要服务能访问,这个标记可以完全无视。
排查过程中我发现,日志里的判据也有坑。
数 Registered tunnel connection 出现的次数这个看起来很靠谱,实际会误报:
# 这个结果不可靠
journalctl -u cloudflared | grep -c "Registered tunnel connection"因为 journald 会滚动,日志被清掉之后这个数字会变成 0,看起来像从没连上过。
包括 systemctl is-active,它在某些时刻也会显示 activating 而不是 active,因为 cloudflared 是 Type=notify 服务,要等它自己上报就绪。
唯一可信的判据是从外部发一个真实请求:
curl -sI https://你的域名 | head -1
# 期望:HTTP/2 200这个判据的好处是它绕过了所有中间状态——不看进程在不在、不看日志怎么写,直接看「外部能不能访问到你的服务」。这才是用户真正关心的事。
踩完之后整理了一套顺序,从「最可信」到「最不可信」:
# ① 先看外部能不能访问(唯一有效判据)
curl -sI https://你的域名 | head -1
# ② 看有没有真正注册上连接
journalctl -u cloudflared -n 50 --no-pager | grep "Registered tunnel"
# ③ 恢复默认配置(把之前改坏的 override 删掉)
rm -f /etc/systemd/system/cloudflared.service.d/override.conf
systemctl daemon-reload
systemctl restart cloudflared --no-block
sleep 30
# ④ 再验一次
curl -sI https://你的域名 | head -1这里有个细节值得单独说:systemctl restart 一定要加 --no-block。
cloudflared 是 Type=notify 服务,不加这个参数,systemctl restart 会阻塞在终端直到服务就绪或超时(最长 3 分钟)。看起来像命令卡死了,实际上是在等。加 --no-block 立刻返回。
我第一次遇到时以为 SSH 断了,还重连了一次。
几个可以直接拿去用的结论:
--protocol http2 在多数家宽上是负优化/dev/tcp 测端口是假阳性。它只验证握手,不验证链路curl -sI 比数日志可靠得多折腾这一趟最大的收获不是某个参数,而是一个判断习惯:当工具的自检结论和实际现象矛盾时,先怀疑自检的判据,而不是现象。
precheck 测的是「能不能连上边缘节点」,我关心的是「别人能不能打开我的网站」。这两件事之间隔着好几层,precheck 失败完全不影响后者成立。
机器还在跑,欢迎交流。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。