cloudflare
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloudflare 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
undefinedAdd 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**
```bashCLOUDFLARE_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**
```bashInstall wrangler
安装 wrangler
bun add -g wrangler
bun add -g wrangler
Login (opens browser)
登录(打开浏览器)
wrangler login
wrangler login
Verify
验证登录状态
wrangler whoami
undefinedwrangler whoami
undefinedOther Tools
其他工具
bash
undefinedbash
undefinedVercel CLI (required)
Vercel CLI(必需)
bun add -g vercel
vercel login
undefinedbun add -g vercel
vercel login
undefinedWorkflow
操作流程
When setting up a new domain, follow these steps:
设置新域名时,请遵循以下步骤:
Step 1: Gather Information
步骤1:收集信息
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
向用户确认以下内容:
- 域名(例如:)
example.com - Clerk DNS记录(从Clerk控制台复制)
- Vercel项目名称(例如:)
my-app - 要创建的邮箱地址(例如:,
contact)support - 重定向目标邮箱(例如:)
me@gmail.com
Step 2: Get Zone ID
步骤2:获取Zone ID
bash
undefinedbash
undefinedIf 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'
-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'
-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
undefinedwrangler pages project list # 显示关联的Zone
undefinedStep 3: Create DNS Records for Clerk
步骤3:为Clerk创建DNS记录
Clerk provides specific DNS records for each project. Common patterns:
bash
undefinedClerk会为每个项目提供专属DNS记录,常见示例:
bash
undefinedExample: 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 }'
-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 }'
-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 }'
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
-H "Content-Type: application/json"
--data '{ "type": "TXT", "name": "@", "content": "clerk-verification=xxxxx", "ttl": 1 }'
undefinedcurl -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 }'
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
-H "Content-Type: application/json"
--data '{ "type": "TXT", "name": "@", "content": "clerk-verification=xxxxx", "ttl": 1 }'
undefinedStep 4: Add Domain to Vercel
步骤4:将域名添加到Vercel
bash
undefinedbash
undefinedAdd 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:
```bashvercel domains add DOMAIN PROJECT_NAME
然后创建Vercel DNS记录:
```bashA 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 }'
-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 }'
-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 }'
-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 }'
undefinedcurl -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 }'
-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 }'
undefinedStep 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
undefinedCreate 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" }'
-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" }'
-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"]}] }'
-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:
```bashcurl -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"]}] }'
-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记录:
```bashMX 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 }'
-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 }'
-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 }'
-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 }'
-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 }'
-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 }'
-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 }'
-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 }'
undefinedcurl -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 }'
-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 }'
undefinedStep 6: Verification Checklist
步骤6:验证清单
After setup, verify:
bash
undefined配置完成后,进行验证:
bash
undefinedList 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}'
-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}'
-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)
undefinedundefinedInteractive Prompts Template
交互式提示模板
When running , ask:
/cloudflareWhat 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.comCommon DNS Record Types
常见DNS记录类型
| 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 |
| 类型 | 使用场景 | 是否开启代理 |
|---|---|---|
| A | 根域名指向IP | 否(Vercel场景) |
| CNAME | 子域名指向主机名 | 否(Clerk/Vercel场景) |
| TXT | 验证、SPF | N/A |
| MX | 邮件路由 | N/A |
Troubleshooting
故障排除
| Issue | Solution |
|---|---|
| Zone not found | Domain must be added to Cloudflare first |
| DNS propagation slow | Wait 5-10 minutes, check with |
| 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 (@) |
| 问题 | 解决方案 |
|---|---|
| 找不到Zone | 需先将域名添加到Cloudflare |
| DNS生效缓慢 | 等待5-10分钟,使用 |
| 邮件无法转发 | 先验证目标邮箱 |
| Vercel返回404 | 确认Vercel相关DNS记录未开启代理(proxied=false) |
| Clerk验证失败 | 确保TXT记录添加在根域名(@)上 |
Useful Commands
实用命令
bash
undefinedbash
undefinedCheck 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}'
-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}'
-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"
-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"
-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.comStep 3: Create Bucket
步骤3:创建存储桶
bash
undefinedbash
undefinedCreate 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"}'
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
-H "Content-Type: application/json"
--data '{"name": "my-app-uploads", "locationHint": "wnam"}'
undefinedcurl -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"}'
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
-H "Content-Type: application/json"
--data '{"name": "my-app-uploads", "locationHint": "wnam"}'
undefinedStep 4: Configure CORS (for user uploads)
步骤4:配置CORS(适用于用户上传场景)
Create :
cors.jsonjson
{
"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.jsonjson
{
"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.jsonStep 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
undefinedAdd 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 }'
-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 }'
-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访问)
- Go to R2 > Manage R2 API Tokens
- Create token with Object Read & Write
- 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 > 管理R2 API令牌
- 创建具备Object读写权限的令牌
- 添加到:
.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
undefinedbash
undefinedList 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
undefinedwrangler r2 bucket cors get BUCKET_NAME
undefinedR2 Use Case Presets
R2场景预设
| 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 |
| 使用场景 | CORS | 公共访问 | 自定义域名 |
|---|---|---|---|
| 用户上传 | 是 | 否 | 可选 |
| 静态资源/CDN | 否 | 是 | 推荐 |
| 备份 | 否 | 否 | 否 |
| 公共下载 | 否 | 是 | 可选 |
R2 Troubleshooting
R2故障排除
| 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 |
| 问题 | 解决方案 |
|---|---|
| 浏览器中出现CORS错误 | 将域名添加到allowedOrigins列表 |
| 403禁止访问 | 检查API令牌是否具备R2:Edit权限 |
| 自定义域名无法工作 | 确保CNAME记录已开启代理(橙色云标识) |
| 上传失败 | 验证Content-Type头与文件类型匹配 |