Help us improve
Share bugs, ideas, or general feedback.
From cce-cloudflare
Diagnoses and configures Cloudflare VPC Services for Workers to access private APIs in AWS, Azure, GCP, or on-premise networks. Use for dns_error troubleshooting, cloudflared tunnels, VPC bindings, and internal service routing.
npx claudepluginhub nodnarbnitram/claude-code-extensions --plugin cce-cloudflareHow this skill is triggered — by the user, by Claude, or both
Slash command
/cce-cloudflare:cloudflare-vpc-servicesThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Enable Workers to securely access private APIs and services through encrypted tunnels without public internet exposure.
Guides Cloudflare platform development: Workers, Pages, storage (KV, D1, R2), AI (Workers AI, Vectorize, Agents SDK), feature flags (Flagship), networking (Tunnel, Spectrum), security (WAF, DDoS), IaC (Terraform, Pulumi). Prioritizes docs retrieval.
Provides Cloudflare platform knowledge on Workers, storage (R2/D1/KV/Durable Objects/Queues), AI Workers, Hyperdrive, Zero Trust, Workflows, Vectorize, and Wrangler CLI for dev, deployment, and best practices.
Configures private networking for Render services with internal DNS, service discovery, and cross-service communication. Useful for wiring services, resolving hostnames, troubleshooting connectivity, and environment isolation.
Share bugs, ideas, or general feedback.
Enable Workers to securely access private APIs and services through encrypted tunnels without public internet exposure.
This skill prevents 5 common errors and saves ~60% tokens.
| Metric | Without Skill | With Skill |
|---|---|---|
| Setup Time | 45+ min | 10 min |
| Common Errors | 5 | 0 |
| Token Usage | ~8000 | ~3000 |
dns_error from outdated cloudflared version or wrong protocol# 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
Why this matters: Workers VPC requires cloudflared 2025.7.0+ with QUIC protocol. Older versions or http2 protocol cause dns_error.
# Use Cloudflare API or dashboard to create VPC service
# See templates/vpc-service-ip.json or templates/vpc-service-hostname.json
Why this matters: The VPC service defines the actual target (IP/hostname) that the tunnel routes to. The fetch() URL only sets Host header and SNI.
// wrangler.jsonc
{
"vpc_services": [
{
"binding": "PRIVATE_API",
"service_id": "<YOUR_SERVICE_ID>",
"remote": true
}
]
}
Why this matters: The binding name becomes the environment variable used in Worker code: env.PRIVATE_API.fetch().
❌ Wrong:
// Port is ignored, relative URL fails
const response = await env.VPC_SERVICE.fetch("/api/users:8080");
✅ Correct:
// Absolute URL, port configured in VPC service
const response = await env.VPC_SERVICE.fetch("https://internal-api.company.local/api/users");
Why: The VPC service configuration determines actual routing. The fetch() URL only populates the Host header and SNI value.
| Issue | Root Cause | Solution |
|---|---|---|
dns_error | cloudflared < 2025.7.0 or http2 protocol | Update cloudflared, configure QUIC, allow UDP 7844 |
| Requests go to public internet | Using public hostname in fetch() | Use internal VPC hostname |
| Connection refused | Wrong port in VPC service config | Configure correct http_port/https_port in service |
| Timeout | Tunnel not running or wrong tunnel_id | Verify tunnel status, check tunnel_id |
| 404 errors | Incorrect path routing | Verify internal service path matches fetch() path |
{
"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
}
]
}
Key settings:
binding: Environment variable name for accessing the serviceservice_id: UUID from VPC service creationremote: Must be true for VPC servicesexport default {
async fetch(request, env) {
const response = await env.PRIVATE_API.fetch(
"https://internal-api.company.local/users"
);
return response;
}
};
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: "john@example.com" })
}
);
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 });
}
};
Located in templates/:
wrangler-vpc.jsonc - Ready-to-use wrangler config with VPC bindingsvpc-service-ip.json - IP-based VPC service API payloadvpc-service-hostname.json - Hostname-based VPC service API payloadCopy these templates as starting points for your implementation.
Located in scripts/:
list-vpc-services.sh - List VPC services via Cloudflare APItail-worker.sh - Debug VPC connections with live logsset-api-token.sh - Set secrets for private API authLocated in references/:
api-patterns.md - Comprehensive fetch() patterns and examples| Package | Version | Purpose |
|---|---|---|
| wrangler | latest | Deploy Workers with VPC bindings |
| cloudflared | 2025.7.0+ | Tunnel daemon (on remote infrastructure) |
| Package | Version | Purpose |
|---|---|---|
| @cloudflare/workers-types | latest | TypeScript types for Workers |
Symptoms: Worker returns dns_error when calling env.VPC_SERVICE.fetch()
Solution:
Symptoms: Logs show requests hitting public endpoints instead of internal
Solution:
// Use internal hostname
const response = await env.VPC_SERVICE.fetch(
"https://internal-api.vpc.local/endpoint" // Internal
// NOT "https://api.company.com/endpoint" // Public
);
Symptoms: Requests hang and eventually timeout
Solution:
Before using this skill, verify: