海外云服务器搭建 Cloudflare Tunnel 免公网 IP 内网穿透完整教程(2026最新版)

📅 · ChengziCloud - 一站式云端服务

Meta Description: 海外云服务器搭建 Cloudflare Tunnel(cloudflared)零信任隧道完整教程:无需公网 IP、无需开放入站端口,把家里或内网的服务安全发布到公网域名。覆盖 cloudflared 安装、连通性预检、CLI 与 Dashboard 双路线建隧道、config.yml 多站点 ingress 配置、系统服务常驻、Zero Trust Access 身份认证、SSH/RDP/任意 TCP 与私有网络 CIDR 路由、性能与多副本调优,另含与 frp / WireGuard / Nginx+SSL 的边界对比表、服务器配置推荐表、服务商价格参考表,以及 10 条常见问题 FAQ。

> 关键词:Cloudflare Tunnel 教程、cloudflared 安装、内网穿透、免公网 IP 发布服务、Zero Trust Access、cfargotunnel、Cloudflare 隧道、海外云服务器内网穿透、cloudflared config.yml、SSH 通过隧道

前言:没有公网 IP,就不配让服务上线吗?

一句话答案:Cloudflare Tunnel(客户端叫 cloudflared)是 Cloudflare 官方的开源隧道工具,它让服务器上的 cloudflared 主动向外、只出站地连到 Cloudflare 全球边缘网络,再由边缘把你指定的域名流量"倒灌"回你的内网服务——于是你既不需要公网 IP,也不需要开放任何一个入站端口,连 TLS 证书都交给 Cloudflare 边缘代管,而隧道本身不额外收费。

这件事之所以值钱,是因为绝大多数人卡住的地方根本不是"不会配 Nginx",而是根本没有一个可以对外开的门:

- 家宽早就没有公网 IP 了。 运营商普遍做 CGNAT,你在路由器上折腾一小时端口映射,最后发现上一级根本没有把公网地址分给你,DMZ 无从谈起。 - 有公网 IP 也不敢开端口。 把 MySQL 的 3306、Redis 的 6379、RDP 的 3389 或者宝塔面板的 8888 直接映射到公网,快的情况下几个小时就会出现在全网扫描器的字典里——本站《网站安全加固》篇里反复讲过,暴露端口等于把爆破入口挂在网上等别人来试。 - 企业/校园网络只放行出站。 很多单位的内网出口策略是"出站随便、入站全禁",你在这种网络里部署的任何服务,用传统反代方案都无法对外提供。 - 证书与备案是额外的两座山。 自建 Nginx 反代要签证书、要续期;想在国内合规地开 80/443,还得走域名备案流程。 - 走第三方内网穿透,免费档基本都要你的钱或者你的脸。 要么按流量收费,要么免费档强制在别人域名下、并且给公网页面加一个插页提示。

Cloudflare Tunnel 这套方案之所以在自建圈子里流行,是因为它把上面五件事一次性解掉了:连接方向反过来(只出站),发布动作交给边缘(域名与证书由 Cloudflare 管),访问控制交给 Zero Trust(在应用前面加一层身份验证),而它本身在免费额度内不额外计费。 它甚至被官方明确设计为"轻量到能在树莓派、笔记本或数据中心服务器上跑",你的服务器配置只需要负责跑业务,不负责扛流量。

如果你手上已经有一台海外云服务器在跑 Nextcloud 私有云盘、Jellyfin 媒体库 或者 Docker + Portainer,但一直因为"不敢开端口"而只能在内网访问,那么这篇教程就是为你写的。推荐用阿里云国际版/AWS/腾讯云国际版部署,通过 5.chengzicloud.cloud 购买享折扣——把机器放在香港/日本/新加坡,隧道到 Cloudflare 边缘的回程质量会明显好过放在欧美机房。

本文给出可直接复制执行的完整命令,以 Ubuntu 22.04 / Debian 12 为主线,并给出 CentOS 7 / RHEL 的 RPM 路线;从装客户端、做连通性预检,到两条建隧道路线(CLI 本地管理 + Dashboard 远程管理)、接真实站点、加身份认证、把 SSH 和数据库也接进去、调优端口与副本,最后附服务器配置推荐表、服务商价格参考表、同赛道方案对比表和 10 条常见问题。

一、先分清边界:Cloudflare Tunnel 和你已经装过的东西各管什么

自建圈最大的困惑不是"怎么装",而是"这么多工具到底该用哪个"。下表先把边界切干净,避免你把 Tunnel 当成万能药:

| 工具 | 它回答的问题 | 前提条件 | 与本文的关系 | |---|---|---|---| | Cloudflare Tunnel(cloudflared) | 没有公网 IP / 不想开放任何入站端口,怎么把内网的 HTTP、SSH、RDP、任意 TCP 服务安全发布出去 | 一个 DNS 托管在 Cloudflare 的域名;服务器能出站访问 7844 | 本文主角 | | frp | 有一台带公网 IP 的中转服务器,怎么把内网端口映射出去 | 一台有公网 IP 的中转 VPS + 在该 VPS 上开放端口 | 边界表对比;纯 UDP 业务、游戏服务器仍应选 frp | | WireGuard | 怎么把多台设备组成一个虚拟内网(点对点、全互联) | 至少一端有公网 IP 或 UDP 端口可达 | 需求是"组网"而不是"发布单个服务"时选它 | | Nginx + Let's Encrypt | 在服务器本机做反向代理、负载均衡、签免费证书 | 服务器需要有公网可达的 80/443 | Tunnel 场景下证书由 Cloudflare 边缘代管,Nginx 只需监听 127.0.0.1 | | Cloudflare CDN | 怎么给已公开的站点做缓存、加速、WAF | 源站本身公开可访问 | Tunnel 是"回源通道",两者可叠加使用 | | 宝塔面板 | 怎么图形化建站、管数据库、装 PHP 环境 | —— | Tunnel 是它的"前置通道":先用隧道把面板/站点接出来,再谈建站 |

