使用 Cloudflare R2 搭建免费个人图床

1. 背景

大善人 Cloudflare 为所有用户提供了 10GB 的免费 R2 对象储存服务,这对于静态个人博客等小型网站来说是极大的利好

优点:

  • 不再需要服务器操心自建图床
  • 不再需要考虑复杂的网络攻击防护或者 HTTPS 证书配置
  • 只需要使用 CF 免费的 R2 对象储存配合 PicList,就可以快速搭建起简单可用的个人图床
  • 图床访问使用 Cloudflare CDN,自带全球加速

下面详细介绍一下逐步搭建流程

2. 搭建流程

2.1. 创建 R2 储存桶

  1. 首先激活账号中的 Cloudflare R2 对象储存,图中已经给出了免费额度,这对于个人用户的小网站来说绰绰有余

    R2储存每月免费使用额度

  2. 创建储存桶,设置桶名字,地区选亚太地区以确保访问速度

创建储存桶

  1. 创建完桶后,回到主界面点击 “Manage”,进入 Cloudflare R2 API Key 管理页面,创建一个 API Key,权限设置为 管理员读和写

    点击Manage进入API Key管理页面

创建新API Key

  1. 记下生成的 API Key 的 S3 访问密钥 ID(AccessKeyID)和机密访问密钥(SecretAccessKey)

记下划红线的两个密钥

也不要忘了记下外面的 R2 对象储存的 S3 API 地址

记下划红线的S3 API地址

  1. 回到储存桶管理页面,随便上传一张测试图片 test.png,以供后面测试使用

上传测试图片

2.2. 配置防盗刷 + 防盗链

R2 对象储存的个人免费额度是有限的,为了防止 DDoS / CC 等恶意消耗流量的攻击,有必要使用 Cloudflare Workers 反代 R2 对象储存,而不是直接将 R2 储存地址对外公开。

Cloudflare Workers 同样是每天免费 10W 请求额度,对于个人网站来说完全足够。下面是部署方法:

  1. 你应该有一个域名托管在 Cloudflare。在此域名的 DNS 页面添加一个子域用于访问图床,例如 image.example.com

  2. 在 Cloudflare 主菜单找到 “Workers 和 Pages”,进入

  3. 右上角点击 “创建应用程序”,创建一个新的 Cloudflare Worker,将如下脚本上传为 worker.js,并部署

    export default {
      async fetch(request, env) {
        // 从环境变量读取防盗链配置
        const ALLOWED_DOMAINS = (env.ALLOWED_DOMAINS_STR || "")
          .split(',')
          .map(domain => domain.trim())
          .filter(domain => domain);
    
        // 1. 验证请求来源
        // 当 ALLOWED_DOMAINS 不为空时,执行防盗链检查
        if (ALLOWED_DOMAINS.length > 0) {
          const origin = request.headers.get("Origin") || "";
          const referer = request.headers.get("Referer") || "";
          const isAllowed = ALLOWED_DOMAINS.some(domain =>
            origin.startsWith(domain) || referer.startsWith(domain)
          );
          if (!isAllowed) {
            return new Response("Forbidden: 防盗链已启用", {
              status: 403,
              headers: { "Access-Control-Allow-Origin": "*" }
            });
          }
        }
    
        // 2. 只允许 GET / HEAD
        if (!["GET", "HEAD"].includes(request.method)) {
          return new Response("Method Not Allowed", { status: 405 });
        }
    
        // 3. 解析请求对象路径
        const url = new URL(request.url);
        const objectKey = decodeURIComponent(url.pathname.slice(1));
        if (!objectKey || objectKey.length > 1024) {
          return new Response("Bad Request", { status: 400 });
        }
    
        // 4. 从 R2 读取文件
        const object = await env.R2_BUCKET.get(objectKey);
        if (!object) {
          return new Response("Not Found", { status: 404 });
        }
    
        // 5. 构造响应头
        const headers = new Headers();
        object.writeHttpMetadata(headers);
        headers.set("etag", object.httpEtag);
        headers.set("Cache-Control", "public, max-age=31536000, immutable");
        headers.set("Access-Control-Allow-Origin", origin || ALLOWED_DOMAINS[0]);
    
        // 6. 处理条件请求(If-None-Match)
        const ifNoneMatch = request.headers.get("If-None-Match");
        if (ifNoneMatch && ifNoneMatch === object.httpEtag) {
          return new Response(null, { status: 304, headers });
        }
    
        // 7. 返回文件流
        return new Response(object.body, { headers });
      }
    };
    

    (脚本参考自 Linux.DO 论坛 @leonkuku 大佬)

    注意这里用到了两个环境变量:

    • R2_BUCKET 用于关联所使用的 Cloudflare R2 储存桶
    • ALLOWED_DOMAINS_STR 用于防盗链,可选是否启用。启用防盗链之后,只有发自指定域名的请求才能成功访问图床
  4. 在 Worker 的绑定页面,为 R2_BUCKET 变量绑定使用的 R2 储存桶

