内网穿透的应用场景

内网穿透大家都不陌生,zerotier,Tailscale等都用过,但缺点就是不能开箱即用,往往需要安装专用的客户端,一对一登录授权,不够“便携性”,流量中转的服务器需要花钱花精力维护,又或者客户端故障。特别是跨国内网的情况下,中转链路就变得更为复杂。而cloudflared的场景更适合中心化的穿透场景,在一个内网部署cloudflared,就可以便携地在任意终端快速通过域名连接你的应用,而你不用关心链路的问题————当然,在境内的速度可用性会降低,但对于个人小应用也是足够的,后面会讲到代理的问题。

下载安装地址

https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/#linux
Cloudflared提供了直接的二进制,可以直接下载运行,虽然二进制有点大38M左右,对嵌入式设备不太友好,好在不用配置什么软件源。
AMD64/x86
ARM64
Cloudflared也提供了简单的更新命令:执行cloudflared update就会更新自己。
当然,官方也提供了docker镜像,方便后续维护升级(升级就是更新docker pull镜像就可以)。 docker compose示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared
    restart: unless-stopped
    command: tunnel run --token ebJhI123oiZxxxxxxxxxxx
    dns:
      - 1.1.1.1
      - 1.0.0.1
    network_mode: host

如果你想用软件源安装方便后续更新,可以使用 https://pkg.cloudflare.com/index.html ,但只支持有限的几种发行版。

场景1 把内网的web服务暴露到公网

适合家里没有公网IP,或者买了个无公网IP的nat鸡,想把自己的web服务放到公网直接浏览器在任意地方都可以访问的。
你只需要在内网任意一台设备上运行部署一次cloudflared,你就可以在Cloudflare后台随意设置暴露哪些内网服务到公网,即使服务不是运行在那台设备上而是在局域网的其他设备上,相当于你的内网和cloudfalre打通了。
前提条件:Cloudflare账号,一个托管在Cloudflare的域名。
推荐上面的docker compose部署。
传输路径:安装了Cloudflared的设备-> Cloudflare Tunnels -> Cloudfare EDGE(用户浏览器)

步骤1 首先添加Tunnels

界面可能随时间变化,所以不截图了,找不到可以点左侧顶部的的菜单搜索:
仪表板后台: https://dash.cloudflare.com/
不要点进去Zero Trust,那里面给的东西和命令提示都是大坑,忽悠你装各种图形One客户端,都是一些用不到的功能和迷惑你。
直接在左侧分类Protect & connect(保护和连接),点击展开左侧菜单Networking(联网),点进去Tunnels
可以查看和创建Tunnel,点右上角Create Tunnel(创建隧道)
输入Tunnel名字,比如Myhome
确认名字后会给出连接Tunnel的token,直接用token就可以连接,命令行如下:

1
cloudflared tunnel run --token eyJhIjxxxxxxxx

当你连上了之后,就可以确认并创建tunnel。
点击你的tunnel的名字,就可以看到状态是否健康和uptime,点击Connectors的ID,就可以看到它目前连接了哪些数据中心(一般会同时连接一个地域里面四个数据中心),源IP,版本等。

步骤2 Routes发布Web应用

这是最轻松的一集,只要tunnel建好了,后续就简单了,随时随地在后台调整你需要发布的Web应用。
切换到【路由】Routes标签页,点击右上角的【添加路由】Add route,选择【添加已发布的应用程序】Published application,输入一个【子域名】Subdomain,然后在【服务URL】Service URL那里直接输入你内网的URL即可,创建完成你就可以直接用你的子域名访问你的内网Web服务了,还能随时随地在Cloudflare后台任意映射任意修改。
另外关于https证书,Cloudflare会自动生成,对于完全托管在Cloudflare的域名来说无需手动干预,但如果你是通过某种早期的歪门邪道的cname方式接入,那么可能每三个月需要手动改一下dns的txt记录来验证证书,这个Cloudflare会给你发邮件提示你添加什么样的txt记录,因为Cloudflare是用的DNS验证而不是http挑战,虽然不知道为啥不采用http验证,大概也是没考虑到这些歪门邪道的用户或者DNS验证实施起来更简单。

题外话:多个副本(Replicas)

