cloudflare

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cloudflare Setup

Cloudflare 配置指南

Automate Cloudflare workflows: DNS setup, Clerk integration, Vercel deployment, email routing, and R2 storage.
自动化Cloudflare工作流:DNS配置、Clerk集成、Vercel部署、邮件路由及R2存储设置。

Prerequisites

前置条件

Authentication (Choose One)

身份验证(二选一)

Option 1: API Token (Recommended)
bash
undefined
选项1:API Token(推荐)
bash
undefined

Add to .env.local

添加到 .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
CLOUDFLARE_API_TOKEN="your-api-token" CLOUDFLARE_ACCOUNT_ID="your-account-id"

在以下地址创建Token:https://dash.cloudflare.com/profile/api-tokens
所需权限:
- Zone:DNS:Edit
- Zone:Zone:Read
- Email Routing Addresses:Edit
- Email Routing Rules:Edit
- Account:R2:Edit(用于R2存储)

**选项2:Wrangler CLI**
```bash

Install wrangler

安装 wrangler

bun add -g wrangler
bun add -g wrangler

Login (opens browser)

登录(打开浏览器)

wrangler login
wrangler login

Verify

验证登录状态

wrangler whoami
undefined
wrangler whoami
undefined

Other Tools

其他工具

bash
undefined
bash
undefined

Vercel CLI (required)

Vercel CLI(必需)

bun add -g vercel vercel login
undefined
bun add -g vercel vercel login
undefined

Workflow

操作流程

When setting up a new domain, follow these steps:
设置新域名时,请遵循以下步骤:

Step 1: Gather Information

步骤1:收集信息

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
    )
向用户确认以下内容:
  1. 域名(例如:
    example.com
  2. Clerk DNS记录(从Clerk控制台复制)
  3. Vercel项目名称(例如:
    my-app
  4. 要创建的邮箱地址(例如:
    contact
    ,
    support
  5. 重定向目标邮箱(例如:
    me@gmail.com

Step 2: Get Zone ID

步骤2:获取Zone ID

bash
undefined
bash
undefined

If using API token

使用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'
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时

wrangler pages project list # Shows associated zones
undefined
wrangler pages project list # 显示关联的Zone
undefined

Step 3: Create DNS Records for Clerk

步骤3:为Clerk创建DNS记录

Clerk provides specific DNS records for each project. Common patterns:
bash
undefined
Clerk会为每个项目提供专属DNS记录,常见示例:
bash
undefined

Example: CNAME record

示例:CNAME记录

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 }'
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

示例:用于验证的TXT记录

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 }'
undefined
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 }'
undefined

Step 4: Add Domain to Vercel

步骤4:将域名添加到Vercel

bash
undefined
bash
undefined

Add domain to Vercel project

向Vercel项目添加域名

vercel domains add DOMAIN --scope=TEAM_SLUG
vercel domains add DOMAIN --scope=TEAM_SLUG

Or link to specific project

或关联到指定项目

vercel domains add DOMAIN PROJECT_NAME

Then create Vercel DNS records:

```bash
vercel domains add DOMAIN PROJECT_NAME

然后创建Vercel DNS记录:

```bash

A record for root domain

根域名的A记录

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 }'
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

www子域名的CNAME记录

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 }'
undefined
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 }'
undefined

Step 5: Setup Email Routing

步骤5:配置邮件路由

First, enable email routing for the zone (do this in Cloudflare dashboard first time).
Then create routing rules:
bash
undefined
首先,为Zone启用邮件路由(首次需在Cloudflare控制台操作)。
然后创建路由规则:
bash
undefined

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" }'
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

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
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"]}] }'

邮件路由所需的MX记录:
```bash

MX records for Cloudflare Email Routing

Cloudflare邮件路由的MX记录

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 }'
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

SPF的TXT记录

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 }'
undefined
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 }'
undefined

Step 6: Verification Checklist

步骤6:验证清单

After setup, verify:
bash
undefined
配置完成后,进行验证:
bash
undefined

List all DNS records

列出所有DNS记录

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}'
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域名状态

vercel domains inspect DOMAIN
vercel domains inspect DOMAIN

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

测试邮件路由(发送测试邮件到contact@DOMAIN)

undefined
undefined

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
运行
/cloudflare
时,询问:
你要配置哪个域名?
> example.com

请粘贴Clerk控制台中的Clerk DNS记录:
> [用户粘贴记录]

Vercel项目名称是什么?
> my-saas-app

需要创建哪些邮箱地址?(逗号分隔)
> contact, support, hello

这些邮箱要重定向到哪个邮箱?
> myemail@gmail.com

Common DNS Record Types

常见DNS记录类型

