AgentSkillsCN

cloudflare

在 Cloudflare 中为 Clerk、Vercel 和邮件路由配置 DNS 域名。适用于新增域名、配置 DNS 记录,或设置邮件重定向时使用。

SKILL.md
--- frontmatter
name: cloudflare
description: "Setup domains in Cloudflare with DNS for Clerk, Vercel, and email routing. Use when adding new domains, configuring DNS records, or setting up email redirects."
allowed-tools: Read, Glob, Grep, Write, Edit, Bash, WebSearch

Cloudflare Setup

Automate Cloudflare workflows: DNS setup, Clerk integration, Vercel deployment, email routing, and R2 storage.

Prerequisites

Authentication (Choose One)

Option 1: API Token (Recommended)

bash
# Add to .env.local
CLOUDFLARE_API_TOKEN="your-api-token"
CLOUDFLARE_ACCOUNT_ID="your-account-id"

Create token at: https://dash.cloudflare.com/profile/api-tokens Required permissions:

  • Zone:DNS:Edit
  • Zone:Zone:Read
  • Email Routing Addresses:Edit
  • Email Routing Rules:Edit
  • Account:R2:Edit (for R2 storage)

Option 2: Wrangler CLI

bash
# Install wrangler
bun add -g wrangler

# Login (opens browser)
wrangler login

# Verify
wrangler whoami

Other Tools

bash
# Vercel CLI (required)
bun add -g vercel
vercel login

Workflow

When setting up a new domain, follow these steps:

Step 1: Gather Information

Ask the user for:

  1. Domain name (e.g., example.com)
  2. Clerk DNS records (paste from Clerk dashboard)
  3. Vercel project name (e.g., my-app)
  4. Email addresses to create (e.g., contact, support)
  5. Redirect target email (e.g., me@gmail.com)

Step 2: Get Zone ID

bash
# If using API token
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=DOMAIN" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" | jq '.result[0].id'

# If using wrangler
wrangler pages project list  # Shows associated zones

Step 3: Create DNS Records for Clerk

Clerk provides specific DNS records for each project. Common patterns:

bash
# Example: CNAME record
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "clerk",
    "content": "frontend-api.clerk.dev",
    "ttl": 1,
    "proxied": false
  }'

# Example: TXT record for verification
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "TXT",
    "name": "@",
    "content": "clerk-verification=xxxxx",
    "ttl": 1
  }'

Step 4: Add Domain to Vercel

bash
# Add domain to Vercel project
vercel domains add DOMAIN --scope=TEAM_SLUG

# Or link to specific project
vercel domains add DOMAIN PROJECT_NAME

Then create Vercel DNS records:

bash
# A record for root domain
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "A",
    "name": "@",
    "content": "76.76.21.21",
    "ttl": 1,
    "proxied": false
  }'

# CNAME for www subdomain
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "www",
    "content": "cname.vercel-dns.com",
    "ttl": 1,
    "proxied": false
  }'

Step 5: Setup Email Routing

First, enable email routing for the zone (do this in Cloudflare dashboard first time).

Then create routing rules:

bash
# Create destination address (must be verified first)
curl -X POST "https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/email/routing/addresses" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "email": "your-main-email@gmail.com"
  }'

# Create routing rule for contact@domain.com
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/email/routing/rules" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "name": "Forward contact",
    "enabled": true,
    "matchers": [{"type": "literal", "field": "to", "value": "contact@DOMAIN"}],
    "actions": [{"type": "forward", "value": ["your-main-email@gmail.com"]}]
  }'

Required MX records for email routing:

bash
# MX records for Cloudflare Email Routing
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "MX",
    "name": "@",
    "content": "route1.mx.cloudflare.net",
    "priority": 69,
    "ttl": 1
  }'

curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "MX",
    "name": "@",
    "content": "route2.mx.cloudflare.net",
    "priority": 46,
    "ttl": 1
  }'

curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "MX",
    "name": "@",
    "content": "route3.mx.cloudflare.net",
    "priority": 89,
    "ttl": 1
  }'

# TXT record for SPF
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "TXT",
    "name": "@",
    "content": "v=spf1 include:_spf.mx.cloudflare.net ~all",
    "ttl": 1
  }'

Step 6: Verification Checklist

After setup, verify:

bash
# List all DNS records
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result[] | {type, name, content}'

# Check Vercel domain status
vercel domains inspect DOMAIN

