Cloudflare Tunnel + SaaS 优选加速完整指南
一句话总结:Cloudflare Tunnel 默认分配的入口 IP 在国内访问很慢。本方案用 Cloudflare for SaaS 把你的业务域名"挂"到一个自己挑选的优选 IP 入口上——DNS 还是解析到 Cloudflare,但连的是你挑过的快节点,进站之后再由 SaaS 回退源把流量送进隧道。本文以 Halo 博客(HTTP 8090)+ Jitsi Meet(HTTPS 8443) 两个内网服务为例,一次配好、顺便支持日后扩展。
🏢 公司 + 家里两台设备都跑 cloudflared?先跳到《进阶三:两地部署》——分清「一条隧道双连接器」还是「两条隧道」,再动手。
📌 为什么要折腾这一套
问题在哪:
Cloudflare Tunnel 可以免公网 IP、免开端口地把内网服务(Halo 博客、Jitsi Meet、Home Assistant……)暴露到公网。但它给每个隧道分配的入口是 xxx.cfargotunnel.com,解析出来的 Cloudflare IP 是随机分配的——这套 IP 对国内用户来说经常又慢又不稳定。
解决思路:
- Cloudflare 的所有边缘节点共享同一套服务,只要能连上任意一个优质节点,就能访问你的服务;
- 优选 IP:通过测速工具(如 CloudflareSpeedTest)或公共优选域名,找出对你网络最快的 Cloudflare IP;
- Cloudflare for SaaS:允许你在 Cloudflare 上注册"自定义主机名",让边缘节点认得你的业务域名——于是可以把业务域名的 DNS 偷偷指到优选 IP 上,节点收到请求后照样能把流量送回你的隧道。
🧠 先看懂原理(配置前必读)
流量是怎么走的
flowchart TD
U["👤 用户访问 https://meet.example1.com"] -->|"① DNS 解析:meet → ip → 优选 IP"| E["🌐 Cloudflare 边缘节点(优选 IP)"]
E -->|"② TLS 握手 SNI = meet.example1.com<br>边缘匹配到自定义主机名"| F["🔁 回退源 tunnel.example2.com"]
F -->|"③ cloudflared 按 Host 头匹配规则<br>(blog.example1.com 则命中另一条规则)"| S["🖥 Jitsi Meet localhost:8443<br>Halo 博客 localhost:8090"]
- ① DNS 决定你连到哪台 Cloudflare 服务器——优选 IP 在这一步起作用;
- ② SNI 决定 Cloudflare 把请求送给谁——SaaS 自定义主机名在这一步起作用;
- ③ 隧道负责按 Host 头把请求分发到对应服务——cloudflared 是从内网主动外连 Cloudflare 的,所以不需要公网 IP。
💡 记住这句就抓住了全文题眼:DNS 决定连到哪,SNI 决定送给谁,Host 头决定进哪个端口。
全部名字一览(2 个服务 + 2 个设施)
双域名方案下,两个服务一共只涉及 4 个子域名字:
| 名字 | 所在域名 | 角色 | DNS 记录 | 云朵 | 对应服务 | 会有人直接访问它吗 |
|---|---|---|---|---|---|---|
blog.example1.com | example1.com(主) | 业务域名① | CNAME → ip.example2.com | ⚪ 灰 | Halo 博客 :8090 | ✅ |
meet.example1.com | example1.com(主) | 业务域名② | CNAME → ip.example2.com | ⚪ 灰 | Jitsi Meet :8443 | ✅ |
ip.example2.com | example2.com(辅) | 优选入口 | CNAME → 优选域名(或 A → 优选 IP) | ⚪ 灰 | 全服务共用 | ❌ 没人,DNS 链条中的指路牌 |
tunnel.example2.com | example2.com(辅) | 回退源 | CNAME → xxx.cfargotunnel.com(Tunnel 自动生成) | 🟠 橙 | 全服务共用 | ❌ 没人,Cloudflare 内部回传用 |
📌 先澄清:这不是要你买四个域名! 上表全部是子域名——子域名不用花钱注册,在 DNS 页面加一条记录就诞生一个。"双域名方案"指的是你只需要注册两个顶级域名:主域名放业务,辅助域名放设施。
共用与独用的边界:业务层每服务一套(blog、meet 各自一条自定义主机名,不能共用);设施层全局一套(ip、tunnel 所有服务共用一条,命名永远用中性名,不要带服务名)。
💡 记忆口诀:
blog/meet给人看,ip来指路,tunnel是 Cloudflare 的内部通道。 设施层建好就忘掉,浏览器里敲的、发给别人访问的,永远只有业务域名。
端口绑定写在哪?——Tunnel 的规则里
回退源不绑定任何端口。真正把"主机名 → 内网端口"对应起来的,是 Tunnel 的 Public Hostname 列表(cloudflared 按请求的 Host 头逐条匹配):
| Tunnel Public Hostname(主机名规则) | 服务 | 说明 |
|---|---|---|
tunnel.example2.com → http://localhost:8090 | 兜底 | 回退源的门牌,service 指哪个服务都行——只有直连 tunnel.example2.com 的人会看到它,SaaS 流量不走这条 |
blog.example1.com → http://localhost:8090 | Halo | 业务规则①,blog 的流量命中这条 |
meet.example1.com → https://localhost:8443(No TLS Verify) | Jitsi | 业务规则②,meet 的流量命中这条 |
两个还是三个子域名?
回退源和业务地址两个角色省不掉,区别只在于要不要 ip 这个中间层。可以省:让业务子域的 CNAME 直接指向优选域名(或优选 IP),第 4 步与第 5 步合并为一步,其余步骤不变。权衡如下:
两个子域(省掉 ip) | 三个子域(推荐) | |
|---|---|---|
| 结构 | 业务子域直接 CNAME → 优选域名 | 业务子域 → ip → 优选域名 |
| 初次配置 | 少建一条记录 | 多一步,多一个"忘建/忘灰云"的出错点 |
| 更换优选目标 | 改业务记录本身,动的是业务记录,改错即业务中断 | 只改 ip,业务记录零风险 |
| 多服务 | 每个服务各自指向优选,换一次改 N 条 | 所有服务共用 ip,换一次只改 1 条 |
| 自动优选工具(cfnb-go 等) | 只能接管业务记录本身,多服务需跑多个实例 | 完美契合:工具只碰 ip,业务记录永久免维护 |
怎么选:单个服务 + 手动维护 → 两个够用;要用自动优选工具,或有多个服务 → 用三个。优选层的所有变化(手动换、自动换、失效回滚)都发生在 ip 上,业务记录永远不动,这就是中间层的价值。
为什么业务域名和 ip 必须是灰云?
灰云(仅 DNS)意味着 Cloudflare 只负责域名解析,不接管流量代理。这样用户的浏览器会直接拿着优选 IP 去连 Cloudflare 边缘,并且 TLS 握手时 SNI 是 meet.example1.com——边缘节点靠这个 SNI 匹配到你注册的自定义主机名。
如果开了橙云,Cloudflare 会把它当成普通站点重新接管 TLS 和回源,与 SaaS 方案冲突,容易出现证书错误、ERR_TOO_MANY_REDIRECTS 或 CNAME 循环。
🛠 准备工作
- 两个域名:主域名
example1.com(放业务)+ 辅助域名example2.com(放设施,必须托管在 Cloudflare);主域名只需能添加 CNAME 和 TXT 记录 -
cloudflared已在一台内网机器上安装并登录 - 两个内网服务已就绪:Halo 博客
http://localhost:8090、Jitsi Meethttps://localhost:8443(自签证书) - Cloudflare 账号已绑定支付方式——Cloudflare for SaaS 功能本身免费(每个域名 100 个自定义主机名以内 0 元,仅用于验证身份)
- 可选:优选 IP 测速工具(CloudflareSpeedTest),或直接用公共优选域名
下文以
example1.com(主域名 / 业务)和example2.com(辅助域名 / 设施)举例,请替换成你自己的域名,其余照抄。只有一个域名?见下文**《备选:单域名方案》**一章,步骤照做,只是把辅助域名的部分换到同一个域名下。
🚀 主线配置:双域名方案(Halo 博客 + Jitsi Meet 双服务一次配齐)
分工一句话:辅助域名 example2.com 承载全部设施(回退源、优选入口、SaaS 面板),主域名 example1.com 只放用户访问的业务地址。
第 1 步:创建 Tunnel,一次添加三条 Public Hostname
- 进入 Cloudflare 控制台 → Zero Trust → Networks → Tunnels
- 点击 Create a tunnel,起个名字(如
my-tunnel),复制安装命令到内网机器上执行,确认连接状态为 Connected - 在 Public Hostnames 中依次添加三条规则(Domain 下拉可以选账号里的任何 zone):
| Subdomain | Domain | Type | URL | TLS 设置 | 说明 |
|---|---|---|---|---|---|
tunnel | example2.com | HTTP | localhost:8090 | — | 回退源门牌,指哪个服务都行 |
blog | example1.com | HTTP | localhost:8090 | — | Halo 博客 |
meet | example1.com | HTTPS | localhost:8443 | No TLS Verify | Jitsi Meet,见下方 ⚠️ |
⚠️ URL 只写
IP:端口,不要加http://前缀(协议由"类型"下拉决定)。⚠️ Jitsi Meet 用的是自签证书:类型选
HTTPS时必须展开 其他应用程序设置 → TLS,勾选 No TLS Verify(不验证 TLS 证书)——否则 cloudflared 校验源站证书失败,访问一律报 502。Halo 是 HTTP,无此问题;将来有走正式证书的 HTTPS 服务则无需勾选。⚠️ 回退源门牌(
tunnel那条)只此一条、中性命名——它是所有服务共用的门,不绑定端口;给新服务加的是"业务主机名"规则,不是新的回退源。💡 门牌指向哪里只影响"直连
tunnel.example2.com的人看到什么":指向真实服务(如 Halo)可作为分段验证探针——直连能打开 = 隧道段是通的,报错时可以二分定位;指向不存在的端口(如localhost:80,前提是 cloudflared 所在机器的 80 上没有服务)则直连一律 502,相当于焊死这个公开入口,更安全但会失去上述探针。调试期建议指向真实服务,稳定后随意。
第 2 步:开通 Cloudflare for SaaS,设置回退源
- 回到普通控制台,选择辅助域名
example2.com - 左侧 SSL/TLS → Custom Hostnames(自定义主机名)
- 如未开通,点击 Enable Cloudflare for SaaS,按提示绑定支付方式(免费,仅验证)
- 在 Fallback Origin(回退源) 中填入第 1 步配置的完整主机名:
tunnel.example2.com - 点击添加,等待状态变为 Active(有效)
⚠️ 回退源状态卡在"待部署(错误)",提示
DNS records are not setup correctly. Origin should be a proxied A/AAAA/CNAME dns record?这个报错的意思是:回退源主机名在 DNS 里找不到同名的橙云 A/AAAA/CNAME 记录。逐一检查:
- 第 1 步的
tunnel规则是否已经添加(没有它,DNS 里就没有tunnel这条记录);- 辅助域名的 DNS 记录页里
tunnel那条 CNAME 是否为橙云(灰云会报此错);- 回退源输入框填的是否为完整主机名
tunnel.example2.com,与 DNS 记录一字不差。核对后点回退源旁的"刷新",验证有几分钟延迟,稍等再刷。
第 3 步:添加自定义主机名(两条业务地址,一次加齐)
- 还是在 Custom Hostnames 页面(辅助域名
example2.com下),点击 Add Custom Hostname - Hostname 填主域名上的业务地址:
blog.example1.com,证书验证方式选 TXT - 再来一次,添加
meet.example1.com,同样选 TXT - 到主域名
example1.com的 DNS 页面添加 TXT 记录。⚠️ 每条主机名页面上列出的每一条 TXT 都要加——每条主机名通常 3 条:2 条_acme-challenge.*(证书验证,同名不同值)+ 1 条_cf-custom-hostname.*(主机名预验证)。两条主机名共 6 条 TXT,缺任何一条都过不了 - 返回 Custom Hostnames 刷新,等待证书状态变为 Active(有效)(证书签发一般需要几分钟)
⚠️ 主机名状态显示"待定(错误)"或"已移动(错误)",提示
custom hostname does not CNAME to this zone?意思是 Cloudflare 检测到自定义主机名的解析链没有落在它的边缘上。两种触发:
- 业务子域的 DNS 记录还没指向本 zone(比如仍是橙云 →
xxx.cfargotunnel.com);- 已指向
ip.example2.com,但ip底下写的不是 Cloudflare 官方 IP(如第三方反代 IP)——解析链终点不在 CF 边缘,同样不算"指向本 zone"。修复:业务子域灰云 CNAME →
ip.example2.com,且ip底下必须是官方 IP(见进阶二第 4 步),然后点"刷新"。注意证书状态(TXT 签发)不受影响、会保持有效,页面可能照常打开——但主机名不 Active 属于"带病运行",别长期放任。记住分工:TXT 验证管证书签发,解析链落在本 zone 管主机名生效,两者缺一不可。反过来看,主机名状态变回 Active 也是一道免费的验收信号——它意味着 Cloudflare 亲自确认了你的优选入口指向它的边缘。
完成后,Cloudflare 边缘就"认得" blog.example1.com 和 meet.example1.com 了,且会为它们自动签发覆盖这两个域名的边缘证书。
第 4 步:创建优选入口
在辅助域名 example2.com 的 DNS 页面添加:
| 类型 | 名称 | 目标 | 代理状态 |
|---|---|---|---|
CNAME | ip | cf.090227.xyz(公共优选域名,可换) | ⚪ 灰云 |
也可以用自己测出的优选 IP:类型选
A,目标直接填 IP 地址。之后要让 cfnb-go 自动接管这条记录的,见下文进阶二。
第 5 步:把业务域名指向优选入口
关键一步。 到主域名 example1.com 的 DNS 页面,处理第 1 步自动生成的两条记录:
| 名称 | 操作 | 最终形态 |
|---|---|---|
blog | 编辑第 1 步自动生成的记录 | CNAME → ip.example2.com,⚪ 灰云 |
meet | 编辑第 1 步自动生成的记录 | CNAME → ip.example2.com,⚪ 灰云 |
改完回自定义主机名页面点刷新,两条主机名的主机名状态应先后变为 Active——至此第 3 步完全闭环。
⚠️ 新建记录时报
An A, AAAA, or CNAME record with that host already exists?说明这个主机名下已经有一条记录了(同一主机名不允许 CNAME 与 A/AAAA 并存)——通常是第 1 步添加 Public Hostname 时 dashboard 自动生成的橙云 CNAME。不要新建,直接编辑那条已有记录:目标改成
ip.example2.com、代理状态改为灰云、保存。如果列表里那条已经是"灰云 →ip.example2.com",则什么都不用做,记录已正确。
第 6 步:SSL 设置
在辅助域名 example2.com 的 SSL/TLS 页面:
- 概述 → 右上角「配置」→ 选「自定义 SSL/TLS」→ 加密模式选完全(严格)/ Full (strict)(选"灵活 Flexible"会导致重定向循环,见故障排查;新版界面若显示"自动模式已启用",同样在「配置」里切换为"自定义"后选择)
- 左侧 边缘证书 页面:开启 始终使用 HTTPS 和 自动 HTTPS 重写
主域名
example1.com若也托管在 Cloudflare:业务记录是灰云、不经过它的代理层,本方案不依赖主域名的 SSL 设置,保持默认即可。
DNS 记录最终形态(对照检查)
| 名称 | 所在域名 | 类型 | 指向 | 云朵 | 服务 |
|---|---|---|---|---|---|
blog | example1.com | CNAME | ip.example2.com | ⚪ 灰 | Halo :8090 |
meet | example1.com | CNAME | ip.example2.com | ⚪ 灰 | Jitsi :8443 |
ip | example2.com | CNAME | 优选域名 / 优选 IP | ⚪ 灰 | 共用 |
tunnel | example2.com | CNAME | xxx.cfargotunnel.com | 🟠 橙 | 共用门牌 |
外加:Custom Hostnames 面板(在 example2.com 下)中 blog.example1.com 与 meet.example1.com 的证书状态、主机名状态均为 Active,Fallback Origin 为 tunnel.example2.com 且 Active。
配好后 example1.com 的 DNS 会非常干净:只剩业务 CNAME 和几条验证 TXT,所有"会变的、要折腾的"东西都在 example2.com 上。
🔀 备选:单域名方案
只有一个域名时,把"回退源 + 优选入口 + SaaS 面板"全部放到同一个域名下即可,其余步骤与主线完全一致。与主线只有 5 处差异:
| 配置项 | 主线(双域名) | 备选(单域名) |
|---|---|---|
| Tunnel 的回退源规则 | tunnel.example2.com | tunnel.example1.com |
| SaaS 开在哪个域名 | example2.com(辅助域名) | example1.com |
| 回退源地址 | tunnel.example2.com | tunnel.example1.com |
| 优选入口 | ip.example2.com | ip.example1.com |
| 自定义主机名的 TXT 验证 | 加在主域名 example1.com 的 DNS | 加在同一域名的 DNS |
怎么选:双域名把"会变的设施"和"业务域名"彻底隔离——主域名换 DNS 服务商、增删业务时,辅助域名上的设施不用动,推荐。单域名少买一个域名、少管一个控制台,适合只有一个域名或追求最简的场景。
从单域名配置切换到双域名?(清理清单)
- Zero Trust 里把原来的回退源规则 Domain 改为辅助域名(或删除重建),让它生成
tunnel.example2.com - 回退源改为
tunnel.example2.com(在辅助域名的 Custom Hostnames 页面重新填写) - 删除主域名 DNS 里旧的
tunnel记录(Tunnel 自动生成的橙云 CNAME)和ip记录——优选设施已整体搬到辅助域名 - 主域名各业务子域的 CNAME 改指
ip.example2.com(辅助域名下的优选入口)
🧩 进阶一:再添加更多服务
第 4 个、第 5 个服务?照葫芦画瓢,每个服务四步(以新的"服务三"为例):
- Tunnel 加一条业务规则:Public Hostname 添加,Subdomain 起名、Domain 选
example1.com、类型和 URL 填服务的协议端口(HTTPS 自签服务记得勾 No TLS Verify); - SaaS 加一条自定义主机名:
服务三.example1.com,TXT 验证的 3 条 TXT 加到example1.com的 DNS; - 主域名 DNS:把第 1 步自动生成的同名橙云记录编辑成灰云 CNAME →
ip.example2.com; - 回自定义主机名页刷新,等两个状态 Active。
回退源和优选入口都不动——它们是全局设施。回退源是 zone 级设置、只能填一个;优选入口也是全体服务共用一条。
💡 也可以不拆子域、用路径区分(如
blog.example1.com/ha),但需要手写 config.yaml 的 path 规则,且不少内网服务假设自己部署在根路径,容易踩坑——推荐用子域。
🤖 进阶二:配合 cfnb-go 全自动优选
优选 IP 会随时间失效(见常见问题 #5),手动更换很麻烦。可以让 cfnb-go 接管 ip 这条记录:它定期从多个数据源聚合 Cloudflare IP,经 TCP 延迟、HTTP 延迟/抖动、真实带宽多重测速后,把最优的一批 IP 自动批量写入 Cloudflare DNS。这也正是"优选入口"单独用一个子域的价值——工具只碰 ip,业务记录永远不用动。
对接步骤
- 创建 API Token:Cloudflare 右上角头像 → My Profile → API Tokens → Create Token → 模板选 Edit zone DNS,Zone Resources 选择辅助域名(优选入口所在域名)→ 创建并复制 Token
- 记下 Zone ID:辅助域名概览页右下角
- 修改 cfnb-go 的
config.json关键字段:
| 字段 | 值 | 说明 |
|---|---|---|
CF_ENABLED | true | 开启 DNS 自动更新 |
CF_API_TOKEN | 上一步的 Token | 只需 Zone → DNS → Edit 权限 |
CF_ZONE_ID | 辅助域名的 Zone ID | 优选入口所在的那个 zone |
CF_DNS_RECORD_NAME | ip.example2.com | 被接管的优选入口(完整主机名) |
DNS_RECORD_TYPE | A | ⚠️ 默认是 TXT,必须改成 A |
DNS_UPDATE_TARGET_COUNT | 15 | 每轮写入 15 条 A 记录,解析时轮询分发 |
CF_PROXIED | false | ⚠️ 保持默认——优选入口必须灰云 |
-
先收紧数据源,只留 Cloudflare 官方 IP 源:默认
ADDITIONAL_SOURCES里的第三方反代源(ipdb.api.030101.xyz?type=bestproxy)和聚合大列表(zip.cm.edu.kg等)混有大量非 Cloudflare 的第三方服务器 IP——实测会写入 Azure/DigitalOcean 之类的机器,测速通过但业务域名直接ERR_CONNECTION_TIMED_OUT。本方案的优选目标必须是 Cloudflare 官方 anycast IP(边缘节点才认 SNI)。推荐只保留这三个(解析出的都是官方 IP),其余enabled: false:"ADDITIONAL_SOURCES": [ { "url": "cf.090227.xyz", "enabled": true }, { "url": "cf.877774.xyz", "enabled": true }, { "url": "https://ghproxy.net/https://raw.githubusercontent.com/yuanxiawan/cfipv4db/refs/heads/main/high_score_ips.txt", "enabled": true } ] -
删掉手动建的
ipCNAME(就是第 4 步建的那条:辅助域名 DNS 里ip→ 优选域名):cfnb-go 只按 A 类型清理旧记录,残留的 CNAME 会和新 A 记录冲突,导致写入失败。tunnel(回退源)和主域名里的业务 CNAME 都不用动。删完后ip会短暂无解析、业务域名暂时打不开——立即手动跑一轮 cfnb-go(docker compose -f deploy/docker-compose.yml run --rm cfnb)把空窗缩到最短。
⚠️ 删了 CNAME 又不运行 cfnb-go ≠ 回退到不优选,而是整条解析链断裂:业务子域的 CNAME 指向ip这个中间层,它底下没有记录时blog/meet直接解析失败、完全打不开。想临时放弃优选,正确做法是把业务记录编辑回橙云 →xxx.cfargotunnel.com(恢复 Tunnel 默认入口),而不是留空中层。 -
验证:
dig ip.example2.com +short应返回一批 Cloudflare 官方 IP(104.x 等段,而不是 Azure/DigitalOcean 之类的第三方机器);DNS 页面ip名下出现一批灰云 A 记录
之后每一轮:cfnb-go 测速 → 原子替换 ip 的全部 A 记录 → 所有指向 ip 的业务域名自动用上最新优选,全程无需人工干预。
💡 多地部署(如公司、家里各一台设备各一条隧道):两台机器同时跑 cfnb-go、各写各的优选入口记录即可,互不干扰——完整拓扑与注意事项见 cfnb-go README《多实例部署:多台机器 / 多个域名同时优选》。本站的完整落地步骤(拓扑选型、双隧道域名规划、Docker 速查)见下文**《🏢 进阶三:两地部署》**。
优选 IP 不可达:业务域名报 ERR_CONNECTION_TIMED_OUT
自动优选后浏览器报"响应时间过长 / 连接超时"(不是 DNS 错误,也不是 404/502)= 解析成功但选出的 IP 在你的网络下连不上——通常是 cfnb-go 的测速环境与浏览器环境不一致,或选入了不可靠的第三方反代 IP。三步定位:
# 1. 看 cfnb-go 写入了哪些 IP(Windows 用 nslookup)
nslookup ip.example2.com
# 2. 逐个测 443 端口可达性
# PowerShell:Test-NetConnection <IP> -Port 443(TcpTestSucceeded : True 即通)
# cmd 用自带的 curl(出现 TLS/证书相关输出 = TCP 通;Timed out = 不通):
# curl -sv --connect-timeout 5 https://<IP>:443
Test-NetConnection <上面拿到的某个IP> -Port 443
# 3. 对照公共优选域名(它可达 → 问题在 cfnb-go 选出的 IP)
Test-NetConnection cf.090227.xyz -Port 443
修复与恢复:
- config.json 里把第三方反代源(如
ipdb.api.030101.xyz?type=bestproxy)enabled: false,只留 Cloudflare 官方 IP 源,重新跑一轮; - 确认 cfnb-go 的运行网络与浏览器走同一出口(同一宽带/运营商),测出的结果才对你有效;
- 恢复访问的临时办法:把业务子域记录改回橙云 →
xxx.cfargotunnel.com(默认入口,慢但能访问),修好后再改回灰云 →ip.example2.com。
⚠️ 注意:TCP 可达 ≠ 可用。 实测踩坑:第三方反代 IP 的 TCP 443 可能全部可达(TcpTestSucceeded: True),但浏览器照样 ERR_CONNECTION_TIMED_OUT——反代机接受了 TCP 连接,却对自定义域名的 SNI 静默丢弃(它们面向的是代理工具场景,转发的是 Cloudflare 官方域名的 SNI)。决定性验证(模拟浏览器的 TLS 行为,PowerShell 用 curl.exe):
# 经第三方 IP 访问你的域名——预期 TLS 挂起/超时
curl.exe -sv --connect-timeout 8 --resolve meet.example1.com:443:<第三方IP> https://meet.example1.com
# 经 Cloudflare 官方 IP 访问你的域名——预期握手成功、返回页面
curl.exe -sv --connect-timeout 8 --resolve meet.example1.com:443:<官方IP> https://meet.example1.com
⚠️ 变体症状:页面能打开、应用报"Connection error"(如 Jitsi Meet 的黄色警告页)。多连接应用(页面 + WebSocket + XMPP 信令)在 DNS 轮询下会命中不同的优选 IP——页面命中的活着、WebSocket 命中的死了,于是"页面正常、信令失败"。橙云(全部连接走官方边缘)正常、灰云报错,即为此症。根治方法相同:优选入口只写 Cloudflare 官方 IP。
这也是测速工具在此场景的盲区:HTTP 检测用的 SNI 是 Cloudflare 官方域名,反代会转发;而浏览器用的 SNI 是你的自定义域名,行为不可控。优选目标必须是 Cloudflare 官方 anycast IP——SNI 路由、证书、回退源整套机制只存在于官方边缘。
❓ 常见疑问:第三方反代 IP 有可能比官方 IP 更快,为什么不用?
有可能——优质线路 VPS(CN2 GIA / CMI)反代到 Cloudflare 快速 PoP,端到端确实可能超过 Anycast 给你分配的默认路径(官方 anycast 路由到哪个 PoP 由 BGP 决定,你无法选择)。但对对外提供服务的域名,速度换不来这四条代价:① SNI 行为不可控(实测 TCP 通但浏览器超时);② 寿命只有分钟~天级(官方 anycast 是周月级);③ L7 反代能看到明文流量;④ Cloudflare 主机名校验不通过,证书续期与路由保障失去官方承诺。
场景区分:代理工具自己用(挂了换一个就行)→ 第三方反代合理;对外服务的域名(7×24、多用户)→ 只用官方 IP。另外官方 IP 段内部本身就有优选空间(不同官方 IP 路由到不同 PoP,
cfipv4db扫的就是这个),官方段内优选已能拿到大部分收益。
另一个常见分支:本地路由器 / 自定义 DNS 报 Server failed(SERVFAIL)——如 OpenWrt/ImmortalWrt、AdGuard Home、SmartDNS 等环境。用公共 DNS 对比:
nslookup ip.example2.com 223.5.5.5
- 公共 DNS 正常、路由器 SERVFAIL → 本地 DNS 的问题。特别注意:若写入的记录里混入了私有地址(数据源脏数据),开启了 rebind 保护的 dnsmasq 会拒绝整个响应——cfnb-go 换用纯 Cloudflare 官方 IP 源重跑即可根治;
- 公共 DNS 也查不到 → 去辅助域名的 DNS 页面确认
ip名下是否真的写入了 A 记录(cfnb-go 日志应有"已将 ip.example2.com 指向 N 个 IP"),没有则是它的 API 配置问题(Token 权限 / Zone ID / 记录名)。
还有一层容易漏掉:浏览器自带的"安全 DNS"(DoH)会绕过系统 DNS——Chrome/Edge 开启后走自己的 DoH 端点,nslookup(走系统 DNS)与浏览器的解析结果可能完全不同,尤其是来源不明的自定义 DoH 端点,可能存在分流 / 假 IP(fake-ip)行为,导致"直连 IP 测试全通、浏览器却超时"的矛盾现象。若两者表现不一致,先在浏览器设置里关闭安全 DNS(或换成 https://dns.alidns.com/dns-query 等公共 DoH),到 chrome://net-internals/#dns 清除主机缓存后对比测试,最终让浏览器解析与系统解析收敛到同一个可信上游。
🛠 如果坚持使用第三方反代源(不换官方 IP),把运行姿态调整为"接受故障、快速恢复":
- 主机名状态会持续显示"已移动(错误)"——功能可用但属带病运行,心里有数即可;
RUN_INTERVAL保持短周期(默认 5 分钟级),死掉的 IP 最快在下一轮被原子替换;DNS_UPDATE_TARGET_COUNT保持较大(如 15),多 IP 轮询分摊"命中死 IP"的概率;- 开启 WxPusher 通知,筛选/DNS 异常第一时间知道;
- 盯证书到期日:主机名不 Active 时证书可能不自动续期,到期前一个月回到 Custom Hostnames 页面确认证书状态,必要时删除重新添加、走一次 TXT 验证;
- 多连接应用(Jitsi)会偶发 "Connection error"——这是第三方源的固有代价,出现时手动重跑一轮 cfnb-go 即可临时恢复。
更新频率怎么选
运行间隔由 RUN_INTERVAL 控制(Docker 部署在 deploy/.env 里改,默认 300 秒):
| 场景 | 建议 |
|---|---|
| 网页 / API 加速(Halo 博客) | 15 ~ 30 分钟 |
| 实时音视频(Jitsi Meet / WebRTC 类) | 12 ~ 24 小时,或固定一批 IP——媒体流走 UDP 直连不经 Cloudflare,优选只影响网页与信令;频繁切 IP 会中断进行中的会话 |
💡 两个服务共用一个
ip入口时取折中:30 分钟 ~ 2 小时皆可;若 Jitsi 会议频繁,倾向更长的间隔。
🏢 进阶三:两地部署 —— 公司 + 家里两台设备
一句话总结:两台设备都跑 cloudflared ≠ 双倍保险,先分清两台机器上的服务是什么关系。同一套服务互为备份 → 保持一条隧道、两台各挂一个连接器(官方高可用形态);服务只在一台上 → 停掉多余那台的连接器;两地各跑各的服务 → 必须拆成两条隧道、两套设施层。最常见的错误形态是"同一条隧道挂两台、服务只在一台上":请求随机派发,约一半概率落到没跑服务的那台,业务域名时好时坏。
先看懂:隧道规则不区分连接器
Tunnel 的 Public Hostname 规则是整条隧道级别的,不跟某台机器绑定。一条隧道挂两个连接器时,边缘会把每个请求随机派给任一健康的连接器,再由它在自己那台机器上按规则找 localhost:端口:
flowchart TD
U["👤 访问 blog.example1.com"] --> CF["🌐 边缘 → SaaS 回退源 → 隧道"]
CF -->|"随机派发 ①"| C1["🏢 公司连接器:本机 8090 有 Halo → 200"]
CF -->|"随机派发 ②"| C2["🏠 家里连接器:本机没跑 Halo → 502"]
- 服务只在一台上 → 约一半请求 502,典型症状是时好时坏、刷新一下又好了;
- 两台都跑同一服务 → 高可用成立,但数据一致性要自己解决——Tunnel 只帮你切流量,不帮你同步数据。
查一下自己现在是哪种:Zero Trust → Networks → Tunnels → 点开隧道名 → Connectors。列出 2 个连接器 = 两台连的是同一条隧道。
先对号入座:三种情况
| 你的实际情况 | 正确做法 | 看哪节 |
|---|---|---|
| 两台跑同一套服务,想互为备份 | 保持一条隧道 + 双连接器(这就是官方 HA) | 情况 A |
| 服务只在一台上(比如只在家里),另一台当时顺手也接上了 | 停掉多余连接器;或给它单建隧道跑它自己的服务 | 情况 C |
| 两台跑不同的服务,都要对外暴露 | 拆两条隧道,第二个站点补一套设施层 | 情况 B |
| 其实想要的是两地内网互访(不对外暴露) | 不走本方案:Private Network + WARP,见章末提示 | 章末 |
情况 A:同一套服务,两地互为备份(一条隧道 + 双连接器)
这是唯一"两台连同一条隧道"是对的场景,主线配置一字不改:一条隧道、一个回退源、一个优选入口、同一批自定义主机名。两台设备用同一个 token 各起一个 cloudflared 容器即可。要成立,必须满足:
- 两台的服务和端口完全一致——规则说
blog → localhost:8090,两台机器的 8090 上都得真有服务,缺谁的谁就随机 502; - 数据一致性自理——Halo 这类有状态服务两台各存一份 = 内容漂移:要么共享同一个数据库/存储,要么接受"一台为主、另一台冷备";
- cfnb-go 只在一台跑——两台都写同一条
ip记录会互相覆盖、来回翻转(两边网络测出的最优 IP 本就不同),等于自己把自己的 DNS 折腾坏。
验证:docker stop cloudflared 停掉一台,业务域名应只中断几秒(另一台接住全部流量)。这就是双连接器买到的东西——连接器级冗余,顺便让 cloudflared 升级可以一台一台来、全程不断流。
加分项:按"访问者"拆主机名,两地各自优选
优选 IP 取决于访问者所在的网络,跟服务器在哪无关——一条 ip 记录同时服务"在公司访问"和"在家里访问",一边测出的优选对另一边未必最优。解法是再注册一对业务主机名、按"人在哪"分流,仍然只要两个域名:两条都是 example2.com 下的自定义主机名(TXT 照加、隧道里各加一条业务规则,都指向同一个服务),都落回同一条隧道:
| 名字 | CNAME 指向 | 由谁优选 |
|---|---|---|
blog-home.example1.com | ip-home.example2.com | 家里机器的 cfnb-go |
blog-office.example1.com | ip-office.example2.com | 公司机器的 cfnb-go |
ip-home / ip-office 是两条不同名的记录,两台 cfnb-go 各写各的、互不干扰;人在公司就用 blog-office,在家就用 blog-home。代价:主机名和 TXT 翻倍,且"同一服务两个网址"的心智负担略增——非重度两地使用可以不做,保持单主机名 + 单 ip 的折中即可。
情况 C:服务只在一台上 —— 停掉多余连接器
最常见也最容易被忽略:服务只在家里,公司那台"顺手"也接进了同一条隧道。此时的公司连接器是纯粹的随机 502 源,不提供任何冗余价值——直接在公司的设备上 docker compose down(或 docker rm -f cloudflared)停掉它,业务域名立刻 100% 稳定。哪天公司设备上真有服务要暴露,再按情况 B 单建一条隧道。
公司设备停掉连接器后,若还想让"人在公司时访问家里服务更快",用情况 A 的加分项即可——源站仍是家里那条隧道,只是给公司网络单独优选一条
ip-office。
情况 B:两地各跑各的服务(两条隧道 + 两套设施层)
✅ 已经用不同 token 建了两条隧道(公司、家里各一条)? 拓扑已经对了——主线第 1 步里"建隧道"这半步天然完成。自检:Tunnels 列表应有两条隧道、Connectors 各 1 个;若哪条隧道下显示 2 个连接器,说明 token 用重了,那台要改连自己的隧道。接下来的工作:让第二条隧道的流量有自己独立的"门"——要么补一套它自己的设施层(回退源 + SaaS 面板 + 优选入口,需第三个域名),要么用 Custom Origins 在现有辅助域名里开一扇门(两个域名就够,见下文《只有两个域名?》),小心下面的回退源约束。
为什么一条隧道装不下
两个硬约束:
- 隧道规则不区分连接器(本进阶开头讲过)——
oa.example1.com → localhost:8080这条规则两台机器都会执行,谁家没有这个服务谁就 502; - 回退源是 zone 级设置、一个辅助域名只能填一个(进阶一末尾也提过)——它决定该域名下所有自定义主机名的流量最终回哪条隧道。公司服务的流量进了家里的隧道,家里可没有公司那台机器。
所以:一条隧道服务一个站点——公司站点的流量必须能送进公司那条隧道:要么给它第二个辅助域名(回退源各指各的,见上面的域名规划),要么用 SaaS 的 Custom Origins(自定义源) 在同一个辅助域名里给它单独"开一扇门"(见下文《只有两个域名?》)。
⚠️ 踩中约束的症状:如果第二个站点的业务主机名注册后走的是默认回退源(没配自定义源、也没换辅助域名),它的流量会稳定地涌进回退源指向的那条隧道——表现为第二个站点的业务域名恒定 404/502(不是时好时坏:流量一直进错隧道,而那条隧道里没有它的 Host 规则)。修法:改注册到第二个辅助域名的 SaaS 下(回退源各指各的隧道),或给该主机名配 Custom Origins 自定义源。
域名规划(3 个域名;只有两个域名也能做,见下文《只有两个域名?》)
| 站点 | 业务域名(都在 example1.com) | 辅助域名(设施层) | 回退源 | 优选入口 |
|---|---|---|---|---|
| 🏠 家 | blog / meet | example2.com | tunnel.example2.com → 隧道① | ip.example2.com |
| 🏢 公司 | oa(示例) | example3.com(新购,托管到同一个 Cloudflare 账号) | tunnel.example3.com → 隧道② | ip-office.example3.com |
flowchart TD
B1["👤 blog / meet.example1.com"] -->|"CNAME → ip.example2.com"| E1["🌐 边缘(example2.com 的 SaaS)<br>回退源 tunnel.example2.com"]
E1 --> T1["🏠 隧道①:家里 cloudflared<br>Halo :8090 / Jitsi :8443"]
B2["👤 oa.example1.com"] -->|"CNAME → ip-office.example3.com"| E2["🌐 边缘(example3.com 的 SaaS)<br>回退源 tunnel.example3.com"]
E2 --> T2["🏢 隧道②:公司 cloudflared<br>公司要暴露的服务"]
配置步骤:主线第 1~6 步 × 2
两个站点各自完整走一遍主线第 1~6 步,只是名字按下表替换:
| 主线步骤 | 站点① 家里 | 站点② 公司 |
|---|---|---|
| 第 1 步 隧道 | my-tunnel-home,规则:tunnel.example2.com + 家里各业务主机名 | my-tunnel-office,规则:tunnel.example3.com + 公司各业务主机名 |
| 第 2 步 回退源 | tunnel.example2.com(example2.com 的 SaaS 面板) | tunnel.example3.com(example3.com 的 SaaS 面板) |
| 第 3 步 自定义主机名 | blog / meet.example1.com,TXT 加在 example1.com | oa.example1.com 等,TXT 也加在 example1.com |
| 第 4 步 优选入口 | ip.example2.com | ip-office.example3.com |
| 第 5 步 业务 CNAME | → ip.example2.com | → ip-office.example3.com |
| 第 6 步 SSL 设置 | example2.com:完全(严格) | example3.com:完全(严格) |
易错点:
- ⚠️ 两条隧道绝不共用 token——同 token = 同一条隧道,又绕回"随机派发"的老问题。第二条隧道在 Zero Trust 里单独 Create a tunnel,用它自己的 token 起公司那台的容器。
- ⚠️ TXT 验证记录全部加在主域名 example1.com 的 DNS 里,两个站点加起来十几条,命名/备注区分清楚,千万别互删。
- ⚠️ 两个 SaaS 面板分别位于
example2.com和example3.com的 SSL/TLS → Custom Hostnames 下,加自定义主机名时先看一眼当前 zone,别加错面板。 example3.com必须添加到同一个 Cloudflare 账号——第 1 步隧道规则的 Domain 下拉里要能选到它。
cfnb-go 两地各跑一份
即进阶二末尾"多地部署"提示的完整版:两台机器各跑一份 cfnb-go、各写各的优选入口记录,互不干扰。两份配置只有这几处不同:
| 配置项 | 家里那份 | 公司那份(3 域名方案) | 公司那份(2 域名方案) |
|---|---|---|---|
CF_API_TOKEN | 只授权所在 zone 的 DNS 编辑 | 只授权 example3.com | 同一个 example2.com 的 Token 即可 |
CF_ZONE_ID | example2.com 的 Zone ID | example3.com 的 Zone ID | 同一个 example2.com 的 Zone ID |
CF_DNS_RECORD_NAME | ip.example2.com | ip-office.example3.com | ip-office.example2.com |
- 优选必须在各自网络下测:公司宽带和家庭宽带的最优 IP 基本不同,把家里测出的结果写进
ip-office是无效的——好在两份实例天然就在各自网络里跑,这正是"各写各的"的价值; - 公司网络若禁 UDP(QUIC 走 7844),cloudflared 会自动回落到 http2/443,也可显式指定(见下方 Docker 速查)。
只有两个域名?用 Custom Origins 给第二条隧道"开一扇门"(推荐)
Custom Origins(自定义源)是 Cloudflare for SaaS 的官方功能:给个别自定义主机名指定"不走默认回退源、改走另一个源服务器",全部套餐可用(含 Free)。于是一个辅助域名就能同时服务两条隧道——默认回退源进家里隧道,公司主机名单独指定进公司隧道:
flowchart TD
B1["👤 blog / meet.example1.com"] --> E1["🌐 边缘:SNI 匹配自定义主机名<br>未配自定义源 → 默认回退源 tunnel.example2.com"]
E1 --> T1["🏠 隧道①(家里)"]
B2["👤 oa.example1.com"] --> E2["🌐 边缘:SNI 匹配自定义主机名<br>配了自定义源 → tunnel-office.example2.com"]
E2 --> T2["🏢 隧道②(公司)"]
在主线第 1~6 步的基础上,只多 3 个动作:
- 公司隧道加门牌:隧道②的 Public Hostname 加一条
tunnel-office+example2.com(Type/URL 随意,比如 HTTP →localhost:80)——dashboard 自动生成橙云 CNAME,指向隧道②的cfargotunnel.com,这就是公司主机名的自定义源; - 公司业务主机名配自定义源:在 example2.com 的 Custom Hostnames 面板添加
oa.example1.com时,在**源服务器(Origin Server)**处选择自定义源 →tunnel-office.example2.com(API 创建则带"custom_origin_server"参数);TXT 照旧加在 example1.com; - 优选入口分家:example2.com 的 DNS 新增一条灰云记录
ip-office(家里现有的ip不动),公司 cfnb-go 只写ip-office——同一台 cfnb-go 配置里只有记录名不同。
DNS 最终形态(对照检查):
| 名称 | 所在域名 | 类型 | 指向 | 云朵 | 说明 |
|---|---|---|---|---|---|
blog / meet | example1.com | CNAME | ip.example2.com | ⚪ 灰 | 家里业务,主线原样不动 |
oa | example1.com | CNAME | ip-office.example2.com | ⚪ 灰 | 公司业务 |
ip | example2.com | A | 家里 cfnb-go 写入的优选 | ⚪ 灰 | 家里 cfnb-go 接管 |
ip-office | example2.com | A | 公司 cfnb-go 写入的优选 | ⚪ 灰 | 公司 cfnb-go 接管 |
tunnel | example2.com | CNAME | 隧道①的 cfargotunnel.com | 🟠 橙 | 默认回退源 |
tunnel-office | example2.com | CNAME | 隧道②的 cfargotunnel.com | 🟠 橙 | 公司主机名的自定义源 |
注意:
- ⚠️ 自定义源必须是同账号里一条橙云 A/AAAA/CNAME 记录(不能直接填 IP、不支持通配符)——第 1 步的门牌正好满足;
- ⚠️ 添加公司主机名时忘了选自定义源 = 它走默认回退源进家里隧道,恒定 404——回面板补选即可,证书与 TXT 都不用重做;
- 隧道回源不经过传统 TLS 回源,官方文档里 Full (strict) / SNI rewrite 的注意事项与隧道场景无关;
- 家里的 blog/meet 什么都不用改——已 Active 的自定义主机名、已签发的证书全部保持原样。
其他替代:公司业务走橙云经典(example1.com 托管在 Cloudflare 时,公司子域橙云 CNAME → 隧道②的
cfargotunnel.com)——零新概念但入口 IP 随机无优选,主域名在第三方 DNS 则此路不通。第三个域名始终是"最对照主线"的选项,想要业务/设施彻底隔离时随时可加。
Docker 部署速查(两台通用)
# docker-compose.yml —— 每台设备一份
# 情况 A(一条隧道双连接器):两台填同一个 TUNNEL_TOKEN
# 情况 B(两条隧道):两台各填各的 token,绝不能相同
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate run
network_mode: host # Linux(NAS/小主机)推荐:容器里的 localhost 就是宿主机
# 用不了 host 模式(Windows/macOS/部分 NAS)就删掉上一行,并做两件事:
# 1) Public Hostname 的 URL 里 localhost 全改成 host.docker.internal
# 2) 加一行: extra_hosts: ["host.docker.internal:host-gateway"]
environment:
- TUNNEL_TOKEN=<你的TUNNEL_TOKEN> # Zero Trust → 该隧道 → Install connector 页可复制
- TUNNEL_TRANSPORT_PROTOCOL=http2 # 可选:公司网络禁 UDP/QUIC 时强制走 443,其余场景删掉
升级照旧 docker compose pull && docker compose up -d;双连接器(情况 A)时一台一台升——先升一台、状态 Connected 且业务正常后再升另一台,全程不断流。
公司设备注意事项
- ⚠️ 先确认公司允许:在公司设备上对外暴露服务前想清楚合规与审计风险;只放个人服务,绝不把公司内网网段加进 Private Network 路由;
- 公司防火墙可能拦 cloudflared 的出站(QUIC/UDP 7844、443)——拦了就用
TUNNEL_TRANSPORT_PROTOCOL=http2走 443; - 公司宽带出口多变(NAT/代理),
ip-office的优选结果以"你人在公司时实际访问"为准,失效就重跑一轮。
❓ 想要的其实是"公司内网 ⇄ 家里内网"互相访问(比如在家连公司 NAS、在公司连家里下载机),而不是把服务暴露到公网?那是另一套玩法:Tunnel 的 Private Network 路由 + WARP 客户端,按网段路由、不经 SaaS 优选链路,参见 Cloudflare 官方文档。
💡 记忆口诀:同服务 → 一条隧道多连接器;不同服务 → 一条隧道一个站点;优选看的是访问者的网络,不是服务器的。
✅ 验证
1. 浏览器直测
- 访问
https://blog.example1.com,应看到 Halo 博客; - 访问
https://meet.example1.com,应看到 Jitsi Meet。
可按 F12 → Network 查看证书,确认覆盖对应业务域名。
2. DNS 解析检查
# 业务域名应先指向优选入口
dig blog.example1.com +short
dig meet.example1.com +short
# 预期输出:ip.example2.com.(单域名方案则为 ip.example1.com.)
# 再往下解析就是优选域名或优选 IP
# 回退源应指向隧道
dig tunnel.example2.com +short
# 预期输出:xxx.cfargotunnel.com.
# (单域名方案:改查 tunnel.example1.com)
3. 分段验证
- 直连回退源
https://tunnel.example2.com(单域名方案为https://tunnel.example1.com)——应看到 Halo 博客(第 1 步门牌规则指向的服务),说明"隧道 + 回退源"这段是通的; - 再访问
https://blog.example1.com和https://meet.example1.com——都能打开且速度提升,说明"优选 + SNI 匹配 + Host 分流"整条链路是通的。
⚠️ 常见问题排查
1. ERR_TOO_MANY_REDIRECTS
- 原因:SSL/TLS 加密模式设为"灵活 (Flexible)",与源站强制 HTTPS 循环跳转。
- 解决:加密模式改为 完全 (Full) 或 完全(严格),Tunnel 的 Public Hostname 类型按服务实际协议选。
2. 502 Bad Gateway
- 可能原因:cloudflared 未运行、内网服务未启动、Public Hostname 的 URL/类型填错、HTTPS 服务是自签证书但没勾 No TLS Verify、自定义主机名未到 Active。
- 排查:先直连回退源(双域名为
https://tunnel.example2.com,单域名为https://tunnel.example1.com)。通了说明隧道没问题,问题在自定义主机名;不通则检查 cloudflared 进程、URL 配置和 No TLS Verify。
3. 404(页面显示 Not Found)
- 原因:自定义主机名的流量进了隧道,但 Tunnel 里没有与该业务主机名同名的 Public Hostname 规则,落到 catch-all 404。
- 解决:回退源规则不参与分流——每个业务主机名都要有一条同名的 Public Hostname(如
meet+example1.com),URL 指向对应服务端口。
4. 证书报错 / 证书不覆盖业务域名
- 原因:自定义主机名未生效,TXT 验证未完成。
- 解决:到 Custom Hostnames 页面检查状态,按提示补齐 TXT 记录后等待 Active。
5. 用了一段时间又变慢了
- 原因:优选 IP / 优选域名会随时间失效。
- 解决:定期更新
ip记录指向的优选域名或 IP;可用 CloudflareSpeedTest 测速,或用 cfnb-go 全自动优选并更新 DNS(见进阶二)。
6. 出现 Error 1014: Cross-User Banned 或 CNAME 循环
- 原因:业务子域或
ip记录开了橙云,代理层互相嵌套。 - 解决:检查这些记录必须是灰云(见上文"为什么业务域名和 ip 必须是灰云")。
7. Jitsi Meet:页面能开但报 "Connection error",或进了会议音视频不通
这是两个不同层的问题,别混为一谈:
- "Connection error"(黄色三角全屏页)是信令层(XMPP/WebSocket)失败,发生在进会议室之前或会议掉线时。排查方向是本文的全部内容:优选 IP 是否官方、WebSocket 是否经稳定路径到达隧道。
- "进了会议室但音视频不通/会议崩溃"是媒体层:浏览器与 JVB 之间的音视频走 UDP 10000,Cloudflare Tunnel 不支持 UDP——这与优选无关,橙云灰云都一样。单人测试不会暴露此问题,双人音视频测试才会。
- 媒体层解法:启用 JVB 的 colibri-ws(媒体改走 WebSocket 经 Tunnel 中继,音视频可用但有性能损耗),或部署 TURN/TLS,或接受"外部访问仅信令、局域网内音视频正常"的局限。
评论区