一句话选型:只发布网页和几个端口给指定的人访问、自己又不想管证书和服务器暴露面 → 用 Cloudflare Tunnel;要做游戏服这类纯 UDP 业务 → 用 frp;要让笔记本、手机、家里设备互相直连成一个内网 → 用 WireGuard。 三者不是替代关系,很多人的最终形态是"WireGuard 管组网 + Tunnel 管对外发布",frp 只留给 UDP 场景。

还有一条必须提前说清的诚实边界:Cloudflare Tunnel 官方"发布应用"支持的协议表里只有 HTTP、HTTPS、UNIX Socket、TCP、SSH、RDP、SMB 这些 TCP 系协议,没有裸 UDP。所以像 Minecraft 的 Bedrock 版、部分对战类游戏服务器、WireGuard 端点这类 UDP 业务,不要指望用隧道解决——那是 frp 的活。

二、它是怎么做到的:把"等别人连进来"改成"我主动连出去"

理解原理比记住命令重要,因为后面所有的排错(尤其是 1033 错误)都要靠这套心智模型。

传统反向代理的模型是"开门等客":服务器在公网 IP 上监听 80/443,防火墙必须放行入站,DNS 把域名解析到这台机器的公网 IP,用户直连进来。这条链路上任何一环缺失——没有公网 IP、防火墙禁入站、端口被封——服务就发布不出去。

Cloudflare Tunnel 把方向反过来,变成"我出门去找 Cloudflare":

1. 你在内网机器上运行客户端 cloudflared; 2. 它主动向外建立若干条加密长连接,连到 Cloudflare 全球网络的隧道入口(region1.v2.argotunnel.com 与 region2.v2.argotunnel.com),走 7844 端口,传输层可选 QUIC(UDP) 或 HTTP/2(TCP),官方客户端会自动回退到可用的那一种; 3. 因此你服务器的防火墙不需要开放任何入站端口,只需要允许出站 7844(这点后面第三节会给出预检命令); 4. Cloudflare 边缘收到某个域名的请求时,顺着已经建立好的隧道把请求推进来,交给 cloudflared; 5. cloudflared 再按你写的规则,把请求转给本机的 127.0.0.1:端口。

关键概念表:

| 概念 | 说明 | |---|---| | 只出站连接(outbound-only) | 客户端只发起出站连接,入站端口零开放。防火墙用"正安全模型"只需放行出站 7844 | | 隧道入口域名 | region1.v2.argotunnel.com / region2.v2.argotunnel.com(US 区域为 us-region1/us-region2,FedRAMP 为 fed-region1/fed-region2) | | 健康 = 四条连接 | 官方把 Healthy 定义为"通过四条连接向 Cloudflare 全球网络提供服务",也就是 4 个副本分别连上两个 region | | <UUID>.cfargotunnel.com | 建隧道时自动生成的专属子域;route dns 会为你的域名创建一条指向它的 CNAME,公开记录里不会出现你的真实 IP | | 两套管理方式 | 本地管理(locally-managed):CLI 创建,配置写在服务器上的 config.yml,登录时生成 cert.pem;远程管理(remotely-managed):在 Dashboard 创建,凭证与路由都在 Cloudflare 侧,服务器上不落配置文件 | | Quick Tunnel | cloudflared tunnel --url http://localhost:8080 一条命令就能拿到一个随机的 trycloudflare.com 子域,官方明确定位为测试/开发用途,不上生产 | | 副本与高可用 | 同一个隧道可以跑多个 cloudflared 副本,各自连上不同 region;副本越多,单台宕机对服务的影响越小 |

两台管理方式怎么选,可以直接照下表:

| 维度 | 本地管理(CLI + config.yml) | 远程管理(Dashboard) | |---|---|---| | 上手方式 | 命令行,适合脚本化、Ansible/CI 批量部署 | 图形界面,适合一次性手工搭建 | | 配置位置 | 服务器上的 .cloudflared/config.yml | Cloudflare 侧,客户端只跑 tunnel run | | 迁移服务器 | 需要把 config.yml + <UUID>.json 一起搬过去 | 新机器装完客户端跑一条安装命令即可 | | 适合场景 | 多站点规则复杂、要写进配置管理 | 少改动、要远程改路由、不想在机器上留凭证 | | 本文 | 第四节路线 A | 第四节路线 B |

三、服务器配置推荐与价格参考

这一节要先纠正一个直觉:Cloudflare Tunnel 不吃 CPU,也不吃内存。 官方系统要求页写得很直白——cloudflared 被设计成"轻量到可以有效地跑在树莓派、你的笔记本或数据中心的服务器上",并且明确说与老式 VPN 不同,隧道吞吐主要由系统软件里配置的可用端口数量决定,而不是服务器的内存和 CPU。所以机器怎么选,取决于你后面要跑什么业务,而不是隧道本身。

3.1 服务器配置推荐(按用途)

| 使用场景 | 推荐配置 | 为什么够用 | |---|---|---| | 个人:给 1~3 个内网服务开个外网入口(NAS、图床、博客) | 1核 1G + 20GB SSD | 隧道客户端常驻占用极小,瓶颈在你的业务应用而不是隧道 | | 小团队:多站点 + Zero Trust 身份认证 + 常驻后台 | 1核 2G ~ 2核 2G + 40GB SSD | 便宜档位里"宁可 1核2G 不要 2核1G",多出来的内存留给业务进程更实际 | | 发布带数据库的正式站点(WordPress / Nextcloud 等) | 2核 4G + 80GB SSD 起 | 隧道只是通道,站点本身的开销才是主项,参考对应站点的配置篇 | | 多人协作:多隧道、多副本、有并发峰值 | ≥2 台 2核4G,每台跑一个副本 | 单点宕机不影响服务;两台分别连不同 region,官方推荐的高可用形态 | | 官方大规模参考口径 | 每个网络位置 2 台专用主机,每台 ≥4核 4G,并为 cloudflared 预留 5 万个端口 | 官方称该配置通常足以承载约 8000 名 Cloudflare One Client 用户(每台 4000 名) |

