关于 cloudflare-vpc-services
此技能指导配置 Cloudflare Workers,通过 VPC 隧道访问私有 API 和服务,并提供配置模板、脚本及请求示例以辅助设置和排错。
主要功能
- 01VPC 隧道配置指南
- 02Wrangler 绑定配置
- 03私有 API 请求示例
- 04隧道故障排查
- 05配置模板与脚本
适用场景
- 01让 Worker 访问内部 API
- 02诊断 VPC 连接错误
- 03将请求路由至私有服务
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ nodnarbnitram/ claude-code-extensions --skill cloudflare-vpc-services安装后在 Claude Code 中输入/cloudflare-vpc-services确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/api-patterns.mdREADME.mdscripts/list-vpc-services.shREADME.mdset-api-token.shtail-worker.shtemplates/vpc-service-hostname.jsonvpc-service-ip.jsonwrangler-vpc.jsonc详细介绍
Cloudflare VPC Services
让 Workers 通过加密隧道安全访问私有 API 和服务,无需暴露到公共互联网。
⚠️ 开始之前
此技能可避免 5 个常见错误,并节省约 60% 的令牌用量。
| 指标 | 不使用技能 | 使用技能 |
|---|---|---|
| 设置时间 | 45 分钟以上 | 10 分钟 |
| 常见错误 | 5 | 0 |
| 令牌用量 | 约 8000 | 约 3000 |
此技能可避免的已知问题
- 因 cloudflared 版本过旧或协议错误导致的
dns_error - 因使用公共主机名而非内部主机名,导致请求离开 VPC
- 端口不匹配:fetch() 中的端口会被忽略,使用服务配置中的端口
- fetch() 调用中缺少绝对 URL
- 隧道 ID 或服务绑定配置不正确
快速开始
步骤 1:验证隧道要求
# Check cloudflared version on remote infrastructure (K8s, EC2, etc.)
# Must be 2025.7.0 or later
cloudflared --version
# Verify QUIC protocol is configured (not http2)
# Check tunnel config or Cloudflare dashboard
原因: Workers VPC 要求 cloudflared 版本为 2025.7.0 或更高,并使用 QUIC 协议。较旧版本或 http2 协议会导致 dns_error。
步骤 2:创建 VPC 服务
# Use Cloudflare API or dashboard to create VPC service
# See templates/vpc-service-ip.json or templates/vpc-service-hostname.json
原因: VPC 服务定义了隧道路由到的实际目标(IP/主机名)。fetch() URL 仅用于设置 Host 标头和 SNI。
步骤 3:配置 Wrangler 绑定
// wrangler.jsonc
{
"vpc_services": [
{
"binding": "PRIVATE_API",
"service_id": "<YOUR_SERVICE_ID>",
"remote": true
}
]
}
原因: 绑定名称会成为 Worker 代码中使用的环境变量:env.PRIVATE_API.fetch()。
关键规则
✅ 务必做到
- ✅ 在 fetch() 中使用包含协议、主机和路径的绝对 URL
- ✅ 使用内部 VPC 主机名,而非公共端点
- ✅ 确保 cloudflared 版本为 2025.7.0 或更高,并使用 QUIC 协议
- ✅ 允许 QUIC 连接的 UDP 端口 7844 出站
❌ 切勿这样做
- ❌ 在 fetch() URL 中使用端口号(它们会被忽略)
- ❌ 为 VPC 内的服务使用公共主机名
- ❌ 认为 http2 协议可用(仅支持 QUIC)
- ❌ 在 fetch() 中使用相对 URL
常见错误
❌ 错误:
// Port is ignored, relative URL fails
const response = await env.VPC_SERVICE.fetch("/api/users:8080");
✅ 正确:
// Absolute URL, port configured in VPC service
const response = await env.VPC_SERVICE.fetch("https://internal-api.company.local/api/users");
原因: 实际路由由 VPC 服务配置决定。fetch() URL 仅用于填充 Host 标头和 SNI 值。
避免已知问题
| 问题 | 根本原因 | 解决方案 |
|---|---|---|
dns_error | cloudflared < 2025.7.0 或使用 http2 协议 | 更新 cloudflared,配置 QUIC,并允许 UDP 7844 |
| 请求访问公共互联网 | fetch() 中使用了公共主机名 | 使用内部 VPC 主机名 |
| 连接被拒绝 | VPC 服务配置中的端口错误 | 在服务中配置正确的 http_port/https_port |
| 超时 | 隧道未运行或 tunnel_id 错误 | 验证隧道状态并检查 tunnel_id |
| 404 错误 | 路径路由不正确 | 验证内部服务路径与 fetch() 路径相符 |
配置参考
wrangler.jsonc
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2024-01-01",
"vpc_services": [
{
"binding": "PRIVATE_API",
"service_id": "daf43e8c-a81a-4242-9912-4a2ebe4fdd79",
"remote": true
},
{
"binding": "PRIVATE_DATABASE",
"service_id": "453b6067-1327-420d-89b3-2b6ad16e6551",
"remote": true
}
]
}
关键设置:
binding:用于访问服务的环境变量名称service_id:创建 VPC 服务时生成的 UUIDremote:VPC 服务必须设为true
常见模式
基本 GET 请求
export default {
async fetch(request, env) {
const response = await env.PRIVATE_API.fetch(
"https://internal-api.company.local/users"
);
return response;
}
};
带身份验证的 POST
const response = await env.PRIVATE_API.fetch(
"https://internal-api.company.local/users",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${env.API_TOKEN}`
},
body: JSON.stringify({ name: "John", email: "[email protected]" })
}
);
使用路径路由的 API 网关
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname.startsWith('/api/users')) {
return env.USER_SERVICE.fetch(
`https://user-api.internal${url.pathname}`
);
} else if (url.pathname.startsWith('/api/orders')) {
return env.ORDER_SERVICE.fetch(
`https://orders-api.internal${url.pathname}`
);
}
return new Response('Not Found', { status: 404 });
}
};
附带资源
模板
位于 templates/:
wrangler-vpc.jsonc- 可直接使用的 Wrangler 配置,包含 VPC 绑定vpc-service-ip.json- 基于 IP 的 VPC 服务 API 请求负载vpc-service-hostname.json- 基于主机名的 VPC 服务 API 请求负载
复制这些模板,以此作为实现的起点。
脚本
位于 scripts/:
list-vpc-services.sh- 通过 Cloudflare API 列出 VPC 服务tail-worker.sh- 使用实时日志调试 VPC 连接set-api-token.sh- 为私有 API 身份验证设置机密
参考资料
位于 references/:
api-patterns.md- 全面的 fetch() 模式和示例
依赖项
必需
| 软件包 | 版本 | 用途 |
|---|---|---|
| wrangler | latest | 使用 VPC 绑定部署 Workers |
| cloudflared | 2025.7.0+ | 隧道守护进程(在远程基础设施上) |
可选
| 软件包 | 版本 | 用途 |
|---|---|---|
| @cloudflare/workers-types | latest | Workers 的 TypeScript 类型 |
官方文档
故障排除
调用 VPC 服务时出现 dns_error
症状: Worker 调用 env.VPC_SERVICE.fetch() 时返回 dns_error
解决方案:
- 将远程基础设施上的 cloudflared 更新到 2025.7.0+
- 配置 QUIC 协议(而非 http2)
- 允许出站 UDP 端口 7844
请求发送到公共互联网
症状: 日志显示请求访问的是公共端点,而非内部端点
解决方案:
// Use internal hostname
const response = await env.VPC_SERVICE.fetch(
"https://internal-api.vpc.local/endpoint" // Internal
// NOT "https://api.company.com/endpoint" // Public
);
连接超时
症状: 请求挂起并最终超时
解决方案:
- 确认隧道正在运行:检查 cloudflared 日志
- 确认 VPC 服务配置中的 tunnel_id 匹配
- 检查隧道到目标的网络连接
设置检查清单
使用此技能前,请确认:
- cloudflared 2025.7.0+ 已部署在远程基础设施上
- 已配置 QUIC 协议(而非 http2)
- 已允许出站 UDP 端口 7844
- 已使用正确的 tunnel_id 创建 VPC 服务
- wrangler.jsonc 包含 vpc_services 绑定
- 使用内部主机名(而非公共端点)
- 在 fetch() 调用中使用绝对 URL
评论
支持 Markdown