网络技术

Cloudflare Tunnel 实战:不需要公网 IP 也能安全暴露内网服务

✎ -- 字 🕐 -- 分钟
字号

你有一台没有公网 IP 的内网服务器,或者不想在防火墙上开放任何入站端口,但又需要从外网访问它——这正是 Cloudflare Tunnel 的用武之地。它通过在你的服务器上运行一个 cloudflared 守护进程,建立到 Cloudflare 全球网络的出站连接,流量从边缘节点通过这条隧道反向到达你的服务,全程不需要开放任何入站端口。

一、工作原理

用户请求
    |
    v
Cloudflare 边缘节点(全球 300+ PoP)
    |  <-- 持久出站 QUIC 隧道(由 cloudflared 建立)
    v
cloudflared 守护进程(运行在你的内网服务器上)
    |
    v
本地服务(localhost:3000 / localhost:8080 等)

关键点:内网服务器只需出站连接,不需要开放任何入站端口;天然支持 DDoS 防护、WAF、Zero Trust 访问控制;免费计划足够个人和小团队。

二、前置准备

  • 一个托管在 Cloudflare 的域名(免费迁移 NS 即可)
  • 内网服务器(Linux,能访问外网)
  • Cloudflare 账号(免费注册)

三、安装 cloudflared

Ubuntu / Debian

curl -L 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 -y
cloudflared --version

CentOS / RHEL

curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.rpm -o cloudflared.rpm
sudo rpm -ivh cloudflared.rpm

四、认证并创建 Tunnel

Step 1:登录

cloudflared tunnel login
# 浏览器选择域名授权,生成 ~/.cloudflared/cert.pem

Step 2:创建 Tunnel

cloudflared tunnel create my-homeserver
# Created tunnel my-homeserver with id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Step 3:配置文件

# ~/.cloudflared/config.yml
tunnel: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
credentials-file: /root/.cloudflared/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json

ingress:
  - hostname: app.example.com
    service: http://localhost:3000

  - hostname: git.example.com
    service: http://localhost:3000

  - hostname: ssh.example.com
    service: ssh://localhost:22

  - service: http_status:404

Step 4:创建 DNS 记录

cloudflared tunnel route dns my-homeserver app.example.com
cloudflared tunnel route dns my-homeserver ssh.example.com
# 自动在 Cloudflare DNS 添加 CNAME 记录

五、启动 Tunnel

临时运行

cloudflared tunnel run my-homeserver

systemd 服务(生产)

sudo cloudflared service install
sudo systemctl start cloudflared
sudo systemctl enable cloudflared
sudo journalctl -u cloudflared -f

六、SSH over Cloudflare Tunnel

无需知道对方 IP,无需 VPN,直接 SSH 连接内网服务器。

# ~/.ssh/config(客户端)
Host ssh.example.com
  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
  User root
  IdentityFile ~/.ssh/id_rsa
ssh ssh.example.com  # 第一次弹出浏览器验证,之后自动

七、Zero Trust 访问控制

配合 Cloudflare Access(免费 50 用户)实现身份验证:

  1. 访问 one.dash.cloudflare.com → Access → Applications
  2. 创建 Self-hosted Application,填写 app.example.com
  3. 配置 Policy:允许 @yourcompany.com 邮箱,或特定 IP 段直接放行

访问时会跳到 Cloudflare 登录页(支持 Google、GitHub、邮箱 OTP),验证通过才能进入。

八、多服务一套配置

ingress:
  - hostname: app.example.com
    service: http://localhost:3000

  - hostname: api.example.com
    service: http://localhost:8080
    originRequest:
      connectTimeout: 30s

  # 基于路径路由
  - hostname: example.com
    path: /admin
    service: http://localhost:9001

  - hostname: example.com
    service: http://localhost:3000

  # HTTPS 本地服务(跳过证书验证)
  - hostname: secure.example.com
    service: https://localhost:443
    originRequest:
      noTLSVerify: true

  - service: http_status:404

九、常见问题

DNS 解析失败

dig app.example.com CNAME
# 应返回 xxx.cfargotunnel.com
# 确认 Cloudflare 小黄云(Proxy)已开启

连接不稳定

sudo journalctl -u cloudflared -n 50
cloudflared tunnel run --retries 5 my-homeserver

本地服务无法访问

# service 以 cloudflared 进程视角为准
service: http://localhost:3000          # 同一台机器
service: http://192.168.1.100:3000      # 局域网另一台

十、与 frp/ngrok 对比

  • 不需要中转服务器:frp 需要一台公网 VPS,Tunnel 不需要
  • 天然 HTTPS + CDN:自动配置证书,接入 Cloudflare 全球 CDN
  • Zero Trust 集成:内置访问控制,无需自建 OAuth
  • 免费且稳定:依托 Cloudflare 全球网络,比自建中转可靠得多

对于家庭实验室、内网开发环境暴露、远程开发等场景,Cloudflare Tunnel 几乎是零运维成本的最优解。