cftunnel — Cloudflare Tunnel Manager for AI Agents
Expose local services to the internet via Cloudflare Tunnels. Use this skill when you need to make a locally running application accessible at a public HTTPS URL.
Flow: Start a local service (e.g. on port 3000) → cftunnel creates a tunnel + DNS route → the service is live at https://hostname.domain.com.
Authentication
Set these environment variables before running any command:
CODEBLOCK0
Quick Reference
Expose a local service (fastest path)
If a tunnel and cloudflared are already running (check with tunnel list), just add a route and DNS:
CODEBLOCK1
Create everything from scratch (one command)
CODEBLOCK2
Then run the connector: INLINECODE3
Programmatic usage (Node.js library)
CODEBLOCK3
All Commands
Tunnel lifecycle
| Command | Purpose |
|---|
| INLINECODE4 | List all tunnels. Find existing tunnel IDs and check status (healthy/down/inactive). |
| INLINECODE5 |
Create a new tunnel. Returns tunnel ID and secret. Add
--config-src local for YAML-managed config. |
|
npx cftunnel tunnel get <tunnel-id> | Get tunnel details including connection status. |
|
npx cftunnel tunnel delete <tunnel-id> | Delete a tunnel. Must have no active connections. |
|
npx cftunnel tunnel token <tunnel-id> | Get the token needed to run cloudflared. Returns
run_cmd and
install_cmd. |
Ingress routes (hostname → local service mapping)
| Command | Purpose |
|---|
| INLINECODE12 | Show current ingress rules. Always has a catch-all 404 as last rule. |
| INLINECODE13 |
Add a route. Preserves existing routes, appends before catch-all. Optional
--path for path filtering. |
|
npx cftunnel route remove <tunnel-id> --hostname <host> | Remove a route by hostname. |
|
npx cftunnel route set <tunnel-id> --route host1=svc1 --route host2=svc2 | Replace ALL routes. Use for bulk configuration. |
DNS records
| Command | Purpose |
|---|
| INLINECODE17 | Create proxied CNAME pointing hostname to tunnel. Required for the hostname to resolve. |
| INLINECODE18 |
List all DNS records in the zone. |
|
npx cftunnel dns delete <record-id> --zone-id <zid> | Delete a DNS record. |
Running the connector
| Command | Purpose |
|---|
| INLINECODE20 | Run cloudflared in foreground. Auto-detects cloudflared from PATH or npm package. |
| INLINECODE21 |
Install cloudflared as a persistent system service (survives reboots). |
Decision Guide
"I need to expose port N on a domain"
→ Check tunnel list for a healthy tunnel. If one exists, use route add + dns create. If not, use quickstart.
"I need to add another service to an existing tunnel"
→ route add + dns create. One tunnel can serve many hostnames.
"I need to change where a hostname points"
→ route remove --hostname X then route add --hostname X --service <new-url>. DNS stays the same.
"I need to take a service offline"
→ route remove --hostname X and optionally dns delete <record-id>.
"The tunnel exists but cloudflared isn't running"
→ npx cftunnel run <tunnel-id> or use tunnel token to get the token for manual cloudflared invocation.
Service URL Formats
The --service flag accepts these protocols:
| Format | Example | Use case |
|---|
| INLINECODE36 | INLINECODE37 | HTTP web apps, APIs |
| INLINECODE38 |
https://localhost:8443 | HTTPS backends |
|
tcp://host:port |
tcp://localhost:5432 | Databases, raw TCP |
|
ssh://host:port |
ssh://localhost:22 | SSH access |
|
unix:///path |
unix:///tmp/app.sock | Unix socket apps |
|
http_status:CODE |
http_status:404 | Static status response (catch-all) |
Output Format
All commands output JSON to stdout. Progress/errors go to stderr.
Parse with jq:
CODEBLOCK4
Common Patterns
Pattern 1: Deploy a new web app
CODEBLOCK5
Pattern 2: Add subdomain to existing tunnel
CODEBLOCK6
Pattern 3: Swap service behind a hostname
CODEBLOCK7
Pattern 4: Clean teardown
CODEBLOCK8
Pattern 5: Programmatic usage in agent code
CODEBLOCK9
Important Notes
- - A tunnel must have
cloudflared running to serve traffic. Creating a tunnel and routes alone is not enough. - The catch-all
http_status:404 rule is always appended automatically. Do not add it manually. - DNS CNAME records must be proxied through Cloudflare (orange cloud). This is set automatically.
- One tunnel can serve multiple hostnames. Prefer reusing existing healthy tunnels over creating new ones.
- INLINECODE51 replaces ALL routes. Use
route add/route remove for incremental changes. - If cloudflared is already running as a service, route changes take effect immediately (no restart needed).
Global Flags
| Flag | Env Var | Description |
|---|
| INLINECODE54 | INLINECODE55 | Cloudflare API token (bearer auth) |
| INLINECODE56 |
CLOUDFLARE_API_KEY | Cloudflare API key (requires --api-email) |
|
--api-email |
CLOUDFLARE_EMAIL | Cloudflare account email |
|
--account-id |
CLOUDFLARE_ACCOUNT_ID | Cloudflare account ID |
cftunnel — 面向AI代理的Cloudflare隧道管理器
通过Cloudflare隧道将本地服务暴露到互联网。当你需要让本地运行的应用程序通过公共HTTPS URL可访问时,使用此技能。
流程: 启动本地服务(例如在3000端口)→ cftunnel 创建隧道 + DNS路由 → 服务在 https://hostname.domain.com 上线。
身份认证
在运行任何命令前设置以下环境变量:
bash
选项A:API密钥 + 邮箱(最常见)
export CLOUDFLARE
APIKEY=
export CLOUDFLARE_EMAIL=
选项B:API令牌(作用域限定,如可用)
export CLOUDFLAREAPITOKEN=
始终需要:
export CLOUDFLAREACCOUNTID=
快速参考
暴露本地服务(最快路径)
如果隧道和cloudflared已在运行(使用 tunnel list 检查),只需添加路由和DNS:
bash
1. 向现有隧道添加入站路由
npx cftunnel route add --hostname --service http://localhost:
2. 创建DNS CNAME记录
npx cftunnel dns create --zone-id --hostname --tunnel-id
从头创建所有内容(一条命令)
bash
npx cftunnel quickstart \
--name \
--hostname \
--service http://localhost: \
--zone-id
然后运行连接器:npx cftunnel run
编程式使用(Node.js库)
typescript
import { createClient, quickstart } from cftunnel;
const client = createClient({ apiKey: ..., apiEmail: ... });
const result = await quickstart(client, {
accountId: ...,
name: my-app,
hostname: app.example.com,
service: http://localhost:3000,
zoneId: ...,
});
console.log(result.run_cmd);
所有命令
隧道生命周期
| 命令 | 用途 |
|---|
| npx cftunnel tunnel list | 列出所有隧道。查找现有隧道ID并检查状态(健康/离线/不活跃)。 |
| npx cftunnel tunnel create <name> |
创建新隧道。返回隧道ID和密钥。添加 --config-src local 使用YAML管理配置。 |
| npx cftunnel tunnel get | 获取隧道详情,包括连接状态。 |
| npx cftunnel tunnel delete | 删除隧道。必须没有活跃连接。 |
| npx cftunnel tunnel token | 获取运行cloudflared所需的令牌。返回 runcmd 和 installcmd。 |
入站路由(主机名 → 本地服务映射)
| 命令 | 用途 |
|---|
| npx cftunnel route list <tunnel-id> | 显示当前入站规则。始终以全匹配404作为最后一条规则。 |
| npx cftunnel route add <tunnel-id> --hostname <host> --service <url> |
添加路由。保留现有路由,在全匹配规则前追加。可选 --path 进行路径过滤。 |
| npx cftunnel route remove --hostname | 按主机名移除路由。 |
| npx cftunnel route set --route host1=svc1 --route host2=svc2 | 替换所有路由。用于批量配置。 |
DNS记录
| 命令 | 用途 |
|---|
| npx cftunnel dns create --zone-id <zid> --hostname <host> --tunnel-id <tid> | 创建代理CNAME记录,将主机名指向隧道。主机名解析必需。 |
| npx cftunnel dns list --zone-id <zid> |
列出区域中的所有DNS记录。 |
| npx cftunnel dns delete --zone-id | 删除DNS记录。 |
运行连接器
| 命令 | 用途 |
|---|
| npx cftunnel run <tunnel-id> | 在前台运行cloudflared。自动从PATH或npm包检测cloudflared。 |
| npx cftunnel run <tunnel-id> --install-service |
将cloudflared安装为持久系统服务(重启后仍存活)。 |
决策指南
我需要在域名上暴露N端口
→ 检查 tunnel list 是否有健康隧道。如果有,使用 route add + dns create。如果没有,使用 quickstart。
我需要向现有隧道添加另一个服务
→ route add + dns create。一个隧道可以服务多个主机名。
我需要更改主机名指向的目标
→ 先执行 route remove --hostname X,然后执行 route add --hostname X --service 。DNS保持不变。
我需要让服务下线
→ route remove --hostname X,可选执行 dns delete 。
隧道存在但cloudflared未运行
→ npx cftunnel run 或使用 tunnel token 获取令牌手动调用 cloudflared。
服务URL格式
--service 标志接受以下协议:
| 格式 | 示例 | 使用场景 |
|---|
| http://host:port | http://localhost:3000 | HTTP Web应用、API |
| https://host:port |
https://localhost:8443 | HTTPS后端 |
| tcp://host:port | tcp://localhost:5432 | 数据库、原始TCP |
| ssh://host:port | ssh://localhost:22 | SSH访问 |
| unix:///path | unix:///tmp/app.sock | Unix套接字应用 |
| httpstatus:CODE | httpstatus:404 | 静态状态响应(全匹配) |
输出格式
所有命令输出JSON到 stdout。进度/错误信息输出到 stderr。
使用 jq 解析:
bash
TUNNEL_ID=$(npx cftunnel tunnel create my-app | jq -r .id)
TOKEN=$(npx cftunnel tunnel token $TUNNEL_ID | jq -r .token)
常见模式
模式1:部署新的Web应用
bash
cd /path/to/app && npm start &
npx cftunnel quickstart \
--name my-web-app \
--hostname app.example.com \
--service http://localhost:8080 \
--zone-id
npx cftunnel run
模式2:向现有隧道添加子域名
bash
npx cftunnel tunnel list | jq .[] | select(.status == healthy)
npx cftunnel route add --hostname api.example.com --service http://localhost:4000
npx cftunnel dns create --zone-id --hostname api.example.com --tunnel-id
模式3:切换主机名后的服务
bash
npx cftunnel route remove --hostname app.example.com
npx cftunnel route add --hostname app.example.com --service http://localhost:9000
模式4:彻底清理
bash
npx cftunnel route remove --hostname app.example.com
npx cftunnel dns list --zone-id
npx cftunnel dns delete --zone-id
npx cftunnel tunnel delete
模式5:在代理代码中编程式使用
typescript
import { createClient, createTunnel, addRoute, createDNS } from cftunnel;
const client = createClient(); // 从环境变量读取
const tunnel = await createTunnel(client, { accountId: ..., name: my-app });
await addRoute(client, {
accountId: ...,
tunnelId: tunnel.id,
hostname: app.example.com,
service: http://localhost:3000,
});
await createDNS(client, {
zoneId: ...,
hostname: app.example.com,
tunnelId: tunnel.id,
});
重要说明
- - 隧道必须运行 cloudflared 才能提供流量服务。仅创建隧道和路由