你还注意到你的Tunnel页面有显示副本(Replicas),还有Add a replica(添加副本)的按钮。不得不说Cloudflare的概念太迷惑,这个在Zero Trust里面叫Connector,
副本 ID=Replica ID=Connector ID(Zero Trust界面的叫法),中文界面就显示副本 ID,英文界面就显示Replica ID
场景是这样的:
你在 服务器 A 和 服务器 B 上用同一个 Tunnel Token 启动了两个 cloudflared。
效果:如果 服务器 A 突然断网或挂掉,Cloudflare 边缘节点会秒级自动把流量切到 服务器 B 的 Connector(replica) 上,访问者完全感觉不到服务中断。
具体的一种应用场景:你可以用同一个token起两个进程,一个直连,一个走代理,代价是cloudflare并没有确定的算法一定分配到哪个副本,一般优先转发到 用户到Cloudflare节点地理上最近 的而不是延迟最低的,比如大多数境内访问默认直连是LAX,即使你代理是HKG,特别是电信用户,大概率可能走绕地球两圈的LAX。

  1. 什么是 Replica?
    添加副本(Replica)的按钮,其实就是给你重新复制一遍那个一模一样的Token,让你在别的机器上跑多一个实例。
  • Replica = 同一个 Tunnel UUID 下运行的多个 cloudflared 实例(connector)
  • 用途:高可用、故障切换、无停机更新配置
  • 每个 Replica 会向 Cloudflare 建立 4 条出站连接(通常分布在至少两个不同数据中心)
  • 所有 Replica 共享相同的路由和配置
  1. 多 Replica 时如何选择?
  • 不支持 流量调度算法(round-robin、hash、加权等)
  • 请求到达 Cloudflare Edge 后,优先转发到 地理上最近 的 Replica
  • 如果距离计算失败或连接不可用,会重试其他可用连接
  • 没有保证最终一定选到某个特定 Replica

官方原文:
By design, replicas do not offer any level of traffic steering (random, hash, or round-robin). Instead, when a request arrives to Cloudflare, it will be forwarded to the replica that is geographically closest. If that distance calculation is unsuccessful or the connection fails, we will retry others, but there is no guarantee about which connection is chosen.

  1. 数量上限
项目限制说明
Active Replicas / Tunnel25软限制,企业可申请提高
连接数 / Tunnel10025 replicas × 4 连接
Tunnels / Account1000软限制
  • 限制只针对 当前 active(已连接) 的 Replica
  • 历史断开的 Connector ID 不占用名额
  1. Replica / Connector ID 生成规则
  • 每次启动 cloudflared 进程都会 重新生成一个唯一的 Connector ID(UUID)
  • 生成依据:cloudflared 版本 + 操作系统/架构 + 功能标志 + 随机 nonce
  • 查看方式:
    • 仪表盘 → Networking → Tunnels → 选择 Tunnel → Connectors 列表
    • 命令:cloudflared tunnel info <NAME_OR_UUID>
  1. 重启、出口 IP 变化的影响
场景结果
Token 不变正常认证到同一个 Tunnel
出口 IP 变化无影响,只是新的出站连接
进程重启 / 崩溃重启 / 服务重启生成全新 Connector ID,旧 ID 变为 inactive
同时在线实例 ≤ 25可无限次重启,不会因 ID 累积而无法加入

Token 不变 + IP 变化 + 频繁重启 → 完全没问题。上限只看当前 active 数量。

实测补充:副本的流量归属与混协议副本

官方“地理最近”的说法之外,实测还有更具体的规律:

  • 流量归属是按客户端入口 colo 确定性地粘住某一个副本的,与启动顺序、注册先后无关,外部也没有接口可以调度。实测从一端访问全部落在 HTTP/2 副本上,而同一时刻从另一台机器访问全部落在 QUIC 副本上;
  • 混协议副本不可行:想做“QUIC 主 + HTTP/2 备”(平时走 QUIC 拿低延迟,QUIC 被封时 HTTP/2 顶上)是做不到的——备份副本不是冷备,它可能恰好接走你的全部真实流量,QUIC 的优势直接归零。

场景2 把内网的tcp端口“暴露”到公网

把这个暴露打引号是有原因的,因为这个暴露需要运行一下客户端来连接,有点类似frp。
那不得不说Cloudflare的界面依然混乱了,这个菜单要从Zero Trust里面翻出来。
而有的账户点进去Zero Trust要你先添加银行卡付款方式,比较早期的账户不用,所以这里只简单介绍下:
点进去Zero Trust,点Tunnels & Mesh,点进去你的tunnel,点Published application routes,点Add a published application route,你可以看到这里的service多了type的选项,可以选tcp,url就填你的局域网,比如192.168.1.123:22,子域名依然自己填一个,比如ssh.myhome.com,保存了之后你就可以这样在任意地方连接你的192.168.1.123:22

