前言

折腾博客怎么能少了图床?用免费的第三方图床总担心跑路,自建又要考虑带宽成本。直到我发现了 Cloudflare R2——每月 10GB 免费存储,无流量费用,配合 Workers 还能实现防盗链。

这篇文章记录我搭建 R2 图床的全过程,包括防盗链配置,确保只有自己的网站能用。

为什么选择 Cloudflare R2

优势:

  • 免费额度大方:每月 10GB 存储 + 1000万次读取
  • 零流量费用:不像 AWS S3 那样按流量计费
  • 速度快:Cloudflare 的 CDN 加速
  • 可控性强:通过 Workers 实现各种自定义功能

免费额度:

  • 存储:10 GB/月
  • A 类操作(写入):100 万次/月
  • B 类操作(读取):1000 万次/月

对于个人博客来说,这个额度完全够用了。

准备工作

  • Cloudflare 账号(免费)
  • 一个域名(我用的是 example.com)
  • 域名已托管到 Cloudflare

第一步:创建 R2 存储桶

  1. 登录 Cloudflare Dashboard

  2. 进入 R2 页面

    • 左侧菜单找到 "R2"
    • 如果是第一次使用,点击 "Purchase R2 Plan"(选择免费计划)
  3. 创建存储桶

    • 点击 "Create bucket"
    • Bucket name:blog-images(你的存储桶名称,可自定义)
    • Location:选择 "Automatic"(自动选择最近的位置)
    • 点击 "Create bucket"
  4. 上传测试图片

    • 进入刚创建的存储桶
    • 点击 "Upload",上传一张测试图片(比如 test.jpg

第二步:创建 Worker 处理请求

  1. 进入 Workers & Pages

    • 左侧菜单点击 "Workers & Pages"
    • 点击 "Create application"
    • 选择 "Create Worker"
  2. 命名 Worker

    • 输入名称:r2-image-handler(你的 Worker 名称,可自定义)
    • 点击 "Deploy"
  3. 编辑 Worker 代码

    • 部署后,点击 "Edit code"
    • 删除默认代码,粘贴以下代码:
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const referer = request.headers.get('Referer');
    
    // 允许访问的域名列表
    const allowedDomains = [
      'example.com',
      'www.example.com'
    ];
    
    // 检查 Referer 是否在允许列表中
    let isAllowed = false;
    
    if (referer) {
      // 检查 Referer 是否包含允许的域名
      for (const domain of allowedDomains) {
        if (referer.includes(domain)) {
          isAllowed = true;
          break;
        }
      }
    }
    
    // 如果不允许访问(直接访问或其他网站引用)
    if (!isAllowed) {
      // 返回防盗链提示图
      const warningImage = await env.MY_BUCKET.get('hotlink-warning.jpg');
      
      if (warningImage) {
        const headers = new Headers();
        headers.set('Content-Type', 'image/jpeg'); // 如果是 PNG 改为 image/png
        headers.set('Cache-Control', 'public, max-age=3600'); // 缓存1小时
        headers.set('X-Robots-Tag', 'noindex');
        
        return new Response(warningImage.body, {
          status: 200,
          headers
        });
      }
      
      // 如果提示图不存在,返回文字提示
      return new Response('Hotlinking is not allowed. Please visit https://example.com', { 
        status: 403,
        headers: {
          'Content-Type': 'text/plain',
          'X-Robots-Tag': 'noindex'
        }
      });
    }
    
    // 从 R2 获取文件
    const objectKey = url.pathname.slice(1); // 去掉开头的 /
    
    // 如果路径为空,返回提示
    if (!objectKey) {
      return new Response('R2 Image CDN - Please specify image path', {
        status: 400,
        headers: { 'Content-Type': 'text/plain' }
      });
    }
    
    // 从 R2 获取对象
    const object = await env.MY_BUCKET.get(objectKey);
    
    if (object === null) {
      return new Response('Image Not Found', { 
        status: 404,
        headers: { 'Content-Type': 'text/plain' }
      });
    }
    
    // 设置响应头
    const headers = new Headers();
    object.writeHttpMetadata(headers);
    headers.set('etag', object.httpEtag);
    
    // 设置缓存(缓存一年)
    headers.set('Cache-Control', 'public, max-age=31536000, immutable');
    
    // 设置 CORS(允许跨域)
    headers.set('Access-Control-Allow-Origin', '*');
    
    // 返回图片
    return new Response(object.body, {
      headers
    });
  }
};
  1. 保存并部署

    • 点击右上角 "Save and deploy"

第三步:绑定 R2 存储桶

  1. 进入 Worker 设置

    • 回到 Worker 列表,点击刚创建的 r2-image-handler
    • 点击 "Settings" 标签
  2. 添加 R2 绑定

    • 找到 "Variables and Secrets"
    • 向下滚动找到 "R2 Bucket Bindings"
    • 点击 "Add binding"
    • Variable name:MY_BUCKET(⚠️ 必须和代码中的一致)
    • R2 bucket:选择 blog-images(你的存储桶名称)
    • 点击 "Save"

