Cloudflare Tunnel 零公网 IP 安全外网访问教程
前言
家里的 NAS、自建博客、开发环境想从外网访问,但你没有公网 IP? 运营商不给力,DDNS 又不稳定,端口映射还有安全风险?Cloudflare Tunnel 提供了一个优雅的解决方案: 零公网 IP、零入站端口、默认 HTTPS, 还能和 Zero Trust 深度集成做身份验证。
简单来说,你在内网跑一个轻量级的 cloudflared 进程,它主动向 Cloudflare 边缘网络建立加密隧道。当用户访问你的域名时,流量先到 Cloudflare, 经过 WAF、Access 等安全检查后,再通过隧道转发到你的内网服务。整个过程,你的源站 IP 完全不暴露,防火墙也不用开任何入站端口。
本文适合:
- 想从外网访问家里 NAS / 自建服务的个人用户
- 需要为团队提供安全内网访问的小团队运维
- 不想折腾端口映射和动态 DNS 的开发者
读完你将学会:
- 两种部署方式:快速上手的控制台 Token 模式 vs 灵活的命名隧道配置模式
- 如何配置多服务、非 HTTP 协议 (SSH/RDP) 支持
- 结合 Zero Trust Access 做身份验证,让敏感服务更安全
- 常见问题排查和安全加固最佳实践
工作原理
在传统方式中,要从外网访问内网服务,你需要:公网 IP → 端口映射 → 防火墙放行。这意味着你的源站直接暴露在互联网上,容易被扫描、攻击。
Cloudflare Tunnel 反其道而行: 由内网主动连出去, 建立一条加密隧道到 Cloudflare 边缘。用户访问你的域名时:
用户浏览器
↓ HTTPS
Cloudflare 边缘服务器(WAF / Access / TLS 终止)
↓ 加密隧道
cloudflared 连接器(内网)
↓ HTTP/SSH/RDP 等
你的本地服务(NAS/博客/面板)
核心优势:
- 无需公网 IP、CGNAT 环境都能用
- 默认 HTTPS 自动签发证书
- 隐藏源站 IP 防护自带
- Zero Trust 集成: 可以加身份验证、设备态势检查等安全策略
准备工作
开始之前,确保你有:
- Cloudflare 账号: 免费计划即可,访问 dash.cloudflare.com 注册
- 域名托管在 Cloudflare: 需要将域名的 NS 记录指向 Cloudflare (在域名注册商处修改)
- Cloudflare Zero Trust 开通: 首次开通可能需要绑定支付方式 (用于防滥用), 但免费计划不会扣费
- 一台内网设备 / Linux /macOS 或支持 Docker 的环境都可以
路径选择:快速 vs 灵活
Cloudflare Tunnel 提供两种配置方式:
路径 A - 控制台托管 (推荐新手):
- 在 Zero Trust 控制台创建隧道,复制 Token 命令直接跑
- 适合快速验证、单个服务、不需要复杂配置的场景
- 配置都在控制台可视化管理,重装机器只需复制命令
路径 B - 命名隧道 + config.yml (推荐进阶):
- 本地创建隧道并生成凭据文件,写 YAML 配置管理多服务
- 适合多服务编排、非 HTTP 协议、私网路由、需要版本控制的场景
- 更灵活,但需要手动管理配置文件
建议: 先走路径 A 快速跑通,确认效果;长期使用或需要高级功能,再切换到路径 B。
路径 A: 控制台托管隧道 (10 分钟上手)
这是最简单的方式,几乎不需要写配置文件。
A1. 创建隧道
- 登录 Cloudflare Zero Trust
- 左侧导航: Networks → Tunnels
- 点击 Create a tunnel
- 选择 Cloudflared 连接器类型,点 Next
- 给隧道起个名字 (比如
home-tunnel), 点 Save tunnel
A2. 安装并运行 cloudflared
创建隧道后,页面会显示不同平台的安装和启动命令。
选择你的操作系统:
控制台会根据你选择的平台 (Windows /macOS/ Linux / Docker) 显示对应的安装步骤。如果机器上还没安装 cloudflared, 按页面指引先完成安装。
复制启动命令:
安装完成后,页面会给出一条带 Token 的命令,类似:
# 临时运行(测试用)
cloudflared tunnel --no-autoupdate run --token <你的TOKEN>
# 或安装为系统服务(推荐)
cloudflared service install <你的TOKEN>
提示: Token 模式的优势在于凭据直接包含在命令中,重装机器只需复制这条命令即可恢复服务,无需管理凭据文件。
在你的机器上执行该命令
- 如果是临时测试: 直接运行带
--token的命令,关闭终端会停止 - 如果是长期运行: 使用
cloudflared service install安装为系统服务,开机自启
执行后,回到控制台页面,底部应显示连接器状态为 HEALTHY, 点 Next 继续。
A3. 绑定公开域名
在隧道详情页,切换到 Public Hostname 标签:
-
点击 Add a public hostname
-
Subdomain: 填写子域名,比如
admin -
Domain: 选择你的域名,比如
example.com -
Service:
- Type: 选择
HTTP(或HTTPS如果内网服务用了 SSL) - URL: 填写内网服务地址,比如
http://localhost:8080或http://192.168.1.100:9000
- Type: 选择
-
点 Save hostname
DNS 记录会自动创建,Cloudflare 会添加一条 CNAME 记录指向你的隧道。
A4. 验证
- 等待 1-2 分钟让 DNS 生效
- 访问
https://admin.example.com - 如果一切正常,应该能看到你的内网服务
常见问题:
- 502 错误: 检查内网服务是否正常运行,端口是否正确
- 连接器显示 Disconnected: 检查 cloudflared 进程是否还在运行
路径 B: 命名隧道 + config.yml (进阶配置)
这条路径适合需要精细管理、多服务编排、非 HTTP 协议支持的场景。
B0. 安装 cloudflared
根据你的系统选择安装方式:
Linux (Debian/Ubuntu, 推荐方式):
# 从 GitHub 下载最新版本
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
# 验证安装
cloudflared --version
macOS:
brew install cloudflare/cloudflare/cloudflared
cloudflared --version
Windows:
# 使用 winget(Windows 10/11)
winget install --id Cloudflare.cloudflared
# 验证安装
cloudflared --version
如果你的系统没有包管理器,可以从 GitHub Releases 下载对应平台的二进制文件。
B1. 登录并创建命名隧道
1. 登录 Cloudflare 账号:
cloudflared tunnel login
这会打开浏览器让你授权,完成后会在本地生成 cert.pem 证书文件:
- Linux/macOS:
~/.cloudflared/cert.pem - Windows:
%USERPROFILE%\.cloudflared\cert.pem
2. 创建隧道:
cloudflared tunnel create my-tunnel
你会看到类似这样的输出:
Tunnel credentials written to /home/user/.cloudflared/12345678-abcd-1234-abcd-1234567890ab.json.
cloudflared chose this file based on where your origin certificate was found.
Keep this file secret. To revoke these credentials, delete the tunnel.
Created tunnel my-tunnel with id 12345678-abcd-1234-abcd-1234567890ab
记下这个隧道 UUID ( 12345678-abcd-1234-abcd-1234567890ab), 后面配置会用到。
3. 绑定域名到隧道:
cloudflared tunnel route dns my-tunnel app.example.com
这会在 Cloudflare DNS 中自动创建一条 CNAME 记录,指向你的隧道。
B2. 编写配置文件
创建配置文件 config.yml:
- Linux/macOS:
~/.cloudflared/config.yml - Windows:
%USERPROFILE%\.cloudflared\config.yml
基础示例 (单服务):
tunnel: 12345678-abcd-1234-abcd-1234567890ab
credentials-file: /home/user/.cloudflared/12345678-abcd-1234-abcd-1234567890ab.json
ingress:
- hostname: app.example.com
service: http://localhost:8080
- service: http_status:404
多服务示例:
tunnel: 12345678-abcd-1234-abcd-1234567890ab
credentials-file: /home/user/.cloudflared/12345678-abcd-1234-abcd-1234567890ab.json
ingress:
# 博客
- hostname: blog.example.com
service: http://localhost:8080
# NAS 管理界面
- hostname: nas.example.com
service: https://192.168.1.10:5001
originRequest:
noTLSVerify: true # 如果是自签证书
# 开发环境
- hostname: dev.example.com
service: http://localhost:3000
# SSH 服务
- hostname: ssh.example.com
service: ssh://localhost:22
# 默认规则(必需,匹配不到时返回 404)
- service: http_status:404
Windows 路径注意:
# Windows 路径需要用双反斜杠或正斜杠
credentials-file: C:\\Users\\YourName\\.cloudflared\\12345678-abcd-1234-abcd-1234567890ab.json
# 或
credentials-file: C:/Users/YourName/.cloudflared/12345678-abcd-1234-abcd-1234567890ab.json
B3. 运行隧道
前台运行 (测试):
cloudflared tunnel run my-tunnel
你会看到类似输出:
2024-12-07T10:30:00Z INF Starting tunnel tunnelID=12345678-abcd-1234-abcd-1234567890ab
2024-12-07T10:30:01Z INF Connection registered connIndex=0 location=NRT
2024-12-07T10:30:01Z INF Connection registered connIndex=1 location=NRT
看到 Connection registered 说明隧道已建立。
安装为系统服务 (生产环境):
Linux:
# 将配置复制到系统目录
sudo mkdir -p /etc/cloudflared
sudo cp ~/.cloudflared/config.yml /etc/cloudflared/
sudo cp ~/.cloudflared/*.json /etc/cloudflared/
# 安装并启动服务
sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
# 查看状态
sudo systemctl status cloudflared
macOS:
# 安装为 launchd 服务
sudo cloudflared service install
sudo launchctl start com.cloudflare.cloudflared
Windows:
# 以管理员身份运行
cloudflared service install
# 启动服务
Get-Service cloudflared | Start-Service
B4. 非 HTTP 协议与私网路由
SSH / RDP 访问:
在 config.yml 中配置非 HTTP 协议:
ingress:
- hostname: ssh.example.com
service: ssh://127.0.0.1:22
- hostname: rdp.example.com
service: rdp://192.168.1.20:3389
- service: http_status:404
客户端连接 SSH:
用户需要先安装 cloudflared, 然后:
# 方式 1:直接连接
cloudflared access ssh --hostname ssh.example.com
# 方式 2:配置 SSH 客户端
# 在 ~/.ssh/config 添加:
Host ssh.example.com
ProxyCommand cloudflared access ssh --hostname %h
私网路由 (访问整个内网段):
- 在配置文件中启用:
warp-routing:
enabled: true
-
在 Zero Trust 控制台添加私网路由:
- Networks → Tunnels → 选择你的隧道 → Private Networks 标签
- 点击 Add a private network
- 输入 CIDR, 比如
192.168.1.0/24
-
访问端安装 Cloudflare WARP 客户端, 登录你的 Zero Trust 团队后,就能直接访问内网 IP 了。
安全加固清单
Cloudflare Tunnel 虽然默认就比传统端口映射安全,但还可以做得更好:
1. 为敏感服务启用 Zero Trust Access
不要让管理面板、数据库管理工具等敏感服务裸奔在互联网上,哪怕通过隧道访问。
步骤:
-
在 Zero Trust 控制台: Access → Applications → Add an application
-
选择 Self-hosted
-
配置应用:
- Application name:
NAS Admin Panel - Session Duration:
24 hours - Application domain:
nas.example.com
- Application name:
-
添加策略:
- Policy name:
Allow My Email Only - Action:
Allow - Include: 选择 Emails → 输入你的邮箱
[email protected]
- Policy name:
-
保存后,访问
nas.example.com会先跳转到 Cloudflare Access 登录页,验证通过才能访问
支持的身份提供商:
- Google、GitHub、Microsoft 等 OAuth
- 一次性 PIN 码 (发送到邮箱)
- SAML / OIDC 企业身份源
2. 最小暴露原则
- 不要暴露数据库端口(MySQL 3306、PostgreSQL 5432 等), 用私网路由 + WARP 访问
- 不要暴露消息队列、Redis 等中间件, 除非你清楚在做什么
- 管理面板和对外服务分开子域, 便于差异化安全策略
3. 正确处理 HTTPS 回源
如果内网服务用了自签证书,测试阶段可以在配置中跳过验证:
ingress:
- hostname: admin.example.com
service: https://localhost:8443
originRequest:
noTLSVerify: true # 仅用于开发/测试
生产环境建议:
- 让 Cloudflare 终止 TLS (用 HTTP 回源)
- 或给内网服务配置由内网 CA 签发的证书,并在
originRequest中指定 CA
4. 部署冗余连接器
同一个隧道可以同时运行多个 cloudflared 实例 (比如在不同机器上), 提供高可用:
# 机器 A
cloudflared tunnel run my-tunnel
# 机器 B(使用相同的 tunnel ID 和凭据文件)
cloudflared tunnel run my-tunnel
Cloudflare 会自动负载均衡,任一实例挂掉不影响服务。
5. 日志和监控
设置日志级别以便排查问题:
cloudflared tunnel --loglevel debug run my-tunnel
或在配置文件中:
loglevel: info
查看日志:
- Linux systemd:
sudo journalctl -u cloudflared -f - Docker:
docker logs -f cloudflared - Windows: 事件查看器或服务日志
常见问题排查
Q1: 浏览器显示 502 Bad Gateway
可能原因:
- 内网服务没启动
- 端口号填错了
- 防火墙拦截了 cloudflared 到内网服务的连接
排查步骤:
# 在运行 cloudflared 的机器上测试内网服务
curl http://localhost:8080
# 检查端口是否在监听
netstat -tlnp | grep 8080 # Linux
netstat -an | findstr 8080 # Windows
Q2: 隧道状态显示 Unhealthy
可能原因:
- cloudflared 进程挂了
- 网络出站受限,无法连接 Cloudflare
- 配置文件有错误
排查:
# 查看进程
ps aux | grep cloudflared # Linux
Get-Process cloudflared # Windows
# 测试网络连通性
curl https://api.cloudflare.com/cdn-cgi/trace
# 前台运行查看详细日志
cloudflared tunnel --loglevel debug run my-tunnel
Q3: HTTPS 证书警告
如果用户访问时看到证书警告,通常是域名配置问题:
- 确保域名已托管在 Cloudflare
- 确保 Cloudflare SSL/TLS 设置不是 "关闭"
- 如果是多级子域 (
admin.sub.example.com), 需要申请 Advanced Certificate
Q4: 访问速度慢或不稳定
- 检查连接器是否健康: 控制台查看连接器状态
- 使用 Docker 并设置自动重启:
docker run --restart unless-stopped ... - 部署多个连接器: 提升可用性
- 检查本地网络: 如果是家用宽带,上行带宽可能是瓶颈
Q5: Docker 容器启动后立即退出
常见原因:
- Token 或凭据文件路径不对
- 配置文件格式错误 (YAML 缩进)
排查:
# 查看容器日志
docker logs cloudflared
# 挂载正确的配置路径
docker run -d --name cloudflared --restart unless-stopped \
-v ~/.cloudflared:/home/nonroot/.cloudflared \
cloudflare/cloudflared:latest tunnel run my-tunnel
与其他方案对比
| 方案 | 公网 IP | 端口映射 | 配置难度 | 安全性 | HTTPS | 成本 |
|---|---|---|---|---|---|---|
| Cloudflare Tunnel | 不需要 | 不需要 | 低 - 中 | 高 (可加 Access) | 自动 | 免费 |
| FRP | 需要中转服务器 | 需要 | 中 | 中 (需自配 SSL) | 需自配 | 中转服务器成本 |
| Ngrok | 不需要 | 不需要 | 低 | 中 | 自动 | 免费版受限,付费较贵 |
| 传统端口映射 | 需要 | 需要 | 高 | 低 (IP 暴露) | 需自配 | 无 (但需公网 IP) |
| Tailscale | 不需要 | 不需要 | 低 | 高 | N/A(P2P) | 免费版有设备数限制 |
Cloudflare Tunnel 的独特优势:
- 和 Cloudflare 生态深度集成、DDoS 防护、CDN、Access、Gateway 一条龙
- 免费且无流量限制: 对个人和小团队非常友好 (免费计划受 Cloudflare 的公平使用和反滥用策略约束,大规模或高风险场景可能需要付费计划)
- 全球边缘网络: 延迟低、可用性高
扩展阅读与参考
官方文档:
下载链接:
社区资源:
写在最后
Cloudflare Tunnel 把 "从外网安全访问内网服务" 这件事变得非常简单。对于个人用户,用控制台 Token 模式几分钟就能跑起来;对于需要精细管理的场景,命名隧道 + config.yml 也提供了足够的灵活性。
我的实际使用建议:
- 先用路径 A 快速验证: 确认 Cloudflare Tunnel 符合你的需求
- 生产环境切到路径 B: 把配置文件纳入版本控制,便于维护
- 敏感服务一定加 Access: 不要偷懒,设置一个邮箱验证就能大幅提升安全性
- 结合私网路由用 WARP: 对于需要访问内网多个设备的场景,比单独配置公开主机名更方便
如果你在使用过程中遇到问题,欢迎查阅官方文档,或在 评论区 / Cloudflare 社区提问。祝你折腾愉快!
此文由 Mix Space 同步更新至 xLog
原始链接为 https://blog.astrasolis.top/posts/tutorial/cloudflare-tunnel-tutorial