1. 为什么“常用命令”这类需求十有八九是XY问题先说结论当有人问“Cloudflare Tunnel 常用命令有哪些”的时候他真正想解决的大概率不是“记不全命令”而是“我的服务外网访问不了不知道该从哪里下手”。这就是典型的XY问题。X是你问出来的那个问题Y是你实际想解决的问题。这种场景在运维群和论坛里太常见了。有人拿着cloudflared tunnel list、cloudflared tunnel run、cloudflared tunnel ingress validate这些命令代码碎片挨个试试完还是不行就跑来问“Tunnel的常用命令有哪些”。可问题从来不在命令多少而在于他可能压根没分清到底是隧道进程没起来是DNS记录没生效是Cloudflare边缘回源失败还是他后端的Web服务本身挂了。命令背得再多也只是把X问题做得更熟练Y问题纹丝不动。“常用命令大全”这类需求本身也容易陷入同样陷阱。我见过有人花了几天整理git常用命令总结真正提交代码时遇到冲突照样慌也有人把linux常用命令大全运维背得滚瓜烂熟线上服务器磁盘满了却不知道用df -h先看一眼再du定位。命令是工具不是目标。Cloudflare Tunnel相关命令也一样你要的不是“全部命令”而是一条能解决问题的诊断路径。那怎么看自己是不是在问XY问题三个信号第一问题描述里只出现了你想用的工具没有出现你的实际架构第二没有贴日志或复现步骤只说“不行”第三一上来就要“所有命令”“完整清单”而不是“某个场景下该用什么”。如果三条里中了两条恭喜你已经陷进X问题里了。下面这篇文章我打算先把Cloudflare Tunnel的常用命令讲透再把真正该掌握的排查思路串起来让你下次遇到问题能直接定位而不是背完命令还在原地打转。2. Cloudflare Tunnel 核心命令速查与背后原理2.1 生命周期五件套login / create / route / run / deleteCloudflare Tunnel的命令其实很少真正贯穿隧道生命周期的就五条login、create、route dns、run、delete。先说这几条后面所有的排查都建立在它们之上。cloudflared tunnel login这条命令会打开浏览器让你选择域名并授权。它的作用不是创建隧道而是生成本地证书默认存放在~/.cloudflared/cert.pem。这个证书决定了你后续能用哪个账号、对哪些域名做操作。很多新手在这步卡住浏览器打开后选了域名授权但终端还停在“Waiting for login to complete...”没反应。多数情况是终端预览环境不支持回调跳转直接把弹出的localhost链接完整复制到本机浏览器就行。注意login是按账号授权的不是按隧道授权。换了一台服务器要重新login一次。cloudflared tunnel create 隧道名创建的是“命名隧道”。它会在~/.cloudflared/下生成一个隧道ID.json文件这个文件就是隧道的身份证。你后续的run、route、delete都可以直接用隧道名或隧道ID指代它。这里有个很多人忽视的点隧道ID和cert.pem都要保存好换机器后缺了隧道ID.jsonrun会直接报“找不到凭据”。cloudflared tunnel route dns 隧道名 域名这条命令干的事情是添加一条CNAME记录把域名解析到隧道ID.cfargotunnel.com。它本质是把你自己的域名“绑定”到这条隧道上。如果你是在Cloudflare官网通过Dashboard创建隧道它不会在本地生成隧道ID文件而是给你一个Token后面用run --token跑这是两种不同创建方式后面第3部分会专门对比。cloudflared tunnel run 隧道名启动隧道进程和Cloudflare边缘节点建立持久连接把公网流量转发到本地的config.yml里配置的服务。你去看cloudflared tunnel list的输出会看到每条隧道后面跟着连接状态和上次活跃时间。这里我建议把run放在systemd或Docker里跑不要直接挂在终端。终端一关隧道就断这是新手最常见的“没访问一会儿就挂了”的原因。cloudflared tunnel delete 隧道名删除隧道前必须先删掉绑定DNS记录否则要加--force。删隧道不等于删本地隧道ID.json清理不彻底的话下次create同名隧道会冲突。这个细节官方文档写得不算明显但实际踩的人非常多。整个生命周期的逻辑可以用一句话串起来login拿到操作权限create造出隧道身份route dns把域名和隧道系起来run让隧道真正跑起来delete是回收站。掌握了这一条线命令就不是死记硬背而是有前因后果的。2.2 调试三兄弟--url临时隧道 / ingress validate / list顺着生命周期再往下有三个调试命令你在排障时会频繁用到。第一个是cloudflared tunnel --url http://localhost:3000不需要登录、不需要创建隧道它会快速生成一个https://随机字符串.trycloudflare.com的临时公网地址直接暴露你本地的Web服务。这个机制特别适合开发联调场景比如本地起了个前端项目想让同事或者微信支付的回调临时访问一下不用去折腾域名和DNS。缺点也很明显URL每次启动都会变没法用于固定域名也不能挂正式环境。第二个是cloudflared tunnel ingress validate它会读取本地的config.yml校验ingress规则有没有语法错误、hostname有没有重复、service格式对不对。这个命令在改完配置后务必执行一次。它不会真正连远端只是做本地静态校验报错信息比如Duplicate hostname、service URL scheme missing都能在启动之前就暴露出来。我自己每次改配置必跑一遍能省掉很多“改了配置但看不懂日志”的时间。第三个是cloudflared tunnel list列出当前账号下所有命名隧道包括隧道ID、名称、创建时间、连接状态。排障的第一步基本都从它开始先确认你要访问的那条隧道是不是真的存在、当前有没有连接。这三条命令加上前面的生命周期命令已经能覆盖90%的日常操作。但请注意这里还没有出现“出错了怎么查”的命令那是后面第4部分的重点。2.3 Docker部署时环境变量比命令行参数更好用现在很多人跑Cloudflare Tunnel都是基于Docker因为不用污染宿主机环境一条docker run就起来了。对比裸机部署Docker方式里使用最频繁的其实不是命令行参数而是环境变量。官方镜像cloudflare/cloudflared最核心的变量就是TUNNEL_TOKEN。你在Cloudflare Dashboard的Zero Trust面板里创建隧道后会拿到一个TokenDocker运行时只需docker run -d --name cloudflared \ --restartunless-stopped \ -e TUNNEL_TOKEN你的Token \ cloudflare/cloudflared:latest \ tunnel --no-autoupdate run --token 你的Token这里最关键的一点是通过Token方式运行时不需要本地cert.pem和隧道ID.json因为Token本身就是一次性打包好的身份凭据。很多人在容器里找不到~/.cloudflared目录就开始怀疑自己的部署方式有问题其实Token模式压根不强依赖那些文件。如果你是通过本地create创建的命名隧道再用Docker启动则需要把宿主机的~/.cloudflared/目录挂载进容器docker run -d --name cloudflared \ -v ~/.cloudflared:/etc/cloudflared \ --network host \ cloudflare/cloudflared:latest \ tunnel --config /etc/cloudflared/config.yml run 隧道名关于--network host我认为能用就不要省。它让cloudflared直接共享宿主机网络栈访问localhost:8080这类地址时就是访问宿主机上的服务。如果你用默认的bridge网络localhost指向的是容器自己你几乎一定会遇到“隧道起来了但页面502”的尴尬局面。另外TUNNEL_INGRESS变量可以让你不写config.yml就定义ingress规则。官方支持把这个变量设成一个JSON数组格式长这样-e TUNNEL_INGRESS[{hostname:app.example.com,service:http://web:8080},{service:http_status:404}]最后一条{service:http_status:404}是兜底规则所有没匹配到具体hostname的请求都返回404。我个人强烈建议不管用什么方式部署都保留这个兜底否则Cloudflare边缘拿到一条没有匹配规则的请求时行为会变得很不直观排障会更痛苦。命令行参数和环境变量的关系可以看成是“两套表达方式”命令行适合临时调试环境变量适合写进compose文件长期运行。比如cloudflared tunnel run --token xxx对应环境变量TUNNEL_TOKEN--url对应TUNNEL_URL--config对应TUNNEL_CONFIG_FILE。至于用哪套取决于你要不要上编排系统。跑在K8s里就老老实实用环境变量跑在单机上命令行完全够用。3. 实操三步把本地服务跑通一个稳定的 Tunnel3.1 准备阶段安装并确认cloudflared可用第2部分讲了命令这一部分我们完整走一遍实操。目标很简单一台服务器或者一台家里的小主机上面跑着一个Web服务端口是8080我们要用app.example.com通过Cloudflare Tunnel把它暴露到公网。第一步是安装cloudflared。Debian/Ubuntu直接用官方仓库装sudo apt-get update sudo apt-get install -y cloudflared cloudflared --version安装完先确认版本号能正常输出。如果你是在较老的系统上装可能遇到缺少依赖的问题直接用官方预先编译好的二进制包也行wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 chmod x cloudflared-linux-amd64 sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared这里有个职业习惯想分享给你装完后先跑一下cloudflared tunnel --help不用看全只看你关心的那几个命令是否存在。不同版本的参数可能有差异比如老版本用cloudflared tunnel route新版本可能已经改了写法。先确认版本再往下走能避免后面拿着旧教程踩坑。3.2 创建隧道、绑定域名、编写config.yml然后执行登录授权cloudflared tunnel login浏览器打开后选择example.com所在账号授权成功后终端显示Successfully logged in。紧接着创建命名隧道cloudflared tunnel create app-tunnel成功后终端会打印隧道ID和凭据文件路径类似/home/user/.cloudflared/隧道ID.json。然后绑定域名cloudflared tunnel route dns app-tunnel app.example.com这一步会在Cloudflare侧对app.example.com创建一条CNAME记录指向隧道ID.cfargotunnel.com。如果这里提示E_DNS_RECORD_EXISTS说明同名记录已经存在先去DNS面板删掉旧记录再重新执行。接下来编写配置文件位置是~/.cloudflared/config.yml内容如下tunnel: app-tunnel credentials-file: /home/user/.cloudflared/隧道ID.json ingress: - hostname: app.example.com service: http://localhost:8080 - service: http_status:404注意credentials-file必须是绝对路径写~/.cloudflared是可以的但你在systemd服务里跑的时候~不一定展开成你想要的路径我吃过这个亏直接写绝对路径最省心。写完后立刻校验cloudflared tunnel ingress validate如果输出Validating rules... OK说明配置没问题。到这一步隧道还没在跑域名也解析不出什么内容千万别急着去浏览器访问。3.3 正式启动从前台到后台再到服务化管理前台启动最方便观察首次运行情况cloudflared tunnel run app-tunnel看到日志出现Registered tunnel connection之类的信息再开第二个终端用curl -I https://app.example.com验证。如果首页能正常返回200说明流程通了。这时候立刻把进程交给systemd托管防止终端退出后隧道失联cloudflared service install sudo systemctl enable cloudflared sudo systemctl start cloudflaredcloudflared service install会自动读取~/.cloudflared/config.yml把它注册成systemd服务。启动后确认状态sudo systemctl status cloudflared sudo journalctl -u cloudflared -f --no-pager日志里如果能看到多条连接状态由connecting变成connected说明它和Cloudflare边缘的几条连接都建好了。到这里一个稳定可用的Tunnel就算完整落地了。后面你再改配置只需三步vi ~/.cloudflared/config.yml、cloudflared tunnel ingress validate、sudo systemctl restart cloudflared。4. 当“Y”真实问题出现时从报错定位到可用的排查命令4.1 三种典型报错凭据缺失、隧道未注册、证书过期命令流程走通了但真正检验你是否理解这套东西的时刻是在你接到“外网打不开”的报障消息时。我按自己在群里帮人看问题的经验整理了三个出现频率最高的报错。第一个是error: unable to find credentials file。启动run时cloudflared在你指定的路径下找不到JSON凭据文件。原因通常是第一你换了用户运行比如之前用root创建的隧道现在用ubuntu用户去run第二你在Docker里挂载路径写错了第三你直接把原来的配置文件拷到新机器但没一起拷凭据文件。解决办法很简单确认当前运行用户的家目录下有隧道ID.json路径和config.yml里credentials-file完全一致。第二个是ERR Tunnel not found、INVALID_REQUEST这类注册失败报错。意思是Cloudflare侧不认识你提供的隧道ID或Token。这种情况最常见的原因是你在A账号创建了隧道然后跑到B账号控制的域名下用或者Token是从Dashboard复制的复制时包含了换行符导致认证失败。你重新复制Token时注意别带空格用命名隧道的检查一下cloudflared tunnel list输出里到底有没有这个名字的隧道。第三个是certificate has expired或token is expired。cert.pem的有效期我记得是十年左右Token模式一般是一段时间有效长时间挂机之后可能出现Token过期。解决方案分别是重新执行cloudflared tunnel login重新授权或者去Dashboard生成一个新Token刷新部署。这类问题和你的Web服务本身没有任何关系如果是刚接手别人留下的系统先看证书和Token再去折腾后端。4.2 日志与系统命令组合从日志金矿里捞线索报错信息只是线索真正完整的证据链在日志里。裸机部署用journalctlDocker部署用docker logs。这里说两个高频组合sudo journalctl -u cloudflared -f --no-pager | grep -i error-f是持续跟踪--no-pager防止日志太多卡在less里。先不跟grep把最近几十行都看一遍再去抓error级别。很多时候你觉得没线索其实是filter太早把上下文丢了。Docker场景则常用docker logs --tail 200 cloudflared输出量很大时先看时间范围内最后几行再搜关键词。日志里反复出现的connection、register、reconnect这几个关键词是有分量的。Registered tunnel connection说明注册成功频繁Reconnecting说明网络到Cloudflare边缘的链路不稳定Unable to unmarshal说明config.yml写错了。另外一个很容易漏掉的排查来源是Cloudflare Dashboard的Analytics。在Zero Trust面板里选中对应的隧道能看到小时级别的流量和请求统计。如果面板上有请求记录但服务器日志完全没有对应报文问题大概率出在ingress规则和本地服务之间。如果面板上压根没有记录说明请求根本没到Cloudflare边缘那就要去查域名解析。4.3 常见问题速查表这里放一张速查表适合贴在屏幕上遇到问题先对号入座。症状可能原因优先命令/操作域名访问超时DNS记录未生效或CNAME指向错误dig app.example.com short确认是否返回隧道ID.cfargotunnel.com页面显示523 Origin Unreachable隧道进程和边缘连接断了cloudflared tunnel list看连接状态重启cloudflared进程页面显示522 Connection timed out隧道进程到边缘建连超时多为本地出网问题检查journalctl -u cloudflared里connection日志确认cloudflared运行正常页面显示524 Timeout本地Web服务响应过慢curl -I http://localhost:8080直连本地服务检查后端耗时502 Bad Gateway反复出现ingress配置的service地址错误cloudflared tunnel ingress validate 确认localhost是否写对Docker记得考虑网络模式ERR Tunnel not found隧道ID/Token和账号不匹配cloudflared tunnel list核对隧道名Dashboard重新生成Token打开页面提示证书错误证书过期或域名SSL模式异常cloudflared tunnel login重新授权检查SSL/TLS加密模式这张表的逻辑其实是把一条访问链路切成五段客户端到Cloudflare边缘、边缘到Tunnel连接、Tunnel到本地服务、本地服务本身、Cloudflare域名配置。任何一段出问题表现都会不一样。所以你下次遇到“打不开”别一上来就怀疑Cloudflare Tunnel整体坏了。先用curl -I https://你的域名看HTTP状态码能拿到状态码说明链路通到了边缘拿不到说明解析或边缘就没通。再curl -I http://localhost:8080测本地。两头一夹问题落在哪一段马上就清楚了。5. 别让X问题吞掉真正的Y问题推荐一整套排查顺序5.1 分层排查不打乱仗最后这部分我想把前面所有命令收敛成一整套排查顺序。这套顺序的核心是先确认问题边界再动手跑命令。顺序大概是这样的先确认现象直接curl -I https://app.example.com记录HTTP状态码。再确认DNSdig app.example.com short看看结果是不是隧道ID.cfargotunnel.com。确认隧道本体cloudflared tunnel list看目标隧道是否正常在线。确认本地进程systemctl status cloudflared或docker ps | grep cloudflared。确认配置cloudflared tunnel ingress validate。确认上游服务curl -I http://localhost:8080。每一步都是上一层的证据也是下一层的铺垫。如果你一上来就重启cloudflared但它本身没病那是在白折腾。我在实际排障中见过最浪费时间的操作就是“不管三七二十一把所有服务全重启一遍”。重启一时爽问题却像打地鼠一样换个地方冒出来。5.2 我实际排查时必问的五个问题如果你是在帮别人远程看问题文字沟通效率很低上面这套命令也很难直接甩给对方。我给自己的规矩是先问五个问题你的服务是什么架构是Docker还是裸机跑访问域名直接返回什么是超时、526、还是空白页cloudflared的最近一条日志是什么贴原文出来这个服务之前是好的吗最近做过什么改动本地直连服务通不通curl http://localhost:端口号有反应吗这五个问题问完大多数XY问题就已经被消解了。你会发现对方想表达的“常用命令有哪些”其实转化成“我的config.yml里service写成了https现在一直502怎么改”这种具体问题。到这一步具体问题配具体命令答案很容易出来。这套思路不只适用于Cloudflare Tunnel。你学习linux常用命令大全、背git常用命令总结、查docker常用命令其实都应该先问自己一句我现在到底要解决什么需要查昨天哪个日志文件变大就去学du和ls需要找出容器里谁在疯狂刷日志就去学docker logs加grep需要看某条隧道为什么连不上边缘才需要看cloudflared tunnel list和journalctl。把Y问题定义清楚X问题的命令自然会出现在你手边。我现在维护的几条隧道里有一条已经连续跑了将近一年没动过。不是我运气好而是当初部署时就把systemd、日志、DNS记录和config.yml四件套一次配齐了。平时唯一要做的就是偶尔看一眼journalctl -u cloudflared有没有刷错误。真正让我省心的不是记住了多少命令而是出了一次问题之后终于学会了按照链路去排查——那比背下所有命令有价值得多。