为什么需要 Cloudflare Tunnel
在本地开发或自建服务时,我们经常遇到这些问题:
- • 没有公网 IP:家庭宽带通常是动态 IP,无法直接从外网访问
- • 端口映射麻烦:需要在路由器上配置端口转发,且暴露真实 IP
- • HTTPS 证书:自签名证书不被信任,申请证书又要域名验证
Cloudflare Tunnel 可以解决这些问题:通过 cloudflared 在本地建立出站连接到 Cloudflare,外部访问通过 Cloudflare 的边缘网络转发到本地服务,全程加密且无需暴露本地 IP。
准备工作
前提条件
- 1. 一个托管在 Cloudflare 的域名(免费账号即可)
- 2. 本地运行的服务(如 Web 服务、API、MCP 服务等)
安装 cloudflared
macOS(通过 Homebrew):
brew install cloudflared
Ubuntu/Debian(推荐方法 - 官方 APT 仓库):
# 添加 Cloudflare GPG key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
# 添加仓库(以 Ubuntu 22.04 jammy 为例)
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared jammy main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
# 更新并安装
sudo apt update
sudo apt install cloudflared
注意:如果不是 Ubuntu 22.04,将 jammy 替换为你的发行版代号:
查看发行版代号:lsb_release -cs
Ubuntu/Debian(备选方法 - 直接下载 deb 包):
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
其他 Linux 发行版(直接下载二进制):
# AMD64
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared
sudo chmod +x /usr/local/bin/cloudflared
# ARM64
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64
sudo mv cloudflared-linux-arm64 /usr/local/bin/cloudflared
sudo chmod +x /usr/local/bin/cloudflared
验证安装:
cloudflared --version
配置步骤
1. 登录 Cloudflare
cloudflared tunnel login
执行后会打开浏览器,选择要使用的域名并授权。授权成功后,会在 ~/.cloudflared/ 目录下生成 cert.pem 证书文件。
2. 创建 Tunnel
cloudflared tunnel create my-tunnel
记下输出中的 Tunnel ID(格式:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),执行成功后会在 ~/.cloudflared/ 目录下生成对应的凭证文件:<tunnel-id>.json。
3. 创建配置文件
在 ~/.cloudflared/ 目录下创建 config.yaml:
mkdir -p ~/.cloudflared
vim ~/.cloudflared/config.yaml
单个服务配置示例:
tunnel: <your-tunnel-id>
credentials-file: /home/username/.cloudflared/<tunnel-id>.json
ingress:
- hostname: app.yourdomain.com
service: http://localhost:8080
- service: http_status:404
多个服务配置示例:
tunnel: <your-tunnel-id>
credentials-file: /home/username/.cloudflared/<tunnel-id>.json
ingress:
- hostname: api.yourdomain.com
service: http://localhost:8080
- hostname: admin.yourdomain.com
service: http://localhost:8081
- hostname: mcp.yourdomain.com
service: http://localhost:8087
- service: http_status:404
注意:
- • 将
<your-tunnel-id> 替换为实际的 Tunnel ID - • 将
<tunnel-id>.json 替换为实际的凭证文件名 - • macOS 路径通常是
/Users/username/.cloudflared/ - • Linux 路径通常是
/home/username/.cloudflared/ - • 最后一条
service: http_status:404 是必需的兜底规则
4. 配置 DNS 路由
为每个域名配置 DNS CNAME 记录:
cloudflared tunnel route dns <tunnel-id> app.yourdomain.com
cloudflared tunnel route dns <tunnel-id> api.yourdomain.com
或者手动在 Cloudflare Dashboard 添加:
- • 目标:
<tunnel-id>.cfargotunnel.com
5. 测试运行
手动启动 tunnel 测试:
cloudflared tunnel run <tunnel-id>
或者使用配置文件名称:
cloudflared tunnel run my-tunnel
访问配置的域名,确认能正常访问本地服务。测试无误后按 Ctrl+C 停止。
6. 配置自启动服务
macOS 方案
重要提示:macOS 上的已知问题
macOS 上 cloudflared service install 命令存在长期已知 bug(Issue #327、Issue #589、Issue #1200):
- • 生成的 plist 文件缺少
tunnel run 参数 - • 服务启动后会循环报错:
Use cloudflared tunnel run to start tunnel <tunnel-id>
因此建议手动创建 plist 文件而不使用 cloudflared service install。
手动创建 LaunchAgent 配置文件:
vim ~/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>tunnel</string>
<string>--config</string>
<string>/Users/username/.cloudflared/config.yaml</string>
<string>run</string>
<string>my-tunnel</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/cloudflared.out.log</string>
<key>StandardErrorPath</key>
<string>/tmp/cloudflared.err.log</string>
</dict>
</plist>
关键配置说明:
- • 必须包含
tunnel 和 run 参数:这是官方 service install 命令生成的 plist 文件缺失的部分 - • Intel Mac 的 cloudflared 路径:
/usr/local/bin/cloudflared - • Apple Silicon (M1/M2/M3/M4) 的路径:
/opt/homebrew/bin/cloudflared - • 使用
which cloudflared 确认实际路径 - • 将
my-tunnel 替换为创建 tunnel 时使用的名称
验证配置文件语法:
plutil -lint ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
加载服务:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
检查状态:
launchctl list | grep cloudflared
tail -f /tmp/cloudflared.out.log
管理命令:
# 停止服务
launchctl bootout gui/$(id -u)/com.cloudflare.cloudflared
# 重启服务
launchctl kickstart -k gui/$(id -u)/com.cloudflare.cloudflared
Ubuntu/Linux 方案
创建 systemd 服务文件:
sudo vim /etc/systemd/system/cloudflared.service
内容如下:
[Unit]
Description=Cloudflare Tunnel
After=network.target
[Service]
Type=simple
User=your-username
ExecStart=/usr/local/bin/cloudflared tunnel --config /home/your-username/.cloudflared/config.yaml run my-tunnel
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
注意:
- • 将
your-username 替换为实际用户名 - • 将
my-tunnel 替换为 tunnel 名称 - • 确认
cloudflared 路径正确(用 which cloudflared 确认)
启用并启动服务:
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 启用开机自启
sudo systemctl enable cloudflared
# 启动服务
sudo systemctl start cloudflared
# 查看状态
sudo systemctl status cloudflared
# 查看日志
sudo journalctl -u cloudflared -f
管理命令:
# 停止服务
sudo systemctl stop cloudflared
# 重启服务
sudo systemctl restart cloudflared
# 禁用自启
sudo systemctl disable cloudflared
# 卸载服务
sudo systemctl stop cloudflared
sudo systemctl disable cloudflared
sudo rm /etc/systemd/system/cloudflared.service
sudo systemctl daemon-reload
常见问题
1. 服务启动失败
检查步骤:
# macOS
tail -20 /tmp/cloudflared.err.log
# Linux
sudo journalctl -u cloudflared -n 50
常见原因:
2. 无法访问服务
排查方法:
# 检查本地服务是否运行
curl http://localhost:8080
# 检查 DNS 配置
nslookup app.yourdomain.com
# 查看 tunnel 连接状态
cloudflared tunnel info <tunnel-id>
3. macOS 服务加载报错
如果遇到 Operation not permitted 或其他权限问题:
# 确保文件权限正确
chmod 644 ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
# 如果之前有残留,先清理
launchctl bootout gui/$(id -u)/com.cloudflare.cloudflared 2>/dev/null
# 重新加载
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
4. 配置文件 YAML 格式错误
YAML 对缩进非常敏感,必须使用空格而非 Tab:
# 正确 ✓
ingress:
- hostname: app.domain.com
service: http://localhost:8080
# 错误 ✗(Tab 缩进)
ingress:
- hostname: app.domain.com
service: http://localhost:8080
5. 端口冲突
如果本地服务未启动或端口不对,tunnel 会报错。确保:
# 检查端口占用
lsof -i :8080 # macOS
netstat -tlnp | grep 8080 # Linux
进阶配置
配置 HTTPS 后端
如果本地服务使用 HTTPS:
ingress:
- hostname: secure.yourdomain.com
service: https://localhost:8443
originRequest:
noTLSVerify: true # 忽略自签名证书
配置非 HTTP 服务(SSH、RDP 等)
ingress:
- hostname: ssh.yourdomain.com
service: ssh://localhost:22
- hostname: rdp.yourdomain.com
service: rdp://localhost:3389
添加自定义 HTTP 头
ingress:
- hostname: api.yourdomain.com
service: http://localhost:8080
originRequest:
httpHostHeader: api.yourdomain.com
总结
Cloudflare Tunnel 提供了一个简单、安全的方式将本地服务暴露到公网:
优点:
- • ✅ 支持多种协议(HTTP/HTTPS/SSH/RDP/WebSocket)
适用场景:
注意事项:
- • Tunnel 本身免费,但流量会经过 Cloudflare CDN
- • 生产环境建议启用 Cloudflare Access 进行访问控制
完整文档参考:
- • Cloudflare Tunnel 官方文档:https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/
- • MCP 服务配置:https://modelcontextprotocol.io/
阅读原文:https://mp.weixin.qq.com/s/ACH25PSxMEukiqe4tbC8Qg
该文章在 2026/2/24 11:04:17 编辑过