> ⚠️ 两条实操提醒:① 如果机器上同时跑着 Nginx、宝塔面板或 Docker,不要让隧道客户端和业务抢同一个端口范围;空闲小机器建议按第三节第 10 步顺手把本机动态端口范围调大(官方给的区间是 11000 60999)。② 官方建议 cloudflared 尽量跑在专用主机上,实在要混部,也请把它注册成 systemd 服务(第四节第 6 步),别用 nohup 挂着。

3.2 服务商价格参考

隧道本身不收费,钱花在机器上。下面按实际会用到的两档配置整理公开官网参考区间:

| 服务商 | 1核2G 月付 | 2核4G 月付 | 数据中心 | 优点 | |---|---|---|---|---| | 阿里云国际版 ECS(通用型) | 约 $12~$20 | 约 $24~$36 | 新加坡/香港/硅谷 | 中文面板、支持支付宝、生态完整 | | AWS Lightsail | 约 $10~$12(2GB 档) | 约 $20~$24(4GB 档) | 全球 20+ 区域 | 固定月费、含流量额度、开箱即用 | | 腾讯云国际版 CVM(轻量/标准) | 约 $10~$16 | 约 $20~$30 | 香港/新加坡/东京 | 低延迟到国内、微信支付 | | Vultr | 约 $12~$18(2GB 档) | 约 $20~$24(4GB 档) | 全球 32 个 | 按小时计费、随时销毁重建 | | DigitalOcean | 约 $12~$18(2GB 档) | 约 $24(4GB 档) | 全球 14 个 | 文档完善、社区教程多 |

> 💡 选址原则和普通建站略有不同:Cloudflare 的免费边缘节点本身遍布全球,但从你的服务器到 Cloudflare 边缘这一段回程、以及国内访客到 Cloudflare 边缘这一段前段,质量并不对等。如果你的访客主要在国内,比较务实的做法是:把 cloudflared 部署在香港/日本/新加坡的海外云服务器上(离 Cloudflare 亚太边缘和国内出口都近),把 Tunnel 当作"运维入口 + 不暴露源站的发布通道";如果要做面向国内用户的高速主站,仍建议叠加国内合规节点或自建 CDN 回源方案。通过 5.chengzicloud.cloud 购买以上平台还可享额外折扣。

> 声明:本文价格数据采集于 2026 年 9 月,仅为公开官网参考区间。云服务器价格随区域、计费方式和活动浮动,请以各厂商官网实时价格为准。除特别标注外,金额单位均为美元(USD)。

3.3 同赛道方案成本对比:为什么不自己搭 frp 中转

很多人的第一反应是"我自己买台 VPS 搭 frp 不就完了"。下表把三条路的经济账摆在一起,你可以按自己的真实需求对号入座:

| 方案 | 固定成本 | 隐性成本 | 自定义域名 | 身份认证 | 协议支持 | |---|---|---|---|---|---| | Cloudflare Tunnel | $0(隧道本身免费;只需一个托管在 Cloudflare 的域名) | 域名年费;国内访客速度看边缘节点质量 | ✅ 免费用自己的域名 | ✅ Zero Trust Access 内置(免费档最多 50 用户) | HTTP/HTTPS/SSH/RDP/SMB/任意 TCP,不含裸 UDP | | ngrok | 免费档 $0(一次性 $5 额度);Hobbyist 月度 $10 使用额度;Pay-as-you-go 月度 $20 使用额度 | 免费档仅 3 个在线端点、1GB 流量、2 万请求,且公网端点带插页提示;自定义域名要 Pay-as-you-go 及以上 | 免费/Hobbyist 不支持 | 付费档有 SSO/RBAC 等能力 | HTTP/TCP/TLS 等 | | 自建 frp + 中转 VPS | 一台小 VPS 约 $5~$12/月(1核1G/1核2G) | 自己维护证书、防火墙、中转机被扫描/被打的风险、UDP 端口开放带来的暴露面 | ✅ 完全自主 | 需自己加(或用 basic auth 等弱方案) | TCP + UDP 全能,游戏服首选 | | 国内商业内网穿透(如花生壳类) | 免费档通常限制带宽与映射数 | 免费档域名归服务商、需实名、带宽受限;付费档按月订阅 | 多为付费能力 | 视档位 | 以 TCP/HTTP 为主 |

一句话结论:只想"把几个服务安全地发布出去",Cloudflare Tunnel 的边际成本几乎为零;要跑纯 UDP 或对中转链路有完全控制权,才去自建 frp。 两条路线上真正贵的东西从来不是软件,而是"暴露在公网上的那台机器的被攻击面"——而这恰恰是 Tunnel 用只出站连接帮你省掉的部分。

四、部署实操:从空机器到"域名能打开内网服务"

下面的步骤以 Ubuntu 22.04 / Debian 12 为主线,RHEL / CentOS 7 的差异会在对应位置单独标出。全程假设你要发布的服务是内网 127.0.0.1:8080 上的一个网站(实际换成 Nginx 的 80、Jellyfin 的 8096、Nextcloud 的 80 都同理)。

第 1 步:确认三个前置条件

| 前置条件 | 怎么确认 | |---|---| | 一个域名,且 DNS 已托管到 Cloudflare | 完整接入:把域名的 NS 改成 Cloudflare 分配的两条 NS;部分接入(CNAME 接入):域名 NS 仍在原服务商,但用 CNAME 把子域指向 Cloudflare。没有域名的场合,可以先用 Quick Tunnel 临时演示(见第六节 Q8) | | 服务器能出站访问 7844 | 见第 3 步的预检命令 | | 服务在本机监听 | ss -lntp \| grep 8080,确认服务确实在跑;注意:反向代理场景下,Nginx 监听 127.0.0.1:80 就够,不需要监听 0.0.0.0 |

