Cloudflare Tunnel:零端口暴露的内网穿透方案

目录

把内网服务发布到公网,传统方案是 frp / ngrok / 端口转发——都要么需要一台公网 VPS 当跳板,要么要花钱买套餐,要么得在路由器开端口。

Cloudflare Tunnel 是 CF 提供的免费方案:装一个客户端(cloudflared),它主动和 CF 的边缘建立反向连接,外网通过你的域名访问,全程 HTTPS,没有任何入站端口暴露。

一、为什么用 CF Tunnel

对比一下主流方案:

方案 公网 IP 端口转发 费用 HTTPS DDoS 防护
frp 自建 需要跳板 VPS 是 VPS 费用 需手动 无
ngrok 免费版 不需要 否 免费但限速/限连接 自动 无
端口转发(路由器) 需要 是 0 需手动 无
CF Tunnel 不需要 否 0 自动 有

适用场景:

  • 家里跑了 NAS / Jellyfin / HomeAssistant,想在外面访问
  • 小公司内网服务想给远程同事用,但没有公网 IP
  • 临时把开发环境 demo 给别人看
  • 树莓派跑了几个服务想公开

二、工作原理

流程图流程图

关键点:

  • cloudflared 主动连 CF,不需要内网开任何端口
  • 流量走 CF → cloudflared → 本地服务
  • 全程 TLS 加密,外网看到的是 CF 的 IP,不是你的真实 IP

三、准备工作

项目 要求
域名 已托管到 Cloudflare(必须)
内网机器 Linux / macOS / Windows / 路由器 / Docker 都能跑
Cloudflare 账号 免费版就够

如果你的域名还没在 CF:先去 dash.cloudflare.com → Add Site → 跟着指引改 NS。

四、操作步骤(推荐 Dashboard 方式)

CF 现在主推 Zero Trust Dashboard 配置 Tunnel,比命令行方式直观。

4.1 进入 Zero Trust

CF 控制台 → 左侧 Zero Trust → 第一次会让你选个 Team 名(随便起)。

4.2 创建 Tunnel

Networks → Tunnels → Create a tunnel:

步骤 操作
Connector type 选 Cloudflared
Tunnel name 随便起,如 home-nas
Save 保存后会给你安装命令

4.3 在你的内网机器上跑 cloudflared

CF 会给一段类似这样的命令(不同平台不一样):

# Linux (Debian/Ubuntu)
curl -L --output cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb

# 服务化 + 用 CF 给你的 token 注册
sudo cloudflared service install <YOUR-TUNNEL-TOKEN>
# Windows
# 下载 https://github.com/cloudflare/cloudflared/releases 里的 .msi 安装
cloudflared.exe service install <YOUR-TUNNEL-TOKEN>
# Docker
docker run -d \
  --name cloudflared \
  --restart unless-stopped \
  cloudflare/cloudflared:latest \
  tunnel --no-autoupdate run --token <YOUR-TUNNEL-TOKEN>

跑起来后回到 Dashboard,Connector 状态变成 HEALTHY。

4.4 配置 Public Hostname

Public Hostname → Add a public hostname:

字段 值
Subdomain nas(最终是 nas.your-domain.com)
Domain 选你的域名
Service Type HTTP / HTTPS / SSH / RDP / TCP 等
URL localhost:8080(内网服务的地址)

保存。CF 会自动给你的子域名添加 CNAME 记录。

4.5 验证

curl -I https://nas.your-domain.com

返回 200 / 301 等正常响应,整个流程跑通。

五、命令行方式(高级 / 想懂原理)

如果你想看到所有细节,命令行方式更清楚:

5.1 安装

curl -L --output cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb

cloudflared --version

5.2 登录 + 授权

cloudflared tunnel login

会打开浏览器让你选 zone,授权完后凭证存在 ~/.cloudflared/cert.pem。

5.3 创建 tunnel

cloudflared tunnel create home-nas

会输出 tunnel UUID,并把凭证存到 ~/.cloudflared/<UUID>.json。

5.4 写配置文件

~/.cloudflared/config.yml:

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

ingress:
  - hostname: nas.your-domain.com
    service: http://localhost:8080
  - hostname: jellyfin.your-domain.com
    service: http://localhost:8096
  - hostname: ssh.your-domain.com
    service: ssh://localhost:22
  - service: http_status:404         # 兜底

5.5 绑定域名 DNS