1
2
3
4
5
6
# 客户端需要在本机运行 cloudflared
# 用 cloudflared access tcp 命令把远程 TCP 服务映射到本地端口
# cloudflared access tcp --hostname <你的公网域名> --url localhost:<本地端口>
cloudflared access tcp --hostname ssh.myhome.com --url localhost:2222
# 再让应用连接本地端口
ssh -p 2222 root@localhost

但实际上,分析日志和源代码可以发现,cloudflared access tcp(以及它的别名 ssh/rdp/smb)在客户端侧走的是 HTTP WebSocket 隧道,换句话说,你可以自己写一个程序走http ws隧道来映射也是一样的效果,甚至我实测可以比官方的优化的更好,并且还测试出用户侧上传限速的问题,当然这是题外话,给有需要的朋友提供一个思路自己实现。

场景? 把ssh/rdp等服务运行在web里

这个是真的要添加支付方式,放弃

穿透速度与限制

Cloudflared的内网穿透基于quic,用户端基于http,端口传输则是走http的ws。在实测中发现,Cloudflared对于用户浏览器则的下行没怎么限速,也就是tunnel端的上传比较好,但对于用户则的上传有明显的限制,突发大带宽的情况下甚至会掐断:
Cloudflare 对过大的 WebSocket 二进制帧存在截断或重置行为。通过实测得出:

  • 256 KiB 的大帧会导致 Cloudflare 在两个方向上截断/重置隧道;
  • 32 KiB 的帧可以稳定传输,完整性没有问题。

Cloudflare Tunnel 对 WebSocket request-body 方向(client → origin) 存在明显的字节速率限制,实测限速时约为 0~1 Mbit/s;而 response-body 方向(origin → client) 不受此限制,可以跑满。

补充几条实测的结论:

  • 这个限速不只是“慢”:实测持续上传约 5 MB / 40 秒后 Cloudflare 会主动断开连接,走 WS 做大流量传输的程序必须自己处理断线重连和续传。
  • Cloudflare 的空闲判定也不可靠:它不保证把 WebSocket 协议层的 Ping 控制帧算作活动,空闲后照样关连接,甚至出现半开连接(连接看起来活着但不再转发数据)。自建客户端要用真实的二进制数据帧做保活,并加应用层活性超时——只看 TCP 状态是永远发现不了的。
  • 压测要节制、拉开间隔:高频高压的测试流量会触发 Cloudflare 的滥用保护导致连接被重置,别把它误判成自己程序的 bug。

如果想点对点组跨国内网,最好两边都起一个tunnel然后写一个程序实现上下行分离的全双工通信,经过实测可行,速度两边都能打满,点对点Cloudflared官方推荐用那个非常难用的图形客户端one来连接,个人感觉没有tunnel默认会建立4 条 HA 连接到 Cloudflare edge稳定。当然这是题外话,有需要的可以自行摸索实现。

进阶:指定传输协议和边缘节点

cloudflared tunnel run 有两个调试参数:--edge 是 tunnel 级参数,必须放在 run 子命令之前--protocol 在 tunnel 级和 run 子命令级都注册了,放前后都可以,统一放前面更不容易出错:

1
2
3
4
# 强制使用 http2(默认 auto,可选 auto / quic / http2)
cloudflared tunnel --protocol http2 run --token eyJhIjxxxxxxxx
# 钉选边缘节点(StringSlice,可重复多次,格式 IP:7844)
cloudflared tunnel --edge 198.41.192.7:7844 --edge 198.41.200.113:7844 run --token eyJhIjxxxxxxxx

边缘节点可以从官方文档获取: https://developers.cloudflare.com/tunnel/configuration/

对应的环境变量是 TUNNEL_TRANSPORT_PROTOCOLTUNNEL_EDGE,docker 部署时用环境变量更顺手。

什么时候要强制 --protocol http2

  • cloudflared 宣称的 QUIC→HTTP/2 自动回退实测不触发:启动会明确打印 Environment ready with degraded transport … proceed using 'http2',然后继续无限重试 QUIC,隧道永远起不来,而进程看起来很健康。UDP 不通的环境必须手动指定,别指望自动降级。
  • 部分运营商/网关对 UDP 做 QoS 或直接 DPI 封锁 QUIC。注意一个坑:“UDP 能通”不代表 QUIC 可用——DPI 设备会放行不像握手的探测报文,却把每个真实的 QUIC Initial 都拦下。