# Test email routing (send test email to contact@DOMAIN)

Interactive Prompts Template

When running /cloudflare, ask:

code
What domain are you setting up?
> example.com

Paste the Clerk DNS records from your Clerk dashboard:
> [user pastes records]

What's the Vercel project name?
> my-saas-app

What email addresses should I create? (comma-separated)
> contact, support, hello

What email should these redirect to?
> myemail@gmail.com

Common DNS Record Types

TypeUse CaseProxied
ARoot domain to IPNo (for Vercel)
CNAMESubdomain to hostnameNo (for Clerk/Vercel)
TXTVerification, SPFN/A
MXEmail routingN/A

Troubleshooting

IssueSolution
Zone not foundDomain must be added to Cloudflare first
DNS propagation slowWait 5-10 minutes, check with dig
Email not forwardingVerify destination email first
Vercel 404Check DNS proxied=false for Vercel records
Clerk verification failedEnsure TXT record is on root (@)

Useful Commands

bash
# Check DNS propagation
dig DOMAIN +short
dig DOMAIN MX +short
dig DOMAIN TXT +short

# List zones in account
curl -X GET "https://api.cloudflare.com/client/v4/zones" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result[] | {name, id}'

# Delete a DNS record
curl -X DELETE "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records/RECORD_ID" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"

R2 Storage Setup

Setup R2 buckets for file storage: user uploads, static assets, backups.

R2 Workflow

Step 1: Determine Use Case

Ask the user:

code
What do you want to do with R2?
1. Create new bucket (full setup)
2. Configure existing bucket (CORS, public access)
3. Setup custom domain for bucket

Step 2: Gather Bucket Info

code
Bucket name?
> my-app-uploads

What will this bucket store?
1. User uploads (images, files) - needs CORS + presigned URLs
2. Static assets (public CDN) - needs public access
3. Backups (private) - no public access
> 1

Custom domain? (optional, press enter to skip)
> uploads.myapp.com

Step 3: Create Bucket

bash
# Create bucket via wrangler
wrangler r2 bucket create my-app-uploads

# Or via API
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{account_id}/r2/buckets" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"name": "my-app-uploads", "locationHint": "wnam"}'

Step 4: Configure CORS (for user uploads)

Create cors.json:

json
{
  "corsRules": [
    {
      "allowedOrigins": ["https://myapp.com", "http://localhost:3000"],
      "allowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
      "allowedHeaders": ["*"],
      "exposeHeaders": ["ETag", "Content-Length"],
      "maxAgeSeconds": 3600
    }
  ]
}

Apply CORS:

bash
wrangler r2 bucket cors put my-app-uploads --file=cors.json

Step 5: Setup Public Access (for static assets)

Option A: Enable R2.dev subdomain (via dashboard)

  • Go to R2 > Bucket > Settings > Public access

Option B: Custom domain:

bash
# Add CNAME record
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "uploads",
    "content": "{account_id}.r2.cloudflarestorage.com",
    "ttl": 1,
    "proxied": true
  }'

Then enable custom domain in R2 bucket settings.

Step 6: Generate S3 API Credentials (for SDK access)

  1. Go to R2 > Manage R2 API Tokens
  2. Create token with Object Read & Write
  3. Add to .env.local:
bash
R2_ACCESS_KEY_ID="your-access-key"
R2_SECRET_ACCESS_KEY="your-secret-key"
R2_ENDPOINT="https://{account_id}.r2.cloudflarestorage.com"
R2_BUCKET_NAME="my-app-uploads"

R2 Quick Commands

bash
# List buckets
wrangler r2 bucket list

# Create bucket
wrangler r2 bucket create BUCKET_NAME

# Delete bucket
wrangler r2 bucket delete BUCKET_NAME

# List objects
wrangler r2 object list BUCKET_NAME

# Upload file
wrangler r2 object put BUCKET_NAME/path/file.png --file=./local.png

# View CORS config
wrangler r2 bucket cors get BUCKET_NAME

R2 Use Case Presets

Use CaseCORSPublicCustom Domain
User uploadsYesNoOptional
Static assets/CDNNoYesRecommended
BackupsNoNoNo
Public downloadsNoYesOptional

R2 Troubleshooting

IssueSolution
CORS error in browserAdd domain to allowedOrigins
403 ForbiddenCheck API token has R2:Edit permission
Custom domain not workingEnsure CNAME is proxied (orange cloud)
Upload failsVerify Content-Type header matches file