Share

外观
风格

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

2026年2月8日 · 专栏

封面图

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> 能看到本地服务