什么时候按性能取向钉死协议:
同路由实测,两个协议没有全面更快的:

  • QUIC 延迟低约 32%,适合交互式流量;
  • HTTP/2 单流上行约 2 倍,适合大流量传输。 理想网络条件下适合QUIC低延迟,更注重网络稳定和带宽适合http2。

什么时候要钉 --edge

  • 出口 DNS 被劫持/污染时,cloudflared 默认解析的 regionN.v2.argotunnel.com 可能解析到假地址导致边缘握手全部失败,钉死边缘 IP 可以直接绕过解析;
  • 做出口策略路由时,需要固定 IP 段作为路由依据;
  • 想固定连到延迟更低的边缘节点时。

关于代理cloudflared和Tunnel连接性问题

对客户端来说,大概率不用关心连接性和代理的问题,因为客户端走的公网域名连接,代理起来也简单。关键是服务端怎么连上tunnel,或者更快地连上tunnel。
cloudflared官方项目里面有不少issue请求支持走代理连接,但无一例外都被close,官方的意思很明确,不支持代理是有意为之,cloudflared主要使用quic进行传输,http2是降级路径,而SOCKS5代理对QUIC并不适用(当然是从标准程序的实现来说,被大家玩出花的代理链路不能比,若必须支持 QUIC over SOCKS5,则需要深度改造 UDP 路径)
此外,Cloudflared在连接过程中会依赖DNS的SRV记录,如果你是专用虚拟机或者docker运行,如果你有搭建内网DNS服务器的话,建议配置专用公共的DNS避免过滤和干扰(如1.1.1.1)。如果你局域网有FakeIP,需要把以下域名后缀加入非FakeIP解析,或者嗅探流量的名单:

1
2
3
4
5
cftunnel.com
argotunnel.com
cfargotunnel.com
cloudflareaccess.com
cloudflareclient.com

部分请求会使用以上域名包装数据内容,但使用的子域名的解析记录本身是不存在的,因此不要尝试嗅探这些域名的流量。
只要满足了正常的DNS解析记录,大概率裸连是没有问题的,如果是普通地把家里的服务暴露到公网,也足够。当然,如果想进行跨国的传输,那就要考虑对cloudflared进行代理:
前提条件:你的节点支持代理udp。
基本思路就是单独开机一个虚拟机或者独立IP的macvlan的docker容器,然后把他的网关直接写成透明代理的网关,DNS设置成1.1.1.1即可。 当你满足了所有链接条件,Cloudflared运行日志会输出如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
2026-07-29T21:12:37Z INF |                               CONNECTIVITY PRE-CHECKS                               |
2026-07-29T21:12:37Z INF +-------------------------------------------------------------------------------------+
2026-07-29T21:12:37Z INF |  COMPONENT         TARGET                     STATUS  DETAILS                       |
2026-07-29T21:12:37Z INF |  DNS Resolution    region1.v2.argotunnel.com  PASS    DNS Resolved successfully     |
2026-07-29T21:12:37Z INF |  DNS Resolution    region2.v2.argotunnel.com  PASS    DNS Resolved successfully     |
2026-07-29T21:12:37Z INF |  UDP Connectivity  region1.v2.argotunnel.com  PASS    QUIC connection successful    |
2026-07-29T21:12:37Z INF |  UDP Connectivity  region2.v2.argotunnel.com  PASS    QUIC connection successful    |
2026-07-29T21:12:37Z INF |  TCP Connectivity  region1.v2.argotunnel.com  PASS    HTTP/2 connection successful  |
2026-07-29T21:12:37Z INF |  TCP Connectivity  region2.v2.argotunnel.com  PASS    HTTP/2 connection successful  |
2026-07-29T21:12:37Z INF |  Cloudflare API    api.cloudflare.com:443     PASS    API is reachable              |
2026-07-29T21:12:37Z INF |                                                                                     |
2026-07-29T21:12:37Z INF |  SUMMARY: Environment is healthy. cloudflared will use 'quic' as primary protocol.  |
2026-07-29T21:12:37Z INF +-------------------------------------------------------------------------------------+

PaoPaoGateway集成的Cloudflared

最新版本的PaoPaoGateway集成了Cloudflared功能,只需要配置token即可开箱即用,简化了代理的问题,自动钉选延迟更低的边缘节点,自动切换备用协议等,相关使用和选项可以参考GitHub说明。