Cloudflare Tunnel 的命令行并不难。真正让日常使用变得零碎的,是命令之外的那些状态:cloudflared 装在哪里、当前使用哪份 YAML、Ingress 规则是否有效、哪个进程由谁启动、Edge 是否连通、源站是否还活着,以及一条 DNS 命令究竟会改动什么。
Tunnelful 是我为这类本地运维工作写的原生 macOS 应用。它不重新实现 Tunnel 协议,也不把 Cloudflare 控制台复制到桌面;它做的是更克制的一层——把分散在终端、配置文件和进程日志里的操作,收拢成一个能检查、能确认、能追溯的本地控制面。

浅色模式概览。公开截图使用中性示例数据,并开启隐私遮罩。
为什么不是再写一套 Tunnel 客户端
Cloudflare Tunnel 的核心模型很清楚:cloudflared 从源站侧主动连接 Cloudflare 网络,不要求把源站直接暴露在公网。对于本地管理的命名 Tunnel,官方 CLI 已经负责登录、创建、校验、路由和运行。
因此,Tunnelful 的架构选择不是“替代 cloudflared”,而是把责任切开:
| 层次 | 负责什么 |
|---|---|
Cloudflare 与 cloudflared |
Tunnel 协议、认证、Edge 连接与流量转发 |
| Tunnelful | 本机环境发现、配置编辑、命令编排、进程生命周期与状态展示 |
| 使用者 | 账户权限、域名、源站安全、上线判断与最终确认 |
这个边界很重要。桌面应用如果偷偷捆绑一个长期不更新的二进制,或者自己解释一套与官方 CLI 不一致的协议,短期看似“开箱即用”,长期却会制造版本、安全和责任上的第二套事实。Tunnelful 只发现或选择用户安装的官方 cloudflared,并显示版本与来源;安装和升级仍由使用者掌控。
一个状态灯不够描述真实运行状态
很多运维界面喜欢给服务放一个绿色圆点,但“绿色”经常混合了至少三件不同的事:
- 本地进程是否存在;
- 连接器是否已经连到 Cloudflare Edge;
- 本地源站是否能响应。
这三者并不等价。进程运行不代表 Edge 已连通,Edge 已连通也不代表 127.0.0.1:3000 背后的应用没有崩溃。反过来,本地源站正常时,Tunnel 也可能仍未启动。
Tunnelful 将它们拆成独立状态,并刻意限制措辞:只说“本 App 管理的进程”,不会因为自己没有进程句柄,就断言系统里不存在其他 cloudflared 服务。源站检查也单独执行,避免一次 Tunnel 连接抖动覆盖真正的应用故障。
这不是视觉上的信息增量,而是故障定位边界。状态一旦混在一起,用户下一步该检查本机、网络还是业务服务,就只能靠猜。
配置编辑的重点不是表单,而是写入协议
把 YAML 映射成几个输入框并不难。难的是在真实配置上做到“不丢、不抢、不写坏”。
Tunnelful 目前只结构化编辑 Ingress 中的 hostname、path 和 service。其他配置段、注释以及规则内的高级字段不会因为 GUI 不认识就被删除。保存时则经过一条明确的流水线:
- 在内存中检查必填字段、兜底规则和基本结构;
- 生成临时预览文件;
- 调用官方
cloudflared tunnel ingress validate校验; - 检查源文件在编辑期间是否被外部修改;
- 备份原文件,保留权限,再原子替换目标文件。
典型的本地配置仍然是官方格式:
tunnel: <TUNNEL_ID>
credentials-file: <CREDENTIALS_FILE>
ingress:
- hostname: preview.example.com
service: http://127.0.0.1:3000
- service: http_status:404
“先生成、再校验、最后提交”比直接覆盖文件多了几步,却避免 GUI 成为配置损坏的来源。外部修改检测同样不能省:编辑期间如果终端或其他工具已经更新原文件,应用应停止覆盖,让用户重新载入,而不是用旧快照赢下最后一次写入。
远端副作用必须在界面上暴露
编辑本地 YAML 与修改 Cloudflare DNS 不是同一种操作。前者有本地备份和恢复路径,后者会改变账户里的远端状态。
所以 Tunnelful 将 DNS 路由处理成一项独立动作:先生成并展示命令,可以只复制;如果要由应用执行,必须关闭隐私遮罩核对真实目标,并再次确认。当前命令显式带上 --overwrite-dns=false:
cloudflared tunnel route dns --overwrite-dns=false demo preview.example.com
这条限制不是为了增加点击次数,而是为了让副作用可见:应用不会静默覆盖同名 DNS 记录。命令超时时,远端结果仍可能已经生效,正确做法是先到 DNS 中核对,而不是无条件重试。
同样的原则也用于进程管理。Tunnelful 只停止或重启自己创建的子进程,不会扫描后杀掉所有同名进程。桌面工具可以提高操作效率,但不应该借“自动化”扩大控制范围。
把安全做成默认工作流
Tunnelful 不读取或上传 credentials 和 cert.pem 的内容,只检查完成当前工作流所需的文件元数据与账户可用性。命令使用参数数组直接启动,不把用户输入拼接成 shell 字符串;日志对常见 Token、用户目录等信息做尽力遮罩。
应用还提供单独的截图隐私模式。开启后,路径中的用户名、Tunnel 标识、域名、源站和 YAML 凭据位置都会换成中性示例值,相关编辑也会锁定。这个功能的出发点很实际:日志和运维界面经常要发给同事或贴进 Issue,泄漏往往不是发生在网络上传,而是发生在一张未经检查的截图里。
当然,脱敏只能降低误操作概率,不能代替人工审查。分享配置、日志或截图前,最终责任仍在使用者。
原生体验不是换一套皮肤
Tunnelful 使用 SwiftUI 编写,主窗口按照日常任务分成概览、Tunnel、发布服务、Ingress 配置、环境检查和日志六个入口。窗口打开时,它是标准 macOS 应用,提供系统菜单;全部窗口关闭后隐藏 Dock 图标,继续常驻菜单栏。
外观支持跟随系统、浅色和深色。登录 Mac 时打开应用、应用启动后运行当前 Tunnel 是两个独立开关:前者只决定应用是否启动,后者只有在 cloudflared、配置和 Tunnel 条件完整时才会执行。