> ⚠️ 别为了 Tunnel 去开端口。 这是最常见的误解:既然隧道是只出站的,你的安全组/防火墙/宝塔面板里一个入站端口都不用放行。第 7 步之前的服务一律只监听 127.0.0.1。

第 2 步:安装 cloudflared

Debian / Ubuntu(APT 仓库,推荐) —— 加官方签名密钥与软件源:

`bash sudo mkdir -p --mode=0755 /usr/share/keyrings curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" | sudo tee /etc/apt/sources.list.d/cloudflared.list sudo apt-get update && sudo apt-get install -y cloudflared `

RHEL / CentOS 7(RPM 仓库):

`bash curl -fsSL https://pkg.cloudflare.com/cloudflared.repo | sudo tee /etc/yum.repos.d/cloudflared.repo sudo yum update -y && sudo yum install -y cloudflared `

Arch Linux:pacman -Syu cloudflared

macOS:brew install cloudflared

通用兜底路线:直接下二进制。 适用于任何发行版,也是"官方仓库被墙/公司源不可用"时的解法。官方提供 amd64 / 386 / arm / arm64 四种架构的裸二进制,以及 .deb / .rpm 包:

`bash curl -fsSL -o /usr/local/bin/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 chmod +x /usr/local/bin/cloudflared cloudflared --version `

版本号不要写死。想知道当前最新版本,用 GitHub API 取,而不是抄教程里的数字:

`bash // 取 cloudflared 最新发布版本号 curl -s https://api.github.com/repos/cloudflare/cloudflared/releases/latest | grep -oP '"tag_name":\s*"\K[^"]+' `

第 3 步:连通性预检(装之前先做,省掉 90% 的排错)

官方专门有一页"连通性预检"。在装客户端之前先跑,能把"环境问题"和"配置问题"提前切开——隧道连不上,九成不是 cloudflared 的错,而是 DNS 或防火墙。

第一步,确认能解析到隧道入口的地址:

`bash dig A region1.v2.argotunnel.com dig A region2.v2.argotunnel.com `

正常应该返回 198.41.192.x(region1)与 198.41.200.x(region2)这一段的地址。如果返回 SERVFAIL / NXDOMAIN / 空,换 Cloudflare 公共解析器再试一次:

`bash dig A region1.v2.argotunnel.com @1.1.1.1 `

若 1.1.1.1 能解析而本机解析器不能,说明你本地 DNS 被改过或被阻断——把机器的 DNS 指向 1.1.1.1,或在出口上放通相关查询。

第二步,确认 7844 端口的出站连通性(TCP 与 UDP 都要测)——把下面命令里的 IP 换成你上一步 dig 出来的任意一个:

`bash nc -uvz -w 3 198.41.192.167 7844 nc -vz -w 3 198.41.192.167 7844 `

| 测试结果 | 含义 | 怎么办 | |---|---|---| | UDP 与 TCP 都成功 | 环境完全就绪,客户端可用任一协议 | 直接进第 4 步 | | 只有 UDP 成功 | 出站 TCP 7844 被拦或做了内容检查 | 客户端只能走 QUIC;不要在配置里强制 http2,否则隧道连不上 | | 只有 TCP 成功 | 出站 UDP 7844 被拦 | 客户端只能走 HTTP/2;不要强制 quic | | 两个都失败 | 出站被策略阻断 | 放通 7844(TCP+UDP);仍不行就找 ISP 或云厂商查出口策略 |

第 4 步:路线 A —— 用 CLI 建"本地管理"隧道

4.1 登录并生成账号证书

`bash cloudflared tunnel login `

它会打印一个链接并要求你在浏览器里授权。在只有 SSH 的服务器上,把终端里那个链接复制到本地浏览器打开、选择要授权的域名即可;授权完成后凭据会落到 ~/.cloudflared/cert.pem。这份 cert.pem 里包含该域名的源站证书公钥/私钥和一个隧道专用 token,它让 cloudflared 有权限为你的域名自动创建 DNS 记录——所以它的权限等于"该域名的 DNS 写权限",务必 chmod 600 并纳入备份。

> ⚠️ 一个真实的坑:cert.pem 里的 token 绑定的是执行 login 那个用户的 API key。如果这个用户后来被移出账号、或权限发生变化,Cloudflare 会轮换该用户的 API key,而本地这份旧 cert.pem 不会自动更新,表现为突然认证失败。官方建议的做法是:为一个专门的"服务用户"授权,或者出问题时重新跑一次 cloudflared tunnel login。

4.2 创建隧道

`bash cloudflared tunnel create my-tunnel `

这条命令会做三件事:把名字和 UUID 绑定、在 ~/.cloudflared/ 生成 <UUID>.json 凭证文件、并创建一个 <UUID>.cfargotunnel.com 子域。记下输出的 UUID 和凭证文件路径,下一步要用。确认隧道建好了:

`bash cloudflared tunnel list `

4.3 写配置文件 config.yml

在 ~/.cloudflared/ 下创建 config.yml。下面是发布单个应用的写法:

`yaml url: http://localhost:8080 tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef credentials-file: /root/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json `

如果这条隧道还要连接私有网络(把整个内网段暴露给装了 Cloudflare One Client 的用户),写法是加 warp-routing:

`yaml tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef credentials-file: /root/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json warp-routing: enabled: true `

多站点场景用 ingress 规则列表,从上到下逐条匹配,最后一条必须是兜底规则:

`yaml tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef credentials-file: /root/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json

ingress: - hostname: blog.example.com service: http://127.0.0.1:80 - hostname: nas.example.com service: http://127.0.0.1:5000 - hostname: panel.example.com service: https://127.0.0.1:8443 - service: http_status:404 `

