Cloudflare Tunnel:不开端口也能访问家里的服务

Cloudflare Tunnel:不开端口也能访问家里的服务
想在外面访问家里 NAS 上的服务,但:
- 没有公网 IP(运营商给的是 NAT)
- 不想在路由器开端口(安全隐患)
- 不想用 ngrok(免费版域名随机、有限制)
后来发现 Cloudflare Tunnel:在本地装个 cloudflared,它主动连到 Cloudflare 边缘节点,外面通过域名访问时请求自动转发到本地。不用开端口,自带 HTTPS,还能加登录保护。
现在我的任务管理器 Web UI 就这么暴露的:https://<REDACTED_HOSTNAME>,出门也能看。
这是什么
Cloudflare Tunnel(原名 Argo Tunnel):
- 本地运行
cloudflared,它主动连接 Cloudflare - 外部请求通过 Cloudflare 边缘节点 → Tunnel → 本地服务
- 不需要公网 IP,不需要开端口
- 自动 HTTPS(Cloudflare 证书)
- 可选登录保护(Cloudflare Access)
架构图:
用户浏览器
│
▼
Cloudflare 边缘节点
│ (加密)
▼
cloudflared (你的电脑)
│
▼
本地服务 (localhost:5700)
效果展示
# 本地服务跑在 5700 端口
mt serve # 任务管理器 Web UI
# 通过公网域名访问
curl https://<REDACTED_HOSTNAME>
# 正常返回页面!
外面用手机也能访问,还能加 Google 登录保护。
快速开始
1. 安装 cloudflared
# macOS
brew install cloudflared
# Linux
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
chmod +x cloudflared && sudo mv cloudflared /usr/local/bin/
# 验证
cloudflared --version
2. 登录 Cloudflare
cloudflared tunnel login
会打开浏览器,选择要使用的域名(必须已托管在 Cloudflare)。授权后会在 ~/.cloudflared/ 生成证书。
3. 创建 Tunnel
cloudflared tunnel create my-tunnel
会输出 Tunnel ID,类似 <REDACTED_TUNNEL_ID>。
4. 配置 ingress
创建 ~/.cloudflared/config.yml:
tunnel: <TUNNEL_ID>
credentials-file: /Users/你的用户名/.cloudflared/74db0e95-xxx.json
ingress:
- hostname: <REDACTED_HOSTNAME>
service: http://127.0.0.1:5700
- service: http_status:404
ingress 是路由规则:
- 访问
<REDACTED_HOSTNAME>→ 转发到本地 5700 端口 - 其他请求 → 返回 404
5. 添加 DNS 路由
cloudflared tunnel route dns my-tunnel <REDACTED_HOSTNAME>
这会在 Cloudflare DNS 自动创建一条 CNAME 记录。
6. 启动 Tunnel
cloudflared tunnel run my-tunnel
现在访问 https://<REDACTED_HOSTNAME> 就能看到本地服务了。
开机自启(macOS)
# 安装为 LaunchAgent
cloudflared service install
# 但默认配置可能不对,建议手动创建 plist
手动创建 ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.cloudflare.cloudflared</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/cloudflared</string>
<string>--config</string>
<string><REDACTED_PATH></string>
<string>tunnel</string>
<string>run</string>
<string>my-tunnel</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardErrorPath</key>
<string><REDACTED_PATH></string>
</dict>
</plist>
加载:
launchctl load ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
添加登录保护(Cloudflare Access)
Tunnel 只负责网络连通,登录验证要用 Cloudflare Zero Trust 的 Access。
1. 进入 Zero Trust Dashboard
https://one.dash.cloudflare.com → Access → Applications
2. 创建 Application
- Type: Self-hosted
- Application name:
mt - Session duration: 24 hours
- Application domain:
<REDACTED_HOSTNAME>
3. 配置策略
- Policy name:
Allow me - Action: Allow
- Include: Emails →
保存后,访问 <REDACTED_HOSTNAME> 会先跳转到 Cloudflare 登录页,验证邮箱后才能访问。
常用命令速查
# === Tunnel 管理 ===
cloudflared tunnel list # 列出所有 tunnel
cloudflared tunnel info my-tunnel # 查看 tunnel 状态
cloudflared tunnel run my-tunnel # 启动 tunnel
cloudflared tunnel delete my-tunnel # 删除 tunnel(谨慎!)
# === DNS 路由 ===
cloudflared tunnel route dns my-tunnel <REDACTED_HOSTNAME> # 添加路由
# === macOS 服务管理 ===
launchctl list | grep cloudflared # 查看状态
launchctl kickstart -k gui/$(id -u)/com.cloudflare.cloudflared # 重启
launchctl unload ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist # 停止
# === 调试 ===
tail -f ~/Library/Logs/cloudflared.log # 查看日志
添加更多服务
一个 Tunnel 可以暴露多个服务,只需要修改 config.yml:
ingress:
- hostname: <REDACTED_HOSTNAME>
service: http://127.0.0.1:5700
- hostname: <REDACTED_HOSTNAME>
service: http://127.0.0.1:8787
- hostname: <REDACTED_HOSTNAME>
service: http://127.0.0.1:8888
- service: http_status:404
然后添加 DNS 路由并重启:
cloudflared tunnel route dns my-tunnel <REDACTED_HOSTNAME>
cloudflared tunnel route dns my-tunnel <REDACTED_HOSTNAME>
launchctl kickstart -k gui/$(id -u)/com.cloudflare.cloudflared
我踩过的坑
1. cloudflared service install 配置不对
默认安装的 LaunchAgent 可能没有指定 config 文件和 tunnel 名。建议手动写 plist。
2. 忘记最后的 404 fallback
ingress 最后一条必须是 catch-all,否则 cloudflared 启动会报错:
- service: http_status:404
3. DNS 路由和 ingress 要匹配
如果 DNS 路由了 <REDACTED_HOSTNAME>,但 config.yml 里没有对应的 hostname,访问会 502。
对比其他方案
| 方案 | 优点 | 缺点 |
|---|---|---|
| Cloudflare Tunnel | 免费、自带 HTTPS、可加 Access | 需要域名托管在 CF |
| ngrok | 简单快速 | 免费版域名随机、有限制 |
| frp | 自部署可控 | 需要公网服务器 |
| Tailscale | 点对点、安全 | 需要两端都装客户端 |
Cloudflare Tunnel 适合:域名在 CF、想要公开访问、需要登录保护。
附录:给 AI 的复现指令
帮我用 Cloudflare Tunnel 把本地服务暴露到公网。
目标:本地 5700 端口的 Web 服务,通过 <REDACTED_HOSTNAME> 访问。
前提:
- 域名 example.com 已托管在 Cloudflare
- 已安装 cloudflared
步骤:
1. cloudflared tunnel login(浏览器授权)
2. cloudflared tunnel create my-tunnel
3. 创建 ~/.cloudflared/config.yml:
tunnel: <TUNNEL_ID>
credentials-file: ~/.cloudflared/<TUNNEL_ID>.json
ingress:
- hostname: <REDACTED_HOSTNAME>
service: http://127.0.0.1:5700
- service: http_status:404
4. cloudflared tunnel route dns my-tunnel <REDACTED_HOSTNAME>
5. cloudflared tunnel run my-tunnel
开机自启(macOS):
- 创建 ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
- launchctl load 加载
可选登录保护:
- Cloudflare Zero Trust → Access → 创建 Self-hosted Application
- 配置 Email 策略允许指定邮箱
成功标志:浏览器访问 https://<REDACTED_HOSTNAME> 能看到本地服务