第四步:配置自定义域名

  1. 添加自定义域名

    • 在 Worker 页面,点击 "Settings"
    • 找到 "Domains & Routes"
    • 点击 "Add" 选择 "Custom Domain"
    • 输入子域名:img.example.com(改成你自己的域名)
    • 点击 "Add Custom Domain"
  2. 等待 DNS 生效

    • Cloudflare 会自动添加 DNS 记录
    • 通常几分钟内就能生效

第五步:测试图床

1. 上传图片到 R2

在 R2 存储桶中上传几张图片,比如:

  • test.jpg
  • avatar.png
  • cover.jpg

2. 测试访问

直接访问:

https://img.example.com/test.jpg

应该能看到图片。

3. 准备防盗链提示图

为了让盗链者看到友好的提示而不是空白,需要准备一张提示图片:

  1. 制作提示图

    • 推荐尺寸:1200x630800x600
    • 格式:JPG 或 PNG
    • 文件大小:控制在 100KB 以内
    • 内容示例:

      🚫 禁止盗链 🚫
      此图片仅供个人博客使用
      请访问:example.com
  2. 上传到 R2

    • 进入 R2 控制台,选择 blog-images 存储桶
    • 上传你的提示图,文件名必须是hotlink-warning.jpg
    • (如果是 PNG 格式,记得修改 Worker 代码中的 Content-Typeimage/png

4. 测试防盗链

在 PowerShell 中测试:

# 测试从你的网站访问(应该显示原图)
curl -I -H "Referer: https://example.com" https://img.example.com/test.jpg

# 测试直接访问(应该显示防盗链提示图)
curl -I https://img.example.com/test.jpg

# 测试从其他网站访问(应该显示防盗链提示图)
curl -I -H "Referer: https://other-site.com" https://img.example.com/test.jpg

测试结果:

  • 从 example.com 访问 → 显示原图 ✅
  • 直接访问 → 显示 hotlink-warning.jpg
  • 从其他网站访问 → 显示 hotlink-warning.jpg

在博客中使用

Markdown 语法

![图片描述](https://img.example.com/your-image.jpg)

HTML 语法

<img src="https://img.example.com/your-image.jpg" alt="图片描述">

Typecho 中使用

直接在编辑器中插入图片时,将链接改为 R2 的地址即可。

配置 PicList 实现自动上传

完成 R2 和 Worker 配置后,最重要的就是配置上传工具。我选择了 PicList(PicGo 的增强版),可以实现截图后自动上传到 R2。

第一步:获取 R2 的 API Token

  1. 进入 Cloudflare R2 页面

  2. 创建 API Token

    • 点击右上角 "Manage R2 API Tokens"
    • 点击 "Create API Token"
    • Token name:piclist-upload(随便起名)
    • Permissions:选择 "Object Read & Write"
    • 如果想限制只能访问特定存储桶,在 "Specify bucket(s)" 中选择 blog-images
    • 点击 "Create API Token"
  3. 保存凭证信息

    创建成功后会显示以下信息,务必保存(只显示一次):

    Access Key ID: xxxxxxxxxxxxxxxxxxxx
    Secret Access Key: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
    Endpoint: https://你的账号ID.r2.cloudflarestorage.com

第二步:下载并安装 PicList

  1. 下载 PicList

  2. 安装 PicList

    • 双击安装包,按提示安装即可

第三步:配置 PicList 的 S3 图床

PicList 原生支持 S3 协议,R2 完全兼容 S3 API,所以可以直接使用 S3 配置。

  1. 打开 PicList

    • 启动后会在系统托盘显示图标
  2. 进入图床设置

    • 右键托盘图标 → "打开详细窗口"
    • 左侧菜单点击 "图床设置"
    • 选择 "Amazon S3"
  3. 填写配置信息

    根据你刚才保存的 API Token 信息填写:

    配置项填写内容说明
    应用密钥 ID你的 Access Key ID就是刚才保存的 Access Key
    应用密钥你的 Secret Access Key就是刚才保存的 Secret Key
    桶名blog-images你的 R2 存储桶名称
    文件路径{year}/{month}/按年月分类存储(可选)
    自定义节点你的账号ID.r2.cloudflarestorage.com⚠️ 去掉 https://
    自定义域名https://img.example.com你的自定义域名
    地区auto自动选择
  4. 设置为默认图床

    • 配置完成后,点击 "确定"
    • 点击 "设为默认图床"

第四步:测试上传

  1. 截图上传测试

    • 按快捷键 Ctrl + Shift + P(默认)
    • 框选截图区域
    • 截图后会自动上传
    • 上传成功后,图片链接会自动复制到剪贴板
  2. 文件上传测试

    • 右键托盘图标 → "打开详细窗口"
    • 点击 "上传区"
    • 将图片拖拽到窗口
    • 或点击 "选择图片" 上传
  3. 验证结果

    • 上传成功后会显示图片链接
    • 访问链接确认图片能正常显示
    • 链接格式应该是:https://img.example.com/2025/10/xxx.png

配置说明

关于文件路径:

{year}/{month}/ 会按照以下格式存储:

blog-images/
  ├── 2025/
  │   ├── 10/
  │   │   ├── image1.png
  │   │   └── image2.jpg
  │   └── 11/
  └── 2026/

你也可以自定义为:

  • {year}-{month}-{day}/ - 按日期分类
  • blog/ - 统一放在 blog 文件夹
  • 留空 - 直接存在根目录

关于自定义域名:

  • ✅ 填写:https://img.example.com - 上传后返回你的自定义域名链接
  • ❌ 不填:上传后返回 R2 原始链接(不推荐)

PicList 常用功能

  1. 快捷键设置

    • 设置 → 快捷键设置
    • 可以自定义截图、上传等快捷键
  2. 上传历史

    • 相册 → 查看所有上传过的图片
    • 可以复制链接、删除图片等
  3. 压缩图片

    • 设置 → PicGo 设置 → 图片压缩
    • 开启后上传前自动压缩,节省空间
  4. 水印功能

    • 插件设置 → 安装水印插件
    • 可以给图片自动加水印

常见问题

Q1: 上传失败,提示 "Network Error"

A: 检查以下几点:

  • Access Key 和 Secret Key 是否正确
  • 自定义节点是否去掉了 https://
  • 桶名是否正确(blog-images
  • 网络是否正常

Q2: 上传成功但返回的链接无法访问

A:

  • 检查 "自定义域名" 是否填写了 https://img.example.com
  • 检查域名是否已经绑定到 Worker
  • 检查 Worker 是否正确绑定了 R2 存储桶

Q3: 图片上传后找不到

A:

  • 去 Cloudflare R2 控制台查看存储桶
  • 根据你设置的 "文件路径" 查找对应目录
  • 比如设置了 {year}/{month}/,就去对应的年月文件夹找

Q4: 可以批量上传吗?

A: 可以!

  • 方法1:在 PicList 上传区,一次选择多张图片
  • 方法2:直接把多张图片拖拽到上传区
  • 方法3:使用 PicList 的相册批量管理功能

Q5: PicList 相册不显示图片怎么办?

A: 这是正常的。S3 协议不支持相册功能,但可以:

  • 查看 PicList 的"上传历史"(本地记录)
  • 去 Cloudflare R2 控制台查看所有文件
  • 上传成功后链接会自动复制,可以保存在文档里

Q6: 防盗链提示图显示不出来?

A: 检查以下几点:

  • 提示图文件名是否为 hotlink-warning.jpg(必须完全一致)
  • 提示图是否已上传到 R2 存储桶根目录
  • 如果用 PNG 格式,代码中的 Content-Type 要改为 image/png

成本分析

个人博客使用完全免费:

  • 存储:10GB 免费额度
  • 读取:1000万次/月免费
  • 流量:完全免费(这是最大优势)

对比其他图床方案:

  • 七牛云:流量费 ¥0.29/GB
  • 又拍云:需要备案 + 流量费
  • 阿里云 OSS:存储费 + 流量费
  • Cloudflare R2:0 元!

关于防盗链的说明

配置完成后的效果:

✅ 从你的网站访问

在 example.com 的博客文章中,图片正常显示:

<img src="https://img.example.com/2025/10/screenshot.png">

→ 显示原图

❌ 直接访问或其他网站盗链

在浏览器地址栏直接打开,或者其他网站引用:

https://img.example.com/2025/10/screenshot.png

→ 显示防盗链提示图 hotlink-warning.jpg

这样做的好处:

  • 🔒 保护你的带宽,防止被薅羊毛
  • 🎯 盗链者看到的是提示图,可以为你的博客引流
  • 💰 节省 R2 的读取次数配额

实际使用体验

配置完成后,我的使用流程变成了:

  1. 写博客需要图片时,按 Ctrl + Shift + P 截图
  2. 图片自动上传到 R2,链接自动复制到剪贴板
  3. 在 Markdown 编辑器中 Ctrl + V 粘贴
  4. 完成!

体验总结:

  • ✅ 速度快:Cloudflare CDN 加速,国内访问也很快
  • ✅ 成本低:完全免费,无需担心流量费用
  • ✅ 操作简单:PicList 配置好后,截图即上传
  • ✅ 防盗链:只有自己网站能用,别人盗链显示提示图

总结

用 Cloudflare R2 搭建图床的优势:

  • 完全免费(个人博客够用)
  • 速度快(Cloudflare CDN)
  • 可控性强(自己掌握数据)
  • 防盗链(保护带宽)
  • 稳定可靠(Cloudflare 的基础设施)

从此告别第三方图床跑路的担忧!


2025.10.21 · 济南
终于有了自己的图床,从此告别第三方跑路的担忧!

P.S. 如果你也在用 R2 + PicList,欢迎评论区交流经验!

最后修改:2025 年 10 月 21 日
如果觉得我的文章对你有用,请随意赞赏