cloudflare
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)
# 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
# Install wrangler
bun add -g wrangler
# Login (opens browser)
wrangler login
# Verify
wrangler whoami
Other Tools
# 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:
- Domain name (e.g.,
example.com) - Clerk DNS records (paste from Clerk dashboard)
- Vercel project name (e.g.,
my-app) - Email addresses to create (e.g.,
contact,support) - Redirect target email (e.g.,
me@gmail.com)
Step 2: Get Zone ID
# 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:
# 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
# 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:
# 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:
# 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:
# 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:
# 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:
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
| Type | Use Case | Proxied |
|---|---|---|
| A | Root domain to IP | No (for Vercel) |
| CNAME | Subdomain to hostname | No (for Clerk/Vercel) |
| TXT | Verification, SPF | N/A |
| MX | Email routing | N/A |
Troubleshooting
| Issue | Solution |
|---|---|
| Zone not found | Domain must be added to Cloudflare first |
| DNS propagation slow | Wait 5-10 minutes, check with dig |
| Email not forwarding | Verify destination email first |
| Vercel 404 | Check DNS proxied=false for Vercel records |
| Clerk verification failed | Ensure TXT record is on root (@) |
Useful Commands
# 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:
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
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
# 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:
{
"corsRules": [
{
"allowedOrigins": ["https://myapp.com", "http://localhost:3000"],
"allowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"allowedHeaders": ["*"],
"exposeHeaders": ["ETag", "Content-Length"],
"maxAgeSeconds": 3600
}
]
}
Apply CORS:
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:
# 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)
- Go to R2 > Manage R2 API Tokens
- Create token with Object Read & Write
- Add to
.env.local:
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
# 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 Case | CORS | Public | Custom Domain |
|---|---|---|---|
| User uploads | Yes | No | Optional |
| Static assets/CDN | No | Yes | Recommended |
| Backups | No | No | No |
| Public downloads | No | Yes | Optional |
R2 Troubleshooting
| Issue | Solution |
|---|---|
| CORS error in browser | Add domain to allowedOrigins |
| 403 Forbidden | Check API token has R2:Edit permission |
| Custom domain not working | Ensure CNAME is proxied (orange cloud) |
| Upload fails | Verify Content-Type header matches file |
More from andrehfp/tinyplate
abacatepay
Help with AbacatePay payment integration in Next.js projects. Use when implementing PIX payments, managing subscriptions, handling webhooks, or debugging payment flows. Covers SDK usage, webhook verification, and billing management for Brazilian SaaS applications.
42marketing-copy
Generate compelling marketing copy using the Elevated Direct Response framework. Use this skill when creating landing pages, headlines, email campaigns, ad copy, CTAs, value propositions, or any persuasive marketing content. Applies contrarian educator tone and direct response principles.
37seo-technical
Implement technical SEO infrastructure for Next.js apps. Use this skill when setting up sitemaps, robots.txt, meta tags, OpenGraph, structured data (JSON-LD), canonical URLs, and other technical SEO elements. Covers Next.js 15/16 App Router patterns and 2025 best practices.
37posthog
Implement PostHog analytics, feature flags, and session replay for Next.js apps. Use this skill for event tracking, user identification, A/B testing, experiments, and session recording setup. Also handles analytics reporting (funnel analysis, retention, SEO) with Google Search Console integration.
27ux-design
Design intuitive user experiences following Jobs-era Apple principles. Use this skill when designing onboarding flows, empty states, dashboards, user journeys, CTAs, forms, or any UI that needs to anticipate user needs and reduce friction. Applies progressive disclosure, anticipatory design, and conversion optimization principles.
18stripe
Help with Stripe payment integration in Next.js projects. Use when implementing checkout flows, subscriptions, webhooks, customer portal, or debugging payment issues. Covers Stripe SDK usage, webhook verification, and subscription management.
13