cloudflared tunnel route dns home-nas nas.your-domain.com
cloudflared tunnel route dns home-nas jellyfin.your-domain.com
cloudflared tunnel route dns home-nas ssh.your-domain.com

CF 会自动加 CNAME。

5.6 跑 + 服务化

# 前台跑(测试)
cloudflared tunnel run home-nas

# 服务化
sudo cloudflared service install
sudo systemctl status cloudflared

六、典型应用场景

6.1 把家里的 Jellyfin 发布到公网

ingress:
  - hostname: video.your-domain.com
    service: http://localhost:8096
  - service: http_status:404

外网浏览器访问 https://video.your-domain.com → 看你 NAS 上的电影。

6.2 SSH 到内网机器(不用 frp)

服务端配置:

ingress:
  - hostname: ssh.your-domain.com
    service: ssh://localhost:22

客户端要装 cloudflared 做转发:

# 本地 cloudflared
cloudflared access ssh --hostname ssh.your-domain.com

# 或者写到 ~/.ssh/config
Host my-home
    HostName ssh.your-domain.com
    ProxyCommand cloudflared access ssh --hostname %h

之后 ssh my-home 就能通到内网机器。

6.3 给路由器后台开公网入口

ingress:
  - hostname: router.your-domain.com
    service: https://192.168.1.1
    originRequest:
      noTLSVerify: true     # 路由器自签名证书要加这条

⚠️ 把路由器后台暴露公网风险很大——建议配合下面的 Access 鉴权。

七、加上 Access 鉴权(必看)

CF Tunnel 默认是任何能访问域名的人都能进。一定要加访问控制。

Zero Trust → Access → Applications → Add an application:

设置 推荐
Type Self-hosted
Application domain nas.your-domain.com
Policy → Action Allow
Include Emails / Email domains / Country / Device posture

常用策略:

  • Emails:只允许特定邮箱(输入 OTP 邮件验证码登录)
  • Email domains:只允许 @your-company.com 结尾
  • Country: 仅允许中国 / 美国
  • Service Token: 给 API/脚本访问用

加完之后,访问域名会先跳到 CF 的登录页,验证通过才进得去——免去自己写鉴权。

八、和 frp 对比

维度 CF Tunnel frp
公网入口 CF 边缘 IP 你自己的 VPS IP
协议 HTTP/HTTPS(主)、TCP/SSH/RDP 全协议 TCP/UDP
配置复杂度 低(Dashboard 点点) 中(写 ini 文件)
自定义域名 必须用 CF 托管 任意
性能 走 CF 边缘,国内访问需绕 直连跳板 VPS,可选近
鉴权 内置 Access 需自己加
国内访问 CF 国内段速度不稳 选国内 VPS 跳板更快

💡 国内访问 NAS / 自部署服务,有时候 frp + 国内 VPS 反而更快。CF Tunnel 的优势在于“零配置 + 自带鉴权 + DDoS 防护”。

九、踩坑清单

现象 原因 解决
cloudflared service install 报错 systemd 没启动 / 权限不够 用 sudo
Connector HEALTHY 但访问 502 内网服务没起 / 端口错 curl localhost:端口 验证
自签名证书报错 TLS 验证失败 originRequest: noTLSVerify: true
国内访问极慢 CF 国内段不稳 考虑反代或换方案
配置了 Access 但还能匿名访问 Policy 没启用 Dashboard 双检
Docker 跑的 cloudflared 连不上本机 默认 bridge 网络不通 host 用 --network host
改 config.yml 没生效 没 reload cloudflared tunnel run 自动 / 服务化要 restart

十、几条实用经验

  • 能用 Dashboard 别命令行——CF 现在主推 Dashboard,文档也更新更勤。
  • 一个 Tunnel 可以挂多个域名,不用每个服务建一个 Tunnel。
  • 配 Access 是基操,没 Access 等于把内网门户开公网。
  • 国内访问要测速:CF 国内出口偶尔不稳,跟优选 IP 那篇配合使用。
  • 不要在主路由器上跑 cloudflared——和软路由 / OpenWrt 配合容易 NAT 链路混乱。挂在 NAS / 一台单独的小主机上更稳。
  • cloudflared 升级很重要:CF 偶尔会让旧版客户端失效,建议开 --no-autoupdate 关掉自动升级、自己定期手动升级,避免半夜被自动重启搞掉。

把这套配通,你的家里 / NAS / 任何内网服务都能用域名 + HTTPS 访问,再也不用折腾路由器端口转发。