DT

dt:to-public-cloudflare

Exposes local projects to the internet via Cloudflare Tunnels with custom domain mapping and automatic management scripts.

Install

mkdir -p .claude/skills/dt-to-public-cloudflare && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11846" && unzip -o skill.zip -d .claude/skills/dt-to-public-cloudflare && rm skill.zip

Installs to .claude/skills/dt-to-public-cloudflare

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Cloudflare Named Tunnel one-click setup: install cloudflared, login, configure tunnel with custom domain, auto-detect project port, push DNS route, write to global tunnel registry, and deploy management scripts (tunnel-add/start/stop/remove/list).
247 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Install cloudflared and log in.
  • Configure Cloudflare Named Tunnels with custom domains.
  • Auto-detect project ports.
  • Push DNS routes.
  • Deploy tunnel management scripts.

How it works

The skill automates the setup of Cloudflare Named Tunnels by installing cloudflared, handling login, configuring tunnels with custom domains, and deploying management scripts.

Inputs & outputs

You give it
Project's local service and desired custom domain
You get back
Publicly exposed service via Cloudflare Tunnel and management scripts

When to use dt:to-public-cloudflare

  • Exposing local development servers to the internet
  • Configuring custom domains for temporary demos
  • Managing multiple public tunnels for local services
  • Automating public tunnel deployment

About this skill

中文环境要求

本技能运行在中文环境下:

  • 面向用户的回复、注释、提示信息必须使用中文
  • AI 内部处理过程可以使用英文
  • 所有生成的文件必须使用 UTF-8 编码(无 BOM)

to-public-cloudflare Skill

将当前项目的本地服务通过 Cloudflare Named Tunnel 一键暴露到公网,绑定自定义域名,生成可复用的启动脚本。


三条铁律(执行前必读)

#规则违反后果
1DNS 路由必须用 TUNNEL_UUID,禁用 TUNNEL_NAME名称相似导致 DNS 指向错误 tunnel,公网 URL 不可用
2cloudflared tunnel route dns 必须加 -fDNS 记录已存在时报错 1003,流程卡死
3DNS 路由出问题时修复而非换子域名产生孤儿 DNS 记录,域名混乱,增加清理成本

核心命令/dt:to-public-cloudflare

参数说明:

  • 无参数:按上次配置(全局注册表)自动续用,跳过已完成的步骤
  • --force-reset:强制重新走全部配置流程(忽略缓存)

全局注册表

所有 tunnel 配置持久化到 ~/.cloudflared/tunnel-registry.json,格式:

{
  "domain": "long123456789.xyz",
  "tunnels": [
    {
      "name": "web",
      "tunnel_id": "<uuid>",
      "subdomain": "web",
      "hostname": "web.long123456789.xyz",
      "port": 4000,
      "config_file": "config-web.yml"
    }
  ]
}

每次执行时:

  1. 读取注册表,识别当前项目目录匹配的条目(通过端口与项目服务端口对比)
  2. 有匹配条目:提示"检测到已配置 tunnel:web.long123456789.xyz → 端口 4000,是否继续?"
    • y → 跳到 Step 8(更新注册表 + 提示启动命令)
    • n → 重新配置
  3. 无匹配:走完整流程

安装 skill 时,install.sh / install.ps1 会自动将 tunnel 管理脚本部署到 ~/bin/

脚本功能
tunnel-add交互式添加或更新 tunnel
tunnel-start [name...]启动指定或全部 tunnel + 健康监测
tunnel-stop停止所有 tunnel + 健康监测
tunnel-remove [name]删除 tunnel
tunnel-list列出所有 tunnel 及状态

重试工具函数(贯穿全流程)

在执行网络相关命令时,统一使用以下重试逻辑:

# retry_cmd <max_attempts> <sleep_seconds> <cmd...>
retry_cmd() {
  local max=$1 sleep_sec=$2; shift 2
  local attempt=1
  while [ $attempt -le $max ]; do
    if "$@"; then return 0; fi
    echo "[重试 $attempt/$max] 命令失败,${sleep_sec}s 后重试:$*"
    sleep "$sleep_sec"
    attempt=$((attempt + 1))
    sleep_sec=$((sleep_sec * 2))  # 指数退避
  done
  echo "[错误] 重试 $max 次仍失败:$*"
  return 1
}