TypeUse CaseProxied
ARoot domain to IPNo (for Vercel)
CNAMESubdomain to hostnameNo (for Clerk/Vercel)
TXTVerification, SPFN/A
MXEmail routingN/A
类型使用场景是否开启代理
A根域名指向IP否(Vercel场景)
CNAME子域名指向主机名否(Clerk/Vercel场景)
TXT验证、SPFN/A
MX邮件路由N/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 (@)
问题解决方案
找不到Zone需先将域名添加到Cloudflare
DNS生效缓慢等待5-10分钟,使用
dig
工具检查
邮件无法转发先验证目标邮箱
Vercel返回404确认Vercel相关DNS记录未开启代理(proxied=false)
Clerk验证失败确保TXT记录添加在根域名(@)上

Useful Commands

实用命令

bash
undefined
bash
undefined

Check DNS propagation

检查DNS生效情况

dig DOMAIN +short dig DOMAIN MX +short dig DOMAIN TXT +short
dig DOMAIN +short dig DOMAIN MX +short dig DOMAIN TXT +short

List zones in account

列出账户中的Zone

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

Delete a DNS record

删除DNS记录

curl -X DELETE "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records/RECORD_ID"
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"

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

R2存储配置

Setup R2 buckets for file storage: user uploads, static assets, backups.
设置R2存储桶用于文件存储:用户上传、静态资源、备份。

R2 Workflow

R2操作流程

Step 1: Determine Use Case

步骤1:确定使用场景

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
询问用户:
你需要对R2执行什么操作?
1. 创建新存储桶(完整配置)
2. 配置现有存储桶(CORS、公共访问)
3. 为存储桶配置自定义域名

Step 2: Gather Bucket Info

步骤2:收集存储桶信息

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
存储桶名称?
> my-app-uploads

该存储桶用于存储什么内容?
1. 用户上传(图片、文件)- 需要CORS + 预签名URL
2. 静态资源(公共CDN)- 需要公共访问权限
3. 备份(私有)- 无公共访问权限
> 1

自定义域名?(可选,直接回车跳过)
> uploads.myapp.com

Step 3: Create Bucket

步骤3:创建存储桶

bash
undefined
bash
undefined

Create bucket via wrangler

通过wrangler创建存储桶

wrangler r2 bucket create my-app-uploads
wrangler r2 bucket create my-app-uploads

Or via API

或通过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"}'
undefined
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"}'
undefined

Step 4: Configure CORS (for user uploads)

步骤4:配置CORS(适用于用户上传场景)

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
创建
cors.json
json
{
  "corsRules": [
    {
      "allowedOrigins": ["https://myapp.com", "http://localhost:3000"],
      "allowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
      "allowedHeaders": ["*"],
      "exposeHeaders": ["ETag", "Content-Length"],
      "maxAgeSeconds": 3600
    }
  ]
}
应用CORS配置:
bash
wrangler r2 bucket cors put my-app-uploads --file=cors.json

Step 5: Setup Public Access (for static assets)

步骤5:配置公共访问(适用于静态资源场景)

Option A: Enable R2.dev subdomain (via dashboard)
  • Go to R2 > Bucket > Settings > Public access
Option B: Custom domain:
bash
undefined
选项A:启用R2.dev子域名(通过控制台)
  • 进入R2 > 存储桶 > 设置 > 公共访问
选项B:自定义域名:
bash
undefined

Add CNAME record

添加CNAME记录

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.
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 }'

然后在R2存储桶设置中启用自定义域名。

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

步骤6:生成S3 API凭证(用于SDK访问)

  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"
  1. 进入R2 > 管理R2 API令牌
  2. 创建具备Object读写权限的令牌
  3. 添加到
    .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

R2快速命令

bash
undefined
bash
undefined

List buckets

列出存储桶

wrangler r2 bucket list
wrangler r2 bucket list

Create bucket

创建存储桶

wrangler r2 bucket create BUCKET_NAME
wrangler r2 bucket create BUCKET_NAME

Delete bucket

删除存储桶

wrangler r2 bucket delete BUCKET_NAME
wrangler r2 bucket delete BUCKET_NAME

List objects

列出存储桶中的对象

wrangler r2 object list BUCKET_NAME
wrangler r2 object list BUCKET_NAME

Upload file

上传文件

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

View CORS config

查看CORS配置

wrangler r2 bucket cors get BUCKET_NAME
undefined
wrangler r2 bucket cors get BUCKET_NAME
undefined

R2 Use Case Presets

R2场景预设

Use CaseCORSPublicCustom Domain
User uploadsYesNoOptional
Static assets/CDNNoYesRecommended
BackupsNoNoNo
Public downloadsNoYesOptional
使用场景CORS公共访问自定义域名
用户上传可选
静态资源/CDN推荐
备份
公共下载可选

R2 Troubleshooting

R2故障排除

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
问题解决方案
浏览器中出现CORS错误将域名添加到allowedOrigins列表
403禁止访问检查API令牌是否具备R2:Edit权限
自定义域名无法工作确保CNAME记录已开启代理(橙色云标识)
上传失败验证Content-Type头与文件类型匹配