深色模式与浅色模式使用同一信息结构,不靠颜色单独表达状态。
安装与第一次运行
Tunnelful 0.1.0 支持 macOS 14 或更高版本,GitHub Release 分别提供 Apple 芯片 arm64 与 Intel x86_64 安装包。先在“关于本机”确认芯片,再下载对应 DMG 和同名校验文件:
shasum -a 256 -c Tunnelful-0.1.0-arm64.dmg.sha256
应用不捆绑 cloudflared。可以先用 Homebrew 安装:
brew install cloudflared
cloudflared --version
随后在 Tunnelful 的“环境检查”中完成可执行文件、配置、凭据和账户状态检查。需要登录时,应用运行官方命令并打开 Cloudflare 页面:
cloudflared tunnel login
当前安装包采用 ad-hoc 签名,尚未使用 Developer ID 签名,也没有经过 Apple 公证。首次启动应只对从本项目 GitHub Release 下载并已核对 SHA-256 的应用,在访达中按住 Control 点按后选择“打开”;不建议运行来源不明的命令绕过系统安全检查。
0.1.0 的边界
这是一个可以使用的首个正式版本,但不是 Cloudflare 管理平台的桌面替代品。当前主要服务于已有本地 YAML 的 locally-managed 命名 Tunnel,并明确不包含:
- GUI 内创建或删除命名 Tunnel;
- Quick Tunnel 与 remotely-managed Tunnel Token 工作流;
- Cloudflare API、Access 策略、私网路由与多主机副本管理;
cloudflared自动安装或自动更新;- Developer ID 签名、Apple 公证和静默更新。
Cloudflare 当前更推荐大多数场景使用 remotely-managed Tunnel,本地管理模式更适合本地开发、测试或遗留配置。Tunnelful 选择先把这一条工作流做扎实,不意味着它适合所有生产拓扑。多副本、高可用、企业权限与远程配置需要另一套更完整的控制面设计,不能靠桌面 GUI 模糊带过。
为什么开源
运维工具会接触可执行文件路径、配置位置、进程输出和账户相关命令。即使它宣称“不上传”,用户也应该能够检查这句话如何落到代码里。
Tunnelful 以 Apache License 2.0 开源。仓库包含 SwiftUI 应用、单元测试、公开内容检查、双架构构建脚本和发布流程。原生应用当前没有额外的第三方 Swift Package 依赖。可以从源码运行:
git clone https://github.com/ihopefulChina/Tunnelful.git
cd Tunnelful
swift test --package-path app
open app/TunnelApp.xcodeproj
静态检查和构建通过不等于真实 Cloudflare 账户、DNS 或公网链路已经完成 UAT。项目把这些验证边界写进 README 与发布文档,是希望“可下载”和“已在你的环境中可上线”不要被混为一谈。
写在最后
我更愿意把 Tunnelful 看成一个边界清楚的小型控制面:它尊重 cloudflared 的权威性,把本地配置当作需要事务保护的数据,把远端变更当作必须确认的副作用,也承认一个进程状态无法代表整条链路。
如果你正在 macOS 上维护 locally-managed Cloudflare Tunnel,可以从 0.1.0 Release 开始。使用中遇到可复现的问题,欢迎在 GitHub Issues 提交;涉及凭据或安全边界的问题,请按照仓库中的 安全政策 私下报告。
延伸阅读: