🎯

cloudflare

🎯Skill

from andrehfp/tinyplate

VibeIndex|
What it does

Automates Cloudflare domain configuration by setting up DNS records, integrating Clerk, configuring Vercel, and managing email routing.

πŸ“¦

Part of

andrehfp/tinyplate(8 items)

cloudflare

Installation

git cloneClone repository
git clone git@github.com:andrehfp/tinyplate.git
πŸ“– Extracted from docs: andrehfp/tinyplate
5Installs
-
AddedFeb 4, 2026

Skill Details

SKILL.md

"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."

Overview

# 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:

```

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

```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:

```

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

```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 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 |