PowerShell 等效:

function Invoke-WithRetry {
  param([int]$MaxAttempts=3, [int]$InitialSleep=2, [scriptblock]$ScriptBlock)
  $attempt = 1; $sleep = $InitialSleep
  while ($attempt -le $MaxAttempts) {
    try { & $ScriptBlock; return } catch {
      Write-Warn "[重试 $attempt/$MaxAttempts] 失败:$_,${sleep}s 后重试"
      Start-Sleep -Seconds $sleep; $attempt++; $sleep *= 2
    }
  }
  throw "[错误] 重试 $MaxAttempts 次仍失败"
}

Step 1:检测并安装 cloudflared

command -v cloudflared

未安装时按平台处理

平台命令备用
macOSbrew install cloudflared若无 brew → 提示安装 brew: https://brew.sh,然后重试
Linux (apt)sudo apt-get install -y cloudflared若 apt 无此包,先添加 repo:https://pkg.cloudflare.com/index.html
Linux (dnf)sudo dnf install -y cloudflared同上
Windowswinget install --id Cloudflare.cloudflared -e若无 winget,用 choco install cloudflared;都没有则提示手动下载:https://github.com/cloudflare/cloudflared/releases

安装后验证:

cloudflared --version

输出示例:cloudflared version 2024.x.x。若仍失败,报错并退出。


Step 2:检测登录状态

检查 cert.pem 是否存在:

# macOS/Linux
ls ~/.cloudflared/cert.pem 2>/dev/null

# Windows
Test-Path "$env:USERPROFILE\.cloudflared\cert.pem"

不存在时

cloudflared tunnel login

该命令会打开浏览器,用户在 Cloudflare Dashboard 选择授权的 zone(域名)。授权完成后 cert.pem 自动写入。

提示用户:

请在浏览器中完成授权,选择你的域名(zone)。
如浏览器未自动打开,请手动访问终端显示的链接。
授权完成后,按任意键继续...

等待用户按键后,验证 cert.pem 是否生成(重试 3 次,间隔 2s)。


Step 3:确认域名

从全局注册表读取 domain

  • 有缓存:提示"当前域名是 long.com,是否保留?(y/n)"
    • y → 使用缓存域名
    • n → 提示重新输入
  • 无缓存:提示"请输入你在 Cloudflare 上已托管的域名(如 long.com):"

提示前置条件:

域名须已添加到 Cloudflare 并完成 NS 配置。
如未完成:https://dash.cloudflare.com/ → 添加站点 → 按向导修改 NS 记录

输入后校验格式(至少包含一个点,无协议前缀),不合法则提示重新输入。


Step 4:校验授权作用域

执行:

retry_cmd 3 2 cloudflared tunnel list
  • 成功(包括空列表):授权正常,继续
  • 返回 401/403 或报认证错误:提示重新登录,跳回 Step 2

Step 5:输入 tunnel 名并创建

询问用户:

请输入 tunnel 名(英文+数字+-,如 my-app):

合法性校验:只允许 [a-z0-9-],不能以 - 开头或结尾。

查询是否已存在

cloudflared tunnel list --output json 2>/dev/null | grep -q "\"name\":\"$TUNNEL_NAME\""

若 jq 可用,用:

cloudflared tunnel list --output json | jq -e ".[] | select(.name==\"$TUNNEL_NAME\")"
  • 已存在:提示"tunnel aaa 已存在,是否复用?(y)/ 换一个名字(n)"
    • y → 从 JSON 中读取 tunnel-id,跳到 Step 6
    • n → 重新输入
  • 不存在
    retry_cmd 3 2 cloudflared tunnel create "$TUNNEL_NAME"
    
    解析输出中的 tunnel-id(格式 UUID),确认 ~/.cloudflared/<id>.json 已生成。

合成完整 hostname = <tunnel-name>.<domain>(如 aaa.long.com)。