关键字段含义如下(因为 YAML 里写 # 注释会被本站的渲染器当成标题,所以注释统一放在这张表里):

| 字段 | 作用 | 必须注意 | |---|---|---| | url | 单应用写法:直接把所有流量转给这个地址 | 与 ingress 二选一,不要同时写 | | tunnel | 隧道 UUID 或名称 | 就是 tunnel create 输出的那串 UUID | | credentials-file | 凭证 JSON 的绝对路径 | 在非 root 用户下跑时要改路径;这里报错是新手第一大坑 | | ingress | 规则列表,按顺序匹配 hostname / path | 最后一条必须是无 hostname 的兜底规则,否则 cloudflared 拒绝启动 | | hostname | 匹配的域名,支持 .example.com 通配 | 不支持 test..example.com 这种中间通配 | | path | 用正则匹配请求路径,如 \.(jpg\|png\|css\|js)$ | 用的是 Go 正则语法 | | service | 转发目标,支持 http:// https:// unix: tcp:// ssh:// rdp:// smb:// http_status:404 | IPv6 字面量要用方括号包起来,如 http://[2001:db8::1]:8000 | | warp-routing.enabled | 打开私有网络路由能力 | 与"私有网络"用法配套,见第 9 步 |

> 🔴 ingress 只匹配路径,不会剥离路径。 官方明确说明:如果规则匹配 path: /api,那么访问 https://example.com/api/users 时,转发给服务的是 完整的 http://localhost:8000/api/users。要改写路径,要么在 Cloudflare 边缘用 URL Rewrite Rules,要么在后面放一层 Nginx/Traefik 来剥前缀——别指望 ingress 帮你做 path rewrite,这是自建用户最常踩的认知错位。

4.4 建立 DNS 路由

`bash cloudflared tunnel route dns my-tunnel blog.example.com `

这一步会在你的 Cloudflare DNS 里创建一条指向 <UUID>.cfargotunnel.com 的 CNAME。好处是:公开的 DNS 记录里永远不出现你的源站真实 IP。

4.5 启动并检查

`bash cloudflared tunnel run my-tunnel cloudflared tunnel info my-tunnel `

如果你的配置文件不在默认目录、或改了名字,用 --config 指定:

`bash cloudflared tunnel --config /path/your-config-file.yml run my-tunnel `

4.6 先在浏览器里验证:访问 https://blog.example.com,能打开内网服务即成功。注意地址栏是 HTTPS,而你的内网服务其实是明文 HTTP——这层 TLS 是 Cloudflare 边缘替你做的,你不需要在源站签任何证书,这是本方案相比自建反代最大的一处省事。

第 5 步:路线 B —— 用 Dashboard 建"远程管理"隧道

不想在服务器上留配置文件和凭证的人,走这条路:

1. 登录 Cloudflare Dashboard,进入 Networking → Tunnels,点 Create a tunnel,给隧道起个能说明用途的名字(例如 home-lab-01),Create; 2. 选择你的操作系统,复制页面给出的安装命令,到内网机器上执行;等页面显示隧道已连接,点 Continue; 3. 接下来按用途二选一: - 发布一个应用:进入该隧道的 Routes 标签 → Add route → Published application,填子域名 + 选择域名 + Service URL(如 http://localhost:8000),保存。保存后全网就能访问了,要限制特定人访问,就去加 Access 应用(第 8 步)。 - 连接一个私有网络:进入 Networking → Routes → Create route → 选 Tunnel CIDR,选刚才的隧道,Network 填内网地址或网段(如 10.0.0.0/24),保存。 4. 回到 Networking → Tunnels 确认状态为 Healthy。

> ⚠️ 多级子域要注意:官方提示,如果你用的是多于一级的子域(例如 a.b.example.com),需要为该主机名单独订购 Advanced Certificate,否则浏览器会报"此网站无法提供安全连接"。

第 6 步:把它注册成系统服务(别用 nohup 挂着)

临时 tunnel run 一关终端就断。生产环境必须注册为服务:

`bash sudo cloudflared service install sudo systemctl start cloudflared sudo systemctl status cloudflared sudo systemctl enable cloudflared `

如果配置文件不在默认目录,安装服务时要显式带上:

`bash sudo cloudflared --config /home/<你的用户>/.cloudflared/config.yml service install `

改完配置后重启生效:

`bash sudo systemctl restart cloudflared `

> 🔴 一台机器上只能有一个以服务方式运行的 cloudflared 实例。 这是官方明说的一条限制,也是"装第二个隧道时报错"的直接原因。要发布更多服务,正确做法是给现有隧道加路由规则,而不是再装一个服务;确实要卸载旧的,用 sudo cloudflared service uninstall。

> 🔴 注册服务前,先确认 config.yml 已经写好、credentials-file 路径真实存在。 顺序颠倒的话,服务会注册成功但一启动就退出,systemctl status 里只看到反复重启——这类"服务在跑但访问报 1033"的问题,到第六节 Q1 处理。

第 7 步:把真实业务接上去(Nginx / 宝塔 / 容器)

隧道通了之后,把它接到你真正想发布的服务上。三种最常见的形态:

形态一:Nginx 在本机做反代,隧道转给 Nginx。 这是最推荐的架构,因为多站点、缓存、重写规则都能在 Nginx 里做,而 Nginx 的 listen 改成只监听本机、不暴露公网:

`nginx server { listen 127.0.0.1:80; server_name blog.example.com; root /var/www/blog; index index.php index.html; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } `

对应 config.yml 里的 service 就写 http://127.0.0.1:80。注意 listen 127.0.0.1:80 而不是 listen 80——后者会监听 0.0.0.0,安全组一放行就等于把源站直接暴露了,隧道反而成了多余的一层。

形态二:宝塔面板。 宝塔默认面板端口是 8888,且强制 HTTPS。不要把 8888 开进安全组,而是把隧道指向它本机端口:

`yaml ingress: - hostname: bt.example.com service: https://127.0.0.1:8888 - service: http_status:404 `

因为宝塔用的是自签证书,cloudflared 默认不信任,会报 origin 证书不受信。两种处理方式:

| 处理方式 | 配置位置 | 代价 | |---|---|---| | 把宝塔的 CA 加进系统信任库后重启 cloudflared | 系统级 | 最干净,推荐 | | originRequest.caPool 指向含该 CA 的本地 PEM 文件 | config.yml 的规则内 | 需要维护 PEM 路径 | | originRequest.noTLSVerify: true | config.yml 的规则内 | 临时手段,官方定位是"最后的兜底",用完要关掉 |

> ⚠️ 命令行的 --origin-ca-pool / --no-tls-verify 只在用 --url 定义单一源站时生效;一旦用了 ingress 规则列表,就必须写在规则下的 originRequest 里。这是"命令行参数明明加了却不生效"的常见原因。

形态三:容器里的应用(Portainer / Jellyfin / Nextcloud)。 容器默认把端口映射到宿主机,把映射改成只绑本机:

`bash docker run -d --name jellyfin -p 127.0.0.1:8096:8096 jellyfin/jellyfin:latest `

然后隧道指向 http://127.0.0.1:8096。只写 -p 8096:8096 会让 Docker 监听 0.0.0.0,而 Docker 自己写的 iptables 规则会绕过 ufw/firewalld——那等于隧道白搭。这条红线在本站 MinIO、Vaultwarden、Umami 等篇章里反复出现过,这里再强调一次。

形态四:一条隧道挂多站点。 用第 4 步的 ingress 列表即可,每条 route dns 建一条 CNAME。适合"一台机器上有站点、面板、媒体库、图床"的家用/小团队形态。

第 8 步:给后台加一层身份认证(Zero Trust Access)

这是 Tunnel 比"随便找个内网穿透"高一个量级的地方:它可以在应用前面加一层企业级身份验证,而你不用改应用一行代码。宝塔、Portainer、Nextcloud 后台这类"绝不能被陌生人碰到登录页"的服务,都建议加上。

在 Dashboard 里:Zero Trust → Access controls → Applications → Create new application → Self-hosted and private → Add public hostname,然后:

| 配置项 | 建议值 | 说明 | |---|---|---| | Domain | 选你刚发布的那个主机名 | 必须是本账号下的活跃 zone;也可以用通配符保护同一根路径下的一组应用 | | Access policies | 建一条 Allow,条件用 Emails / Email domain / IP / 单点登录组 | 所有 Access 应用默认是拒绝(deny by default):用户必须先命中一条 Allow 策略才能访问 | | Identity providers | 至少启用一种(邮箱一次性验证码 / Google / GitHub / SAML/OIDC 等) | 只放行单一 IdP 时可打开 Apply instant authentication,跳过 Cloudflare 登录页直达 SSO | | Session Duration | 按敏感度设,管理后台建议短一些 | Cloudflare 会检查每一次 HTTP 请求的应用令牌;过期后重新认证 | | 独立 MFA | 管理类应用建议开启 | 在策略里配 MFA 要求 | | Service Token | 给机器/CI 用的场合 | 不适用于交互式登录,用于程序化访问;可勾选"没有正确 service token 时返回 401" | | 自定义拦截页 | 可留默认 | 默认提示为"该账号无权访问",也可改成跳转 URL 或自定义页面模板 |

配好之后的效果是:用户先过 Cloudflare 的身份验证,才轮到你的应用登录页。即使哪天应用的漏洞导致登录被绕过,攻击者也进不来——因为他连应用页面都拿不到。

> 💡 免费额度:Cloudflare Zero Trust 的 Free 档为"50 名用户以内",$0 永久;超过 50 人转 Pay-as-you-go,官方公开价 $7/用户/月。家用和绝大多数小团队场景完全落在免费档里。

第 9 步:把 SSH、数据库、RDP 也接进来

Tunnel 不只发网页。只要是非 HTTP 服务,官方要求客户端侧也装 cloudflared,这是这套方案与"网页发布"最大的使用差异:

| 服务类型 | service 写法 | 客户端怎么连 | |---|---|---| | SSH | ssh://127.0.0.1:22 | 客户端跑 cloudflared access ssh --hostname ssh.example.com | | 任意 TCP(MySQL/Redis 等) | tcp://127.0.0.1:3306 | 客户端跑 cloudflared access tcp --hostname db.example.com --url 127.0.0.1:3306 | | RDP | rdp://127.0.0.1:3389 | Windows 端可用浏览器版 RDP,或用 client-side cloudflared | | SMB | smb://127.0.0.1:445 | 需配合 cloudflared access | | 跳板机 | bastion | 让 cloudflared 充当跳板,可访问任意本地地址 |

SSH 的最省事形态(客户端只输一条命令就进服务器,不再需要把 22 端口开到公网):

`bash // 控制端(你的笔记本)执行,把 ssh.example.com 换成你的隧道域名 cloudflared access ssh --hostname ssh.example.com `

如果要让"整个内网段"都可达,就要用私有网络路由:服务端 config.yml 打开 warp-routing(第 4 步已给),然后:

`bash cloudflared tunnel route ip add 10.0.0.0/24 my-tunnel cloudflared tunnel route ip show `

之后端用户必须安装并登录 Cloudflare One Client(原 WARP 客户端),才能访问这些私有 IP。这就是"零信任内网"的形态:没有 VPN 网关、没有开放端口,靠身份而不是靠网络位置来控制访问。

> ⚠️ 两条使用提醒:① 官方明确说,长时间存活的连接(例如挂着不动的 SSH 会话、数据库长连接)更应该用 Client-to-Tunnel / Cloudflare One Client 形态,而不是 cloudflared access 的 WebSocket 桥接;② 非 HTTP 服务没有浏览器里的"网页登录页",访问控制依赖 Access 应用策略 + 客户端身份,所以策略一定要配 Z。

第 10 步:性能与可用性调优

隧道跑起来之后,下面四件事决定它"稳不稳":

10.1 把本机可用端口范围调大。 官方口径是吞吐由端口数决定,给出的一致推荐是把 5 万个端口留给 cloudflared:

`bash echo 'net.ipv4.ip_local_port_range = 11000 60999' | sudo tee -a /etc/sysctl.d/99-cloudflared.conf sudo sysctl -p /etc/sysctl.d/99-cloudflared.conf `

10.2 跑多副本。 官方把 Healthy 定义为"通过四条连接提供服务",并建议每个网络位置至少两台专用主机。小团队至少做到:同一台机器上多副本,或者两台机器各跑一个副本连不同 region。

10.3 不要乱锁协议。 第 3 步的预检已经告诉你能走 QUIC 还是 HTTP/2。官方明确警告:当一个协议被网络阻断而你又在配置里强制它时,隧道会直接连不上。除非有明确理由,让客户端自动回退。

10.4 监控隧道状态与通知。 Dashboard 的 Networking → Tunnels 会给出状态;官方还提供隧道的日志、指标与通知三类观测能力。至少要打开"隧道掉线通知",否则你往往是"用户打不开页面了"才知道隧道断了。

10.5 顺手做的两件小事:把 cloudflared 的日志接入本站《Prometheus + Grafana 服务器监控》篇的采集体系;把 config.yml 与 <UUID>.json 纳入本站《服务器备份与容灾》篇的备份清单——这两个文件丢了,隧道就得重建。

五、安全加固与日常运维

Tunnel 这套架构最大的安全红利可以总结成一句话:用"正安全模型"替代"负安全模型"。传统做法是"先全开,再一条条封禁",而官方对 Tunnel 的定位是阻断所有入站流量,只允许 cloudflared 的出站流量——只有你在隧道配置里明确写出来的服务才会对着外部世界可见。

围绕这个模型,下面六条是必做的:

| 加固项 | 具体做法 | 不做会怎样 | |---|---|---| | 安全组/防火墙只留出站 | 云安全组不放行任何入站端口;服务器防火墙阻断入站、放行出站 7844(TCP+UDP) | 端口暴露在公网,被扫描器爆破只是时间问题 | | 服务只监听 127.0.0.1 | Nginx listen 127.0.0.1:80;Docker -p 127.0.0.1:PORT:PORT | 隧道变成"多余的装饰",源站仍可直接命中 | | 非公开应用一律加 Access | 面板、Portainer、数据库管理界面、文件库,全部套一层 Zero Trust 应用策略 | 只剩应用自身的登录页,一个弱口令就全线失守 | | 凭证最小权限 + 600 权限 | cert.pem、<UUID>.json 一律 chmod 600;用专门的"服务用户"执行 tunnel login | cert.pem 等于域名的 DNS 写权限;用户权限变更后还会突然认证失败 | | 隐藏源站 | 用 route dns 生成 CNAME 指向 <UUID>.cfargotunnel.com,不在任何地方公开源站 IP | 攻击者可以绕过 Cloudflare 直连源站,抗 DDoS 与 WAF 全部失效 | | 状态与日志纳入监控 | 打开隧道掉线通知,日志接入现有监控告警体系 | 隧道断了没人知道,等到用户反馈已经影响业务 |

日常运维的三件事:

1. 升级客户端:用官方 APT/RPM 仓库安装的,直接 sudo apt-get upgrade cloudflared(或 sudo yum update cloudflared)即可;官方另有 "Update cloudflared" 专页介绍各平台升级方式。升级后记得 systemctl restart cloudflared。 2. 改配置的标准动作:改 config.yml → cloudflared tunnel ingress validate(校验规则)→ cloudflared tunnel ingress rule https://你的域名/路径(预演某条 URL 会命中哪条规则,排错神器)→ sudo systemctl restart cloudflared。 3. 备份:config.yml + <UUID>.json + cert.pem 三件套。只备份业务数据不备份这三样,重建隧道时要重新走一遍授权和签发流程。

六、常见问题 FAQ

Q1:访问域名报 Error 1033(Cloudflare Tunnel error)怎么办?

1033 的含义非常明确:Cloudflare 网络找不到一个健康的 cloudflared 实例来接这个流量——也就是"隧道没连上",问题在源站侧,不在浏览器侧。按顺序查:

1. 到 Networking → Tunnels 或跑 cloudflared tunnel list 看状态:

| 状态 | 含义 | 处理 | |---|---|---| | Healthy | 四条连接正常在跑 | 不用动 | | Inactive | 隧道建了,但客户端从未连上过 | 到服务器上跑安装/启动命令,把隧道真正连起来 | | Down | 之前连上过,现在进程停了 | 检查 systemctl status cloudflared、机器是否关机、网络是否变化 | | Degraded | 在跑,但至少一条连接失败了 | 查日志 + 检查本地防火墙是否在拦到 Cloudflare 的 7844 |

2. 最常见的三个根因:服务没注册成 systemd 服务(终端一关就断)、服务器出站 7844 被拦、config.yml 里 credentials-file 路径不对(下一问)。

Q2:页面报 502 Bad Gateway / Unable to reach the origin service 是什么问题?

和 1033 正好相反:隧道本身是通的,但 cloudflared 连不上你在规则里写的那个本地服务。所以它是"应用问题"而不是"隧道问题"。逐项核对:service 里的地址端口是否写对(http:// 还是 https://)→ 本机 ss -lntp | grep 端口 确认服务在听 → 服务是否只监听 127.0.0.1 而你的规则写的是容器名或别的 IP → 服务是否刚崩溃。

Q3:启动报 Tunnel credentials file '...json' doesn't exist or is not a file?

config.yml 里的 credentials-file 路径不对。最常见的两种情形:一是换了用户(/root/.cloudflared/... 在普通用户下不存在,要改成对应的家目录)。官方给的排查方式就是这个:把 /root/ 换成你的家目录,或用 cloudflared tunnel list 确认当前凭据到底落在哪。

Q4:源站本身就是 HTTPS(或用了自签证书),隧道起来后报证书不受信?

说明源站的证书 cloudflared 不信任,典型触发条件是服务器与 Cloudflare 之间还夹着 SSL/TLS 检查设备。三种处理方式,按推荐度排序:把该 CA 加进系统信任库后重启 cloudflared → 在规则的 originRequest.caPool 里指向含该 CA 的本地 PEM → 临时把 originRequest.noTLSVerify 设为 true。最后一种只是兜底,证书链修好后必须关掉。

Q5:我能在一台机器上装第二个隧道吗?

不能以"服务"的方式装第二个。 官方明确:一台机器上只允许一个 cloudflared 实例作为服务运行。要发布更多服务,就往现有隧道的 ingress 里加规则、并各自 route dns;确实要换掉旧的,sudo cloudflared service uninstall 卸载后再装。

Q6:Cloudflare Tunnel 到底收不收费?我需要买 Zero Trust 套餐吗?

隧道连接器本身不额外收费,你只需要一个托管在 Cloudflare 的域名(域名年费照常)。要额外能力时才有付费项:Zero Trust 免费档覆盖 50 名用户、$0 永久,家用与小团队(给团队加个身份认证、给后台加个 SSO)都在免费额度内;超过 50 人转 Pay-as-you-go,公开价 $7/用户/月。换句话说:拿它做内网穿透,成本上限就是一台小机器的钱。

Q7:国内访问快不快?走这条链路还需要备案吗?

两个问题要分开答。速度:这条链路是"访客 → Cloudflare 边缘 → 隧道 → 你的服务器",国内访客到 Cloudflare 免费边缘的体验波动很大,不适合当作面向国内用户的高速主站 CDN 方案;务实定位是"运维入口 + 不暴露源站的发布通道",把 cloudflared 放在港/日/新机房能显著改善回程。备案:隧道不改变"服务在境内还是境外"这件事——服务部署在境内且要公开提供网站服务,依然按属地要求走备案;把服务放在境外服务器上,则不涉及境内备案流程。别指望用隧道"绕过"合规要求,它解决的是网络可达性,不是合规性。

Q8:Quick Tunnel(cloudflared tunnel --url)能当正式方案用吗?

不能。 官方定位写得很清楚:Quick Tunnels 只用于测试和开发,正式使用请创建隧道。另外两个限制要知道:① 它每次生成随机的 trycloudflare.com 子域,域名不固定;② 如果 .cloudflared 目录下存在 config.yml,Quick Tunnel 会不可用——需要临时改名才能用。它的正确用途是"给你笔记本上的 demo 临时开个外链给同事看"。

Q9:CentOS 7 能装吗?会不会撞上 glibc 版本太老的坑?

能,而且没有 glibc 问题——cloudflared 是静态链接的 Go 二进制,官方同时提供 .deb / .rpm 包与裸二进制,不依赖系统 glibc 的新版本。所以 CentOS 7 的 glibc 2.17 完全不是障碍(这与本站 code-server / Ollama / Meilisearch 三篇的 glibc 坑正好相反,属于同一类"官方原生分发形态决定一切"的判断)。CentOS 7 上的推荐装法是走官方 RPM 仓库:curl -fsSL https://pkg.cloudflare.com/cloudflared.repo | sudo tee /etc/yum.repos.d/cloudflared.repo 然后 sudo yum install -y cloudflared。

Q10:我开游戏服务器 / 需要纯 UDP,能用 Tunnel 吗?

不要用。 官方"发布应用"支持的协议表里是 HTTP、HTTPS、UNIX Socket、TCP、SSH、RDP、SMB 这一组 TCP 系协议,没有裸 UDP。Minecraft Bedrock、部分对战类游戏服、WireGuard 端点这类 UDP 业务,请走本站《frp 内网穿透完整教程》或直接自建 WireGuard——这也是我们反复强调"先看边界表"的原因:选错工具的代价是整条链路白做。

七、总结

用 Cloudflare Tunnel 发布内网服务,整条链路其实就是十步:确认域名托管在 Cloudflare → 装 cloudflared → 先用 dig + nc 做连通性预检 → CLI 或 Dashboard 建隧道 → route dns 建 CNAME → 写 config.yml(多站点用 ingress,末条必须兜底)→ 注册成 systemd 服务 → 接真实业务(Nginx 只监听 127.0.0.1)→ 给非公开应用套一层 Zero Trust Access → 调大端口范围、跑多副本、开掉线通知。

真正决定这套隧道好不好用的,不是命令,而是三个判断:

第一,搞清它回答的是哪个问题。 它回答的是"我连一个能对外开放的门都没有,怎么把服务安全地发布出去",靠的是把连接方向反过来,所以入站端口一个都不用开。它不是 CDN 加速方案,也不是 UDP 业务方案——这两件事各有各的工具,硬套只会又慢又挫败。

第二,把"暴露面"当成第一设计目标。 隧道最大的价值是让你不必把 3306、6379、3389、8888 挂到公网。既然不用开,就一个都别开;既然 Access 能免费加一层身份验证,面板类应用就一个都别裸奔。

第三,接受"这两件事它做不到"。 一是纯 UDP 不行——游戏服请找 frp;二是国内访问速度不由你控制——它取决于访客到 Cloudflare 边缘那一段,所以务实的用法是"运维通道 + 不暴露源站的发布方式",同时把 cloudflared 部署在离你更近的亚太机房。一个工具被讲清边界,比被吹成万能更有价值。

最后回到它在本站服务体系里的位置:WireGuard 管"设备之间怎么互相看得见",frp 管"有公网 IP 的中转怎么映射任意 TCP/UDP",Cloudflare Tunnel 管"没有公网 IP 时怎么把服务安全发布到域名上",Nginx + Let's Encrypt 管"服务本机怎么反代与签证书"。四者拼起来,才是一套完整的内网服务对外可达方案。

延伸阅读: - frp 内网穿透完整搭建教程(含 UDP 场景与 frps 服务端) - WireGuard VPN 自建完整教程 - Nginx 反向代理 + Let's Encrypt 免费 SSL 证书配置完整教程 - Cloudflare CDN 免费接入与全站加速完整教程 - 网站安全加固与入侵防护完整指南 - 宝塔面板安装与建站一站式教程

> 本文由 5.chengzicloud.cloud 提供,点击访问首页了解更多海外云服务器部署方案和专属优惠。