为worker绑定R2储存桶

  1. 在 Worker 的设置页面

    • 添加自定义域,设置为你刚刚选取的访问图床使用的域名。例如:image.example.com
    • 如果需要使用防盗链,则继续添加环境变量,为 ALLOWED_DOMAINS_STR 变量配置允许访问图床的域名列表,域名之间用逗号隔开。例如:https://blog.example.com,https://image.example.com
  2. 回到 Worker 的部署页面点击 “部署”,部署最新版本的 worker.js

  3. 测试效果:用浏览器访问 https://image.example.com/test.png (改成你自己的图床域名),只要能看到图片,就代表配置成功

    • 如果开启了防盗链,需要用终端执行如下命令进行测试:(链接都需要改成你自己的图床域名)

      curl -I -H "Referer: https://image.example.com" "https://image.example.com/test.png"

2.3. 配置 PicList 图片上传

下面,开始配置 Piclist 图床客户端,以方便地向 Cloudflare R2 储存上传图片

  1. 安装 PicList 客户端(项目地址:https://github.com/Kuingsmile/PicList
  2. 配置图床:切换到图床设置页面,选择 AWS S3,各配置项按实际情况填写:
    • 配置名:自己起一个名字
    • AccessKeyId:填之前记录的 S3 访问密钥 ID(AccessKeyID)
    • SecretAccessKey:填之前记录的 机密访问密钥(SecretAccessKey)
    • Bucket:填你创建储存桶时设置的储存桶名字
    • 上传路径:按你的需要进行设置,没有特殊需求的话保持默认即可
    • Region:填 auto
    • 自定义节点:填之前记录的 S3 API 地址
    • 自定义域名:填你之前设置的访问图床的域名,例如 https://image.example.com
    • 其他设置保持默认即可
  3. 保存图床设置,将本配置设置为默认图床
  4. 回到图片上传页面,有需要的话可以设置一下右上角的图片处理设置

按需配置图片预处理

  1. 在上传页面上传一张图片。上传完毕后,PicList 会自动将图片的外链 URL 复制到你的剪贴板
  2. 大功告成!

2.4. 为图床配置缓存(可选)

Cloudflare R2 每月有 1000W 免费读取次数。如果你不放心,可以再增加一层缓存,既可以减少回源读取次数,又能加速访问速度。不过缓存可能导致图片修改以后更新不及时,有这方面需求的可以不启用此功能。

具体方法:

  1. 在 Cloudflare 的域名管理页面菜单中找到 “缓存”,进入 Cache Rule,点击创建规则
  2. 如下设置缓存配置
    • 将 URL 匹配的值改成你自己的图床域名,比如 https://image.example.com/*
    • 将启用边缘 TTL 设置,选择指定 TTL,时间选择 1 天。这个时间是 Cloudflare 缓存图片的时间,可按你的需求自行调整

Cloudflare缓存配置

  1. 配置完成后点击右下角部署,稍等一会后缓存就将生效
  2. 启用缓存后,每当图床的某张图片被访问,Cloudflare 会把它放入全球 CDN 缓存 24 小时,24 小时以内对这张图片的任意访问都将直接从缓存读取。这样大大降低了 Workers 和 R2 储存的读取请求开销,也提高了响应速度

3. 图床使用

配置完成后,图床使用方法如下:

  1. 打开 PicList,点击 “上传” 按钮选择要上传的图片文件,或者点击 “剪贴板图片” 按钮上传剪贴板中的图片
  2. 稍等片刻
  3. 上传完毕,PicList 自动将图片外链复制到剪贴板

随处使用你的外链吧~

4. More…

如果以后随着网站规模增长,R2 对象储存的免费额度不够使用了,可以继续使用收费额度(R2 收费并不贵),或者迁移到其他 S3 兼容的对象储存平台,乃至在自己的服务器上自建 S3,不管怎么样都是相当方便的。

5. Reference


使用 Cloudflare R2 搭建免费个人图床
https://blog.openyq.top/posts/58768/
作者
yqs112358
许可协议