CRITICAL: 创建成功后,必须保存以下变量供后续步骤使用:

  • TUNNEL_ID: 隧道 UUID(如 5af095b0-b00c-4b19-b1af-0c16183eef39
  • CREDS_FILE: credentials 文件路径(如 ~/.cloudflared/<TUNNEL_ID>.json
  • TUNNEL_NAME: 隧道名称
  • HOSTNAME: 完整域名(如 aaa.long.com

重要: 后续所有 cloudflared tunnel route dns 命令必须使用 TUNNEL_ID(UUID),绝不能使用 TUNNEL_NAME。因为 tunnel name 可能与其他名称相似的 tunnel 产生解析歧义,导致 DNS 路由到错误的隧道。


Step 6:检测项目启动命令与端口

在项目根目录按以下优先级侦察(从高到低),找到第一个有效端口即停止:

优先级来源文件侦察方式
1start.sh / start.ps1 / run.sh搜索 PORT= / --port
2package.json scripts.dev/start搜索 -p \d+ / --port \d+ / PORT=\d+
3.env / .env.local / .env.development搜索 ^PORT=\d+
4vite.config.* / next.config.*搜索 port:\s*\d+
5Python: app.run(port= / uvicorn ... --port / manage.py runserver搜索 port=\d+ / --port \d+;默认 8000
6Spring Boot: application.properties/yml搜索 server\.port=\d+
7Go: ListenAndServe\(":\d+正则搜索
8docker-compose.yml搜索 ports: 中的宿主端口

有侦察结果时

检测到启动命令:npm run dev
端口:3000(来源:package.json scripts.dev)
是否修改端口?直接回车保留 3000,或输入新端口号:

用户输入新端口时:

  1. 修改原配置文件中的端口(精确替换,只改端口数字,不改其他参数)
  2. 改动前展示 diff
  3. 让用户确认

无侦察结果时

未能自动检测到启动命令或端口。
请输入项目启动命令(如 npm run dev、python main.py、./start.sh):
请输入服务监听端口(如 3000):

Step 7:生成 cloudflare 配置并推送路由

7.1 生成配置文件

写入 ~/.cloudflared/config-<tunnel-name>.yml

tunnel: <tunnel-id>
credentials-file: /Users/<user>/.cloudflared/<tunnel-id>.json
ingress:
  - hostname: aaa.long.com
    service: http://localhost:3000
  - service: http_status:404

Windows 路径用 \ → 写入时改为 /(cloudflared 在 Windows 也接受 /)。

7.2 推送 DNS CNAME

CRITICAL — 必须使用 TUNNEL_ID (UUID) 而非 TUNNEL_NAME

使用 tunnel name 可能导致 DNS 路由到错误的隧道(cloudflared 可能将名称解析为其他已存在的隧道)。必须使用完整的 UUID。

# 正确:使用 UUID + -f 强制覆盖
cloudflared tunnel route dns -f "$TUNNEL_ID" "$HOSTNAME"

为什么必须加 -f? 如果该 hostname 之前配置过(即使是配置到其他 tunnel),不加 -f 会报错 "An A, AAAA, or CNAME record with that host already exists"。-f 会先删除旧记录再创建新记录。

CRITICAL — 验证路由是否正确指向你的 tunnel

# 确认输出中 tunnelID= 后面是你的 TUNNEL_ID
cloudflared tunnel route dns -f "$TUNNEL_ID" "$HOSTNAME"
# 正确输出示例:
# Added CNAME wecom.long123456789.xyz which will route to this tunnel tunnelID=5af095b0-...

如果输出的 tunnelID 不是你的 TUNNEL_ID,说明路由到了错误的隧道。此时需要:

  1. 检查 cloudflared tunnel list 确认 tunnel name 和 ID 对应关系
  2. 重新用 UUID 执行 cloudflared tunnel route dns -f <UUID> <HOSTNAME>

CRITICAL — 禁止创建替代子域名规避问题

如果 DNS 路由创建后输出显示 tunnelID 不正确(指向了错误的隧道),禁止换一个新子域名(如 wecom-demo 替代 wecom)来规避问题。必须先诊断根因:

  1. 确认 TUNNEL_ID 是否正确
  2. -f 标志 + UUID 强制覆盖

如果需要创建多个 tunnel 映射到同一个本地服务(例如临时测试),必须先向用户说明原因并获得同意。

7.3 等待 DNS 生效(提示用户)

DNS CNAME 记录创建后,需要 Cloudflare DNS 传播。提示用户:

DNS 记录已创建:<hostname> → <tunnel-id>.cfargotunnel.com

Cloudflare DNS 是全球分布式系统,新记录通常 1-5 分钟内在全球生效。
如果你现在访问 https://<hostname> 可能暂时无法解析,
这是正常现象,请稍等片刻再试。

我们将在启动 tunnel 后自动验证连接状态。

7.4 解析验证(可选,非阻塞)

# 验证 DNS 是否开始解析(新记录可能返回空)
dig +short "$HOSTNAME" CNAME 2>&1
# 如果返回空,说明 DNS 尚在传播中,继续后续步骤即可

Step 8:写入注册表 + 提示启动

不再生成 per-project 的 start-public.sh / start-public.ps1,改为写入全局注册表,由全局管理脚本统一启动和监控。

8.1 初始化注册表

注册表文件 ~/.cloudflared/tunnel-registry.json 可能不存在(首次使用时)。写入前必须检查并初始化:

REGISTRY_FILE="$HOME/.cloudflared/tunnel-registry.json"
if [ ! -f "$REGISTRY_FILE" ]; then
  echo '{"domain":"","tunnels":[]}' > "$REGISTRY_FILE"
fi

8.2 更新注册表

# bash (Python 替代 jq,兼容性更好)
python3 -c "
import json
with open('$REGISTRY_FILE') as f:
    reg = json.load(f)
reg['domain'] = '$DOMAIN'
reg['tunnels'] = [t for t in reg.get('tunnels', []) if t['name'] != '$TUNNEL_NAME']
reg['tunnels'].append({
    'name': '$TUNNEL_NAME',
    'tunnel_id': '$TUNNEL_ID',
    'subdomain': '$TUNNEL_NAME',
    'hostname': '$HOSTNAME',
    'port': $PORT,
    'config_file': 'config-${TUNNEL_NAME}.yml'
})
with open('$REGISTRY_FILE', 'w') as f:
    json.dump(reg, f, indent=2, ensure_ascii=False)
"

若无 Python,优先使用 jq(参考原版命令),再不行用 node。

8.3 冲突检测

场景处理
子域名已存在于注册表提示"web 已指向 4000 端口,是否更新为新端口?"→ 更新 config + 注册表
端口与其他 tunnel 相同允许(正常需求),提示"注意:build 也使用端口 3000"
Cloudflare 端同名 tunnel复用,跳过创建

Step 9:启动 Tunnel


Content truncated.

When not to use it

  • When exposing services without Cloudflare Named Tunnels.
  • When manual configuration of cloudflared is preferred.

Limitations

  • Requires a Cloudflare account with a hosted domain.
  • DNS routes must use TUNNEL_UUID, not TUNNEL_NAME.

How it compares

This skill provides a one-click setup for Cloudflare Tunnels with custom domain binding and management scripts, automating a process that would otherwise involve multiple manual steps and command executions.

Compared to similar skills

dt:to-public-cloudflare side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
dt:to-public-cloudflare (this skill)02moCautionIntermediate
deployment-pipeline-design62moReviewAdvanced
cloudflare-deploy36moReviewIntermediate
deployment-engineer44moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

deployment-pipeline-design

wshobson

Design multi-stage CI/CD pipelines with approval gates, security checks, and deployment orchestration. Use when architecting deployment workflows, setting up continuous delivery, or implementing GitOps practices.

670

cloudflare-deploy

davila7

Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or set up a project on Cloudflare.

342

deployment-engineer

sickn33

Expert deployment engineer specializing in modern CI/CD pipelines, GitOps workflows, and advanced deployment automation. Masters GitHub Actions, ArgoCD/Flux, progressive delivery, container security, and platform engineering. Handles zero-downtime deployments, security scanning, and developer experience optimization. Use PROACTIVELY for CI/CD design, GitOps implementation, or deployment automation.

418

devops

mrgoonie

Deploy to Cloudflare (Workers, R2, D1), Docker, GCP (Cloud Run, GKE), Kubernetes (kubectl, Helm). Use for serverless, containers, CI/CD, GitOps, security audit.

216

kcli-cluster-deployment

karmab

Guides deployment and management of Kubernetes clusters with kcli. Use when deploying OpenShift, k3s, kubeadm, or other Kubernetes distributions.

22

managing-deployment-rollbacks

jeremylongshore

Deploy use when you need to work with deployment and CI/CD. This skill provides deployment automation and orchestration with comprehensive guidance and automation. Trigger with phrases like "deploy application", "create pipeline", or "automate deployment".

11

Search skills

Search the agent skills registry