Cloudflare Tunnel 配置实战:无需备案安全暴露内网服务

📅 2026-05-12 👤 运维 🔧 👁️ 37 次阅读 ⏱️ 6 分钟阅读 ❤️ 0

Cloudflare Tunnel 配置实战:无需备案安全暴露内网服务

背景:公司测试环境需要外网访问,但阿里云国内服务器 80/443 端口必须 ICP 备案。本文记录如何通过 Cloudflare Tunnel 绕过备案限制,安全暴露内网服务。


一、问题背景

1.1 需求场景

  • 开发测试环境部署在阿里云 ECS(杭州区域)
  • 需要随时随地访问测试网站
  • 应用运行在 localhost:5000

1.2 遇到的坑

问题 原因
开放 5000 端口给任意 IP 安全风险极高,易被扫描攻击
使用 Nginx + 80 端口 阿里云国内服务器 ICP 备案拦截,返回 403
使用 Nginx + 8080 端口 URL 带端口号,不美观
直接暴露公网 IP 源站 IP 泄露,易被 DDoS

1.3 核心诉求

  • ✅ 无需 ICP 备案
  • ✅ 使用标准 443 端口(HTTPS)
  • ✅ 隐藏真实服务器 IP
  • ✅ 自定义域名(如 blog.elliotz.men
  • ✅ 免费或低成本

二、解决方案:Cloudflare Tunnel

2.1 什么是 Cloudflare Tunnel?

Cloudflare Tunnel(原 Argo Tunnel)是 Cloudflare 提供的内网穿透服务,核心特点:

┌─────────────┐     ┌─────────────────┐     ┌─────────────┐
│   用户浏览器  │ →  │  Cloudflare Edge │ →  │  cloudflared │
│  (全球任意位置)│     │  (全球 CDN 节点)  │     │  (本地守护进程) │
└─────────────┘     └─────────────────┘     └──────┬──────┘
                                                    │
                                          ┌────────▼────────┐
                                          │  localhost:5000  │
                                          │  (你的应用)       │
                                          └─────────────────┘

流量走向: 1. 用户访问 https://blog.elliotz.men 2. DNS 解析到 Cloudflare Edge(最近 CDN 节点) 3. Cloudflare Edge 通过 outbound 连接(非入站)找到本地 cloudflared 4. cloudflared 将请求转发到 localhost:5000

2.2 核心优势

优势 说明
无需开放入站端口 服务器防火墙可全部关闭,cloudflared 主动 outbound 连接
无需公网 IP 甚至可以在 NAT/内网环境运行
自动 HTTPS Cloudflare 边缘自动签发证书,无需手动配置 SSL
隐藏源站 IP 用户只能看到 Cloudflare IP,保护源站
无需 ICP 备案 流量通过 Cloudflare 国外节点,不受国内备案限制
免费 Cloudflare Free 计划即可使用

2.3 与传统方案对比

方案 备案 暴露 IP HTTPS 成本 复杂度
直接开放端口 ✅ 暴露 手动配置
Nginx + 80/443 必须 ✅ 暴露 手动配置
Nginx + 非标准端口 ✅ 暴露 手动配置
Cloudflare Tunnel ❌ 无需 ❌ 隐藏 自动 免费
FRP/ngrok 部分暴露 手动配置

三、配置实战

3.1 准备工作

  • 注册 Cloudflare 账号(免费):https://dash.cloudflare.com
  • 注册域名(本文使用 elliotz.men,Cloudflare 注册,5年140元)
  • 一台 Linux 服务器(本文使用 Ubuntu 24.04)
  • 本地应用已运行(本文使用 localhost:5000

3.2 安装 cloudflared

# 下载安装包
cd /tmp
curl -L --output cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb

# 安装
sudo dpkg -i cloudflared.deb

# 验证安装
cloudflared --version
# 输出:cloudflared version 2026.3.0

3.3 创建 Tunnel

方式一:通过 Cloudflare Zero Trust Dashboard(推荐)

  1. 访问 https://one.dash.cloudflare.com
  2. NetworksTunnelsCreate a tunnel
  3. 选择 Cloudflared
  4. 填写名称:elliot
  5. 保存后会显示安装命令,复制 Token:
sudo cloudflared service install <TOKEN>

方式二:命令行创建(需要证书)

# 登录(浏览器认证)
cloudflared tunnel login

# 创建隧道
cloudflared tunnel create elliot

# 获取隧道 UUID
cloudflared tunnel list

3.4 配置路由

在 Dashboard 中配置 Public Hostname

  1. 进入 Tunnel 详情页 → Public Hostname 标签
  2. 点击 Add a public hostname
  3. 填写:
  4. Subdomain: blog
  5. Domain: elliotz.men
  6. Path: (留空)
  7. Type: HTTP
  8. URL: localhost:5000
  9. 点击 Save hostname

或在配置文件中定义(备用方案)

# /etc/cloudflared/config.yml
tunnel: <TUNNEL-UUID>
credentials-file: /etc/cloudflared/<TUNNEL-UUID>.json

ingress:
  - hostname: blog.elliotz.men
    service: http://localhost:5000
  - service: http_status:404

3.5 配置 DNS

在 Cloudflare Dashboard → DNS 中添加记录:

Type Name Target Proxy Status
CNAME blog <TUNNEL-UUID>.cfargotunnel.com 🟠 Proxied

注意:Target 是隧道的 CNAME 地址,格式为 <UUID>.cfargotunnel.com

3.6 启动服务

# 启动并设为开机自启
sudo systemctl start cloudflared
sudo systemctl enable cloudflared

# 查看状态
sudo systemctl status cloudflared

# 查看日志
sudo journalctl -u cloudflared -f

3.7 验证访问

curl -I https://blog.elliotz.men

# 预期输出:
# HTTP/2 200
# server: cloudflare
# cf-cache-status: DYNAMIC

四、踩坑记录

4.1 错误:503 Service Unavailable

现象

HTTP/2 503
cf-cache-status: DYNAMIC

原因:Tunnel 未配置 ingress 规则

解决: - 检查 Dashboard 中是否添加了 Public Hostname - 或检查 /etc/cloudflared/config.yml 是否有 ingress 配置 - 重启服务:sudo systemctl restart cloudflared

4.2 错误:403 Forbidden(阿里云备案拦截)

现象

<title>Non-compliance ICP Filing</title>

原因:阿里云国内服务器 80/443 端口未备案被拦截

解决:使用 Cloudflare Tunnel(流量通过 Cloudflare 边缘,不走阿里云 80/443)

4.3 错误:No ingress rules were defined

日志

WRN No ingress rules were defined... cloudflared will return 503

原因:Tunnel 运行了但没有配置路由规则

解决:在 Dashboard 的 Public Hostname 标签页添加路由,不是 Private Hostname

4.4 域名解析不生效

排查

# 检查 DNS 解析
nslookup blog.elliotz.men

# 检查是否指向 Cloudflare
dig blog.elliotz.men +short
# 应返回 Cloudflare 的 CNAME 或 IP

解决:等待 DNS 传播(通常几分钟),或检查 DNS 记录的 Proxy 状态是否为橙色云


五、进阶配置

5.1 多服务路由

ingress:
  - hostname: blog.elliotz.men
    service: http://localhost:5000

  - hostname: api.elliotz.men
    service: http://localhost:3000

  - hostname: admin.elliotz.men
    service: http://localhost:8080
    originRequest:
      noTLSVerify: true

  - service: http_status:404

5.2 添加基础认证(双重保护)

在 Nginx 层添加基础认证:

server {
    listen 80;
    server_name localhost;

    location / {
        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/.htpasswd;
        proxy_pass http://localhost:5000;
    }
}

5.3 配合 Cloudflare Access(零信任)

如需更严格的访问控制: 1. Cloudflare Dashboard → AccessApplications 2. 添加 blog.elliotz.men 3. 配置身份提供商(Google、GitHub、OTP 等) 4. 设置访问策略(如仅允许公司邮箱)


六、成本分析

项目 费用 说明
Cloudflare 账号 免费 Free 计划即可
Cloudflare Tunnel 免费 不限流量
域名 elliotz.men 140元/5年 Cloudflare 注册,比国内便宜
阿里云 ECS 按需 原有服务器,无额外费用
总计 140元/5年 约 28元/年

💡 对比:国内 .com 域名通常 60-80元/年,Cloudflare 注册确实更便宜


七、总结

7.1 核心原理

Cloudflare Tunnel 的本质是反向 WebSocket 连接

  1. 本地 cloudflared 主动连接 Cloudflare Edge(outbound)
  2. 建立持久 WebSocket 隧道
  3. 用户请求到达 Cloudflare Edge
  4. Edge 通过已有隧道将请求转发给本地
  5. 本地响应原路返回

关键:服务器无需开放任何入站端口,防火墙可以全部关闭。

7.2 适用场景

  • ✅ 开发测试环境外网访问
  • ✅ 家庭 NAS/内网服务暴露
  • ✅ 绕过 ISP 封锁或备案限制
  • ✅ 保护源站 IP 防止 DDoS
  • ✅ 快速临时分享本地服务

7.3 不适用场景

  • ❌ 高带宽视频流(有速度限制)
  • ❌ 生产环境核心服务(建议配合 Access)
  • ❌ 需要固定出口 IP 的场景

八、参考链接


作者:运维 🔧
日期:2026-05-12
标签:#cloudflare #tunnel #内网穿透 #网络安全 #免备案

最后更新:2026-08-11 06:47