跳转至

Cloudflare Tunnel 自建服务暴露实战:不开端口把内网应用安全推向公网

很多运维和自建玩家都卡在同一个问题上:家里的 NAS、内网的 Web 面板、或者一台跑着小工具的服务,想从外面访问,但运营商给的是 CGNAT、没有公网 IP,或者干脆不敢在路由器上开 443 端口。传统做法是端口映射加反向代理 VPS,要么有安全风险,要么有成本。Cloudflare Tunnel(前身 Argo Tunnel)给出第三条路:不开任何入站端口,把服务经一条加密隧道推到 Cloudflare 边缘,再转给访客。本文只讲运维落地,不讲营销话术。

1. 它到底解决了什么:连接方向反过来了

端口映射的模型是“公网主动连进来”:你告诉路由器“443 端口的包转给内网那台机器”,于是这台机器必须有一个监听端口永远对全网开放。Tunnel 反过来:你机器上的 cloudflared 守护进程主动向外连到 Cloudflare,维持一条只出不进的长连接。访客访问你的域名时,流量先到 Cloudflare,再沿这条已有的连接回到你机器。你的内网从不需要接受任何入站连接,因此没有端口可供扫描器发现,家庭公网 IP 也永不暴露。这是安全模型的根本改变,而不只是“少配一条映射”。

2. 安装与认证

cloudflared 是 Cloudflare 出的单二进制,Linux/macOS/Windows 都支持。Debian/Ubuntu 走官方仓库:

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 update && sudo apt install cloudflared

先登录并绑定你的域名:

cloudflared tunnel login
这会打开浏览器让你授权域名。授权后创建一个具名隧道,会生成凭证文件并记录隧道 UUID:
cloudflared tunnel create my-homelab

3. 用 config.yml 编排 ingress

Tunnel 本身不知道要服务什么,规则写在 ~/.cloudflared/config.yml(作为服务运行时实际读 /etc/cloudflared/config.yml):

tunnel: <你的隧道UUID>
credentials-file: /home/youruser/.cloudflared/<你的隧道UUID>.json

ingress:
  - hostname: app.yourdomain.com
    service: http://localhost:8080
  - hostname: ssh.yourdomain.com
    service: ssh://localhost:22
  - service: http_status:404
最后一行 http_status:404 是 catch-all,没有它 cloudflared 会拒绝启动。每个 hostname 对应一个内网服务地址和端口,支持 HTTP/HTTPS 与 SSH/VNC 等协议。对 SSH 这类非 HTTP 服务,Cloudflare 会用浏览器里的 web terminal(基于 WASM)渲染,无需本地 SSH 客户端也能用。

4. DNS 自动路由与常驻

把主机名指向隧道(自动建 CNAME),不用手动填 IP:

cloudflared tunnel route dns my-homelab app.yourdomain.com
每个 ingress 里的 hostname 都要对应跑一次。前端验证没问题后,注册成系统服务常驻:
sudo cloudflared service install
sudo systemctl enable --now cloudflared
以服务方式运行,机器重启后自动拉起,不用开个终端挂着。

5. 给 SSH 上锁:Cloudflare Access

裸把 SSH 通过 Tunnel 暴露出去很危险,必须叠加身份校验。在 Cloudflare Zero Trust 控制台里把 ssh.yourdomain.com 注册为自托管应用,建一条策略:只允许你自己的邮箱,并要求 OTP 或 SSO。这样任何访客在流量触及你服务器之前,必须先过 Cloudflare 的身份关。配合短会话有效期、限定来源地区,能把“公网 SSH 暴破”这个老问题彻底关掉。记住一句话:Tunnel 只是通道,Access 才是锁。

6. 常见故障与排查

  • 502 错误:本地服务没起来,或 config.yml 里的端口写错。先 curl http://localhost:8080 确认本机可达。
  • WebSocket 失败:后端用了自签名证书时,加 originRequest: { noTLSVerify: true }。
  • DNS 不解析:CNAME 传播可能要等几分钟,cloudflared tunnel route dns 后耐心等。
  • 配置不生效:以服务方式运行时读的是 /etc/cloudflared/config.yml 而不是家目录,改完要 cp 过去再重启服务。

7. 免费版的清醒认知

