Cloudflare R2

把 Cloudflare R2 配成 01MVP 图片资产仓库

Cloudflare R2 适合做 01MVP 的公共图片资产仓库:它兼容 S3 API,模板现有的 @01mvp/storage 不需要额外适配;公开访问用自定义域名,写文档时可以直接插入稳定的图片 URL。

推荐第一阶段这样落地:

Cloudflare R2
+ assets.01mvp.com
+ VS Code 粘贴上传
+ R2 Web 管理后台
+ 上传前本地压缩

这里暂不接入 Cloudflare Image Transformations。图片压缩先放在上传前处理,后续确实需要响应式尺寸、格式自动转换或站点性能优化时再单独开启。

推荐结构

Bucket

01mvp-public-assets

用于公开图片、文章截图、封面图和公开下载文件。以后如果要放会员资料、未发布素材或课程源文件,再单独创建 01mvp-private-assets,不要把私有内容放进公开 bucket。

自定义域名

https://assets.01mvp.com

正式文章和文档里只使用这个域名,不长期使用 r2.devr2.dev 适合测试;生产访问使用自定义域名,后续才能配合 Cloudflare Cache、WAF、访问控制等能力。

目录约定

images/01mvp/2026/05/demo.png
images/articles/codex-game-dev/cover.png
images/screenshots/2026/05/dashboard.png
files/downloads/01mvp-template.zip

文章中最终插入:

![demo](https://assets.01mvp.com/images/01mvp/2026/05/demo.png)

使用条件

  • Cloudflare 账号已经能启用 R2。R2 有免费额度,但它是用量计费产品,正式使用前需要确认账号 Billing/付款方式状态。
  • 01mvp.com 在可配置的 Cloudflare zone 中。R2 自定义域名需要把域名添加到同一个 Cloudflare 账号,或者按 Cloudflare 的 partial/CNAME setup 接入。
  • R2 API Token 只给目标 bucket 的读写权限,不使用全账号管理员 Token。
  • 公开 bucket 只放可公开访问的文件。私有资料以后放独立 bucket,并通过后端或签名 URL 访问。
  • 面向中国大陆稳定分发、OTA、App 安装包下载时,不要只依赖 R2;把国内回源作为扩展方案单独设计。

创建 R2 bucket

Cloudflare Dashboard > R2 Object Storage 创建:

01mvp-public-assets

存储类型先选 Standard。第一阶段图片、截图、文档附件都放这里。

绑定自定义域名

进入 bucket 的 Settings > Custom Domains,添加:

assets.01mvp.com

等待状态变为 Active 后,上传一个测试文件并访问:

https://assets.01mvp.com/images/01mvp/test.png

不要把生产文章图片指向 pub-xxxxx.r2.dev

创建 R2 API Token

进入 R2 > Manage R2 API Tokens,创建 S3-compatible credentials。权限建议只覆盖 01mvp-public-assets,用于上传、删除和读取对象。

不要把已有的高权限 CLOUDFLARE_API_TOKEN 直接给 VS Code 插件或 R2 Web 使用。R2 S3 凭证应单独创建 bucket 级 Object Read & Write token。Cloudflare API token 如果没有创建 User API Token 的权限,就只能在 Dashboard 里手动创建这组 S3 credentials。

最小权限 R2 API Token

这组凭证只用于 R2 Web、VS Code 图片上传插件和项目上传接口。权限只给 01mvp-public-assets 的对象读写,不给全账号权限。

  1. 进入 Cloudflare Dashboard
  2. R2 -> Manage R2 API Tokens -> Create API token
  3. 权限选择 Object Read & Write
  4. 限定范围只选 01mvp-public-assets 这个桶(不要选全部桶)
  5. 把生成的 Access Key ID / Secret Access Key 填到 R2 Web、VS Code 插件和项目环境变量

填写项目环境变量

R2 的原生 S3 API endpoint 和给读者访问的公开域名是两件事:

变量示例用途
S3_ENDPOINThttps://<ACCOUNT_ID>.r2.cloudflarestorage.com服务端连接 R2 S3 API,执行上传、删除和签名 URL 生成
NEXT_PUBLIC_S3_ENDPOINThttps://assets.01mvp.com前端和文档用来拼接公开图片、附件和下载链接

S3_ENDPOINT 不需要写成 NEXT_PUBLIC_。真正必须保密的是 S3_ACCESS_KEY_IDS3_SECRET_ACCESS_KEY;它们只能放在服务端环境变量、受保护的管理工具或本机上传插件里。

S3_ENDPOINT=https://<ACCOUNT_ID>.r2.cloudflarestorage.com
S3_REGION=auto
S3_ACCESS_KEY_ID=你的R2AccessKeyId
S3_SECRET_ACCESS_KEY=你的R2SecretAccessKey
S3_BUCKET=01mvp-public-assets
NEXT_PUBLIC_S3_ENDPOINT=https://assets.01mvp.com

配置 CORS

如果要使用浏览器直传、R2 Web 或管理页上传,需要给 bucket 配 CORS。使用 Wrangler 4 设置时,JSON 文件必须包含 rules 数组:

{
  "rules": [
    {
      "allowed": {
        "origins": [
          "http://localhost:7001",
          "https://01mvp.com",
          "https://www.01mvp.com",
          "https://r2.01mvp.com"
        ],
        "methods": ["GET", "POST", "PUT", "DELETE", "HEAD"],
        "headers": [
          "authorization",
          "content-type",
          "x-amz-content-sha256",
          "x-amz-date",
          "x-amz-copy-source",
          "x-amz-metadata-directive"
        ]
      },
      "exposeHeaders": ["ETag"],
      "maxAgeSeconds": 86400
    }
  ]
}

然后执行:

wrangler r2 bucket cors set 01mvp-public-assets --file r2-cors.json --force

如果临时使用 R2 Web 官方在线站点,也要把它的域名加入 AllowedOrigins;私有部署后只保留自己的 r2.01mvp.com

验证上传和访问

上传一个测试文件到:

images/01mvp/test.png

确认公开访问正常:

curl -I https://assets.01mvp.com/images/01mvp/test.png

命令行落地参考

如果本地已经配置 CLOUDFLARE_ACCOUNT_IDCLOUDFLARE_API_TOKEN,可以用 Wrangler 完成大部分配置:

wrangler whoami
wrangler r2 bucket create 01mvp-public-assets
wrangler r2 bucket domain add 01mvp-public-assets \
  --domain assets.01mvp.com \
  --zone-id <ZONE_ID> \
  --min-tls 1.2 \
  --force
wrangler r2 bucket cors set 01mvp-public-assets --file r2-cors.json --force

验证公开访问:

wrangler r2 object put 01mvp-public-assets/images/01mvp/test.png \
  --file ./test.png \
  --content-type image/png \
  --cache-control "public, max-age=31536000, immutable" \
  --remote \
  --force

curl -I https://assets.01mvp.com/images/01mvp/test.png

返回 HTTP/2 200 就说明 R2 bucket、自定义域名和公开访问链路都正常。

自动创建 R2 S3 凭证

如果要用脚本自动创建 S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY,当前 CLOUDFLARE_API_TOKEN 需要用户级 API Token 管理权限。Cloudflare Dashboard 里的路径是:

My Profile
→ API Tokens
→ 编辑当前 token
→ User
→ API Tokens
→ Edit

创建出来的 R2 S3 凭证规则:

  • S3_ACCESS_KEY_ID 使用新建 API token 的 id
  • S3_SECRET_ACCESS_KEY 使用新建 API token 的 value 做 SHA-256 后的 64 位 hex 字符串
  • token policy 只给 01mvp-public-assets bucket 的 Workers R2 Storage Bucket Item ReadWorkers R2 Storage Bucket Item Write

写入本地环境变量后应得到:

S3_ENDPOINT=https://<ACCOUNT_ID>.r2.cloudflarestorage.com
S3_REGION=auto
S3_BUCKET=01mvp-public-assets
NEXT_PUBLIC_S3_ENDPOINT=https://assets.01mvp.com

验证方式是用这组 S3 credentials 真实写入一个测试对象,再访问公开 URL:

curl -I https://assets.01mvp.com/images/01mvp/s3-credential-test.txt

返回 HTTP/2 200 表示 S3 credentials、bucket 权限和公开域名都已经正常。

VS Code 粘贴上传

VS Code 插件只负责把本地图片上传到 R2,并把公开 URL 插入 Markdown/MDX。完整使用教程见 Paste and Upload。插件字段名会有差异,但核心配置保持一致:

endpoint: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
region: auto
bucket: 01mvp-public-assets
accessKeyId: R2 Access Key ID
secretAccessKey: R2 Secret Access Key
publicUrlBase: https://assets.01mvp.com
pathTemplate: images/01mvp/{YYYY}/{MM}/{uuid}.{ext}

如果使用 Paste and Upload,可以按下面填写:

插件字段推荐填写
S3: Endpointhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com
S3: Regionauto
S3: Bucket01mvp-public-assets
S3: Access Key IDR2 S3 credentials 的 Access Key ID
S3: Secret Access KeyR2 S3 credentials 的 Secret Access Key
S3: Prefiximages/01mvp/2026/05/
S3: Public Url Basehttps://assets.01mvp.com/images/01mvp/2026/05/
Undo Limit10

S3: PrefixS3: Public Url Base 要保持同一段路径。比如 Prefix 写 images/01mvp/2026/05/,Public Url Base 也要包含 /images/01mvp/2026/05/,否则上传位置和文章里的图片地址会对不上。

Workspace: PathWorkspace: Link Base 是本地保存模式使用的字段;使用 R2/S3 上传时不用填,除非你明确想把图片同时保存到仓库里。

推荐上传路径:

images/01mvp/2026/05/<hash>.png

这样文章迁移、缓存规则和批量管理都更清楚。

R2 Web 管理后台

日常管理推荐用 vikiboss/r2-web。它是纯前端 R2 文件管理器,支持中文、拖拽上传、粘贴上传、图片本地压缩、文件预览、复制直链、复制 Markdown/HTML 链接。

推荐部署为:

https://r2.01mvp.com

落地方式:

  1. 部署 vikiboss/r2-websrc 目录到 Cloudflare Pages、Vercel 或 Netlify。
  2. r2.01mvp.com 绑定到这个静态站。
  3. 在 R2 CORS 中允许 https://r2.01mvp.com
  4. 用 Cloudflare Access 限制只有自己的邮箱能打开后台。
  5. 在 R2 Web 中填写 01mvp-public-assets 的最小权限凭证。

Cloudflare Pages 的命令行部署示例:

git clone https://github.com/vikiboss/r2-web.git
cd r2-web
wrangler pages project create 01mvp-r2-web --production-branch main
wrangler pages deploy src \
  --project-name=01mvp-r2-web \
  --branch=main \
  --commit-message "Deploy R2 Web"

部署后把 r2.01mvp.com 作为 Pages custom domain。未登录访问时,如果 curl -I https://r2.01mvp.com/ 返回 302 到 *.cloudflareaccess.com,说明 Cloudflare Access 已经保护住后台。

R2 Web 的凭证保存在浏览器本地。不要把配置分享链接或二维码发到公共渠道;API Token 也不要给全账号权限。

国内访问扩展

assets.01mvp.com 适合 01MVP 文档、博客、教程和海外读者图片。它不应该被写成中国大陆稳定分发的唯一方案。

如果要做 OTA、App 安装包、课程大文件或中国大陆用户高稳定访问,建议增加一条独立链路:

assets-cn.01mvp.com
→ 阿里云 OSS / 腾讯云 COS
→ 国内 CDN

文档图片先走 R2;下载分发和大文件按访问区域拆分,后面再做同步脚本或发布流程。

图片压缩策略

第一阶段不接入 Cloudflare Image Transformations。

优先使用:

  • 截图前控制尺寸
  • VS Code 插件上传前压缩
  • R2 Web 的本地图片压缩
  • 必要时用 sharp 在服务端上传前处理

后续如果需要按设备尺寸输出 WebP/AVIF,再单独设计图片优化层。

常见问题

相关资源