免费版覆盖隧道连接本身,但边界要清楚:Cloudflare TOS 禁止用免费隧道做流媒体分发(Jellyfin/Plex 串流会违规);Argo Smart Routing 是单独付费项,免费回程延迟更高;UDP 支持有限,游戏服务器这类强 UDP 场景不合适。而且 Tunnel 引入了新依赖——你机器在线、cloudflared 运行、Cloudflare 网络正常,三者少一个服务就不可达。对纯静态站点,其实没必要上 Tunnel,直接丢 CDN 更省心;Tunnel 真正划算的场景是“必须跑在你自己硬件上的有状态服务”。

8. 上线后的巡检与防退化纪律

Tunnel 是“会悄悄退化”的典型:cloudflared 进程被 OOM 杀掉、凭证文件权限错了、CNAME 被误删,服务就无声消失。建立纪律:

  • 每日:外部拨测你的主机名是否返回 200,监控 cloudflared 进程存活与到 Cloudflare 的延迟。
  • 每周:确认凭证文件权限和到期( Tunnel 凭证长期有效,但绑定的域名 NS 若迁走会失效)。
  • 多实例:同内网至少跑两个 cloudflared 实例,Cloudflare 按就近和健康度 failover,避免单机单点。
  • 每次变更前:先在 staging 用 cloudflared tunnel run 前台跑通,再切服务;改完 ingress 立刻 dig 主机名确认 CNAME 生效。
  • 红线:禁止裸暴露 SSH 不加 Cloudflared Access;禁止为图省事把整个内网段通过 Tunnel 无差别暴露。

FAQ

Cloudflare Tunnel 和直接端口映射比,真正的安全收益在哪? 核心收益是“攻击面归零”。端口映射要求路由器上长期开一个监听端口,扫描器能直接打到你的服务,这个端口本身就得一直被修补和监控。Tunnel 反过来:连接永远由你机器主动向外发起,内网没有任何端口对公网开放,扫描器连门都找不到。暴露面从“整个端口上的服务”收缩到“Cloudflare 替你暴露的那几个主机名”,而且你家庭公网 IP 永不暴露给访客。这是实打实的安全改进,不是便利性的附赠。 走 Tunnel 之后,我的流量是不是全被 Cloudflare 看光了,还私密吗? 是的,流量会经 Cloudflare 中转,它看得到明文的请求与响应——这和任何挂在 Cloudflare 后面的站点没有区别。所以 Tunnel 不等于端到端加密,它解决的是“你不用把服务裸奔在公网”和“不用暴露家庭 IP”,而不是“Cloudflare 看不见”。对隐私敏感的本地服务,要么只对自己用(配 Cloudflare Access 限定邮箱),要么接受这个前提。把它当成“受 Cloudflare 保护的托管部署”来理解最准确。 免费版 Tunnel 有哪些坑,哪些事不能做? 免费版覆盖隧道连接本身,但有边界。第一,Cloudflare TOS 禁止通过免费隧道做流媒体分发(Plex/Jellyfin 这类),做视频串流会违规;第二,Argo Smart Routing 是单独付费项,免费隧道走的是公共回程,延迟更高;第三,UDP 支持有限,游戏服务器这类强 UDP 场景不合适。另外 Tunnel 引入了新依赖:你机器在线、cloudflared 运行、Cloudflare 网络正常,三个条件少一个服务就不可达,这点和静态托管不同,要纳入可用性评估。 用 Tunnel 暴露 SSH 很危险,怎么锁才安全? 裸暴露 SSH 确实危险,必须叠加 Cloudflare Access。做法:在 Zero Trust 控制台里把 ssh.yourdomain.com 注册成一个自托管应用,建一条策略只允许你自己的邮箱,并要求 OTP 或 SSO 二次验证。这样任何访客在流量触及你服务器之前,必须先过 Cloudflare 的身份校验。再配合短会话、限定来源国家,基本可以把“公网 SSH 暴破”这个老问题彻底关掉。记住:Tunnel 只是通道,身份校验才是锁。 Tunnel 挂了怎么发现、怎么failover,不能每次都靠用户报障吧? 不能靠报障。至少三层:第一,把 cloudflared 注册成 systemd 服务并 enable,进程崩了能自起;第二,在同一内网多部署一个 cloudflared 实例(同隧道或不同隧道),Cloudflare 会按就近和健康度failover,避免单机单点;第三,用外部拨测监控你的主机名是否 200,再监控 cloudflared 进程的存活与上游延迟。关键认知是:你的可用性 = 自己机器在线 + cloudflared 运行 + Cloudflare 网络正常,三者都要单独监控,不能只盯其中一项。

相关文章