博客写到现在,最磨人的小事之一永远是把图片塞到哪。早期丢进 Git 仓库,仓库越来越胖,clone 一次要等半天;后来丢对象存储,又要绑卡、又要盯着流量账单。直到我把目光投向 Cloudflare——它家的全球网络本来就是干 CDN 的,顺手再白嫖一个图床,不香吗。
不过先说清楚,本文说的「零成本」有前提:Cloudflare 免费额度 + EdgeOne 免费版,在免费额度内零成本;超出免费额度,两边都会按量计费。
这篇文章记录我用 CloudFlare-ImgBed(更准确地说是一个带相册功能的 fork:Sanyue ImgHub)搭建图床的全过程,以及后面又叠了一层 EdgeOne 加速的玩法。
它到底是什么
CloudFlare-ImgBed 是一套跑在 Cloudflare 上的开源图床程序,核心依赖有四样:
- Cloudflare Pages:托管前端管理界面
- Cloudflare Workers:处理上传、鉴权、回源逻辑
- R2 对象存储:实际存图片二进制的地方(我用的是桶
img-r2) - Workers KV:存图床配置和图片元数据索引(我用的是命名空间
img_url;即使主存储是 R2,KV 仍然是必绑项)
也就是说,它不需要你有一台服务器,也不收流量费——只要有一个 Cloudflare 账号,图片就天然享受 Cloudflare 的全球边缘节点。
我选它的理由很朴素:免费、全球加速、数据自己掌控。比起把图片交给某些图床 SaaS,至少域名和整条链路都攥在自己手里。
⚠️ 关于「免费」,先泼盆冷水
我这套架构里 KV 和 R2 各负责一块,免费额度都是真的,但不是无限免费:
- R2 桶
img-r2:存图片二进制本身。
- 免费额度 10 GB / 月(存储 + 一定读写操作配额)
- 超出按 $0.015 / GB·月 计费
- egress 免费(这才是 Cloudflare 一统图床的关键卖点——访客看图不计流量费)
- KV 命名空间
img_url:存图床配置 + 图片元数据(文件名、大小、日期等索引),不存图片本体。
- 单值上限 25 MiB;账户总容量 1 GB(Free 计划)
- 超出按 $0.50 / GB·月 计费
个人博客图量稳定在几百 MB 以内的话,整套都在 Cloudflare 免费额度内,真正的零成本。如果哪天图片攒到 GB 级,重点盯 R2 账单——KV 这边元数据占用几乎可以忽略。
部署大概长这样
- Fork 仓库,在 Cloudflare Pages 里关联 Git 仓库部署前端。这一步有两个字段必须手动填上,Cloudflare 默认值跟项目不一致,漏掉就是空白页:
- 构建命令:
npm install - 构建输出:
frontend-dist - 生产分支、构建系统版本等其他字段保持默认即可。
- 构建命令:
- 建一个 Worker 跑后端逻辑,两个资源都要绑:
- R2 桶
img-r2(变量名img_r2)—— 实际存图片二进制 - KV 命名空间
img_url(变量名img_url)—— 存图床配置和元数据 - 项目里的「变量名」就是 Worker 代码里
env.img_r2/env.img_url的来源,命名写错图片就存不进去;
- R2 桶
- 进图床后台(
pic.yuyt.top/admin)设好管理员 token、存储后端类型选 R2(其它如 Telegram 可不选);这些配置会写进 KVimg_url里持久化,不需要在 Pages 环境变量里再设一份。 - 绑一个自定义域,比如我的
pic.yuyt.top。
各 fork 的细节略有差异,但主干流程都差不多。真正容易卡住人的不是部署本身,而是后面怎么和你现有的博客架构接起来——这部分才是我踩坑的主战场。
我的真实架构:Cloudflare + EdgeOne 夹层
我的博客主站在国内,如果图片直接走 pic.yuyt.top(Cloudflare 域名),国内访客偶尔会抽到慢节点。于是我在前面又叠了一层腾讯云 EdgeOne 做加速:
访客浏览器
│ https://pic.yuyt.cn/file/动漫/云海彩虹与满月.png
▼
EdgeOne(加速域 pic.yuyt.cn,节点缓存 30 天)
│ 回源
▼
Cloudflare(pic.yuyt.top,ImgBed 实际运行处)
│
├─► R2 桶 img-r2:实际存图片二进制(250 MB+ 在用)
└─► KV img_url:存图床配置 + 图片元数据(约 458 KB / 454 keys)
这样做的好处:
- 国内访客打到 EdgeOne 的就近节点,回源一次后被 30 天强制缓存,后续几乎零回源;
- 源站
pic.yuyt.top是独立的.top域,和博客主域yuyt.cn不在同一 TLD,DNS 完全不冲突,省去灰云绕行的麻烦; - 真正存图片的只有 Cloudflare R2 桶
img-r2一侧,EdgeOne 只是个聪明的缓存代理。
两个坑,记下来省得你踩
坑一:链接里的 /file/ 前缀
ImgBed 内部实际路径是带 /file/ 的,比如:
https://pic.yuyt.top/file/动漫/云海彩虹与满月.png
但它的后台「自定义链接」前缀如果只填 https://pic.yuyt.cn/(没带 /file/),复制出来的链接就会少一层,贴到博客里直接 404。
正确做法:把自定义链接前缀设成 https://pic.yuyt.cn/file/,让后台复制出的直链自带 /file/。这一个小设置,能救回你一半的裂图。
坑二:别在 EdgeOne 上开 Referer 防盗链
我一度想给图床加防盗链,挡掉外站盗用。结果一开,RSS 阅读器抓取文章里的图片时,因为请求不带博客域的 Referer,全被 403——订阅者看到的文章全是裂图。
对个人博客来说,防盗链的收益远小于它搞砸 RSS、社交分享预览的代价。最后我选择直接关掉,图床该谁看谁看。如果你也接了 RSS,这条建议请直接抄走。
日常怎么用
上传就在 ImgBed 后台拖拽,复制 Markdown 直链往文章里贴即可。
唯一要注意的是同名替换:当你替换了同一张图(URL 不变、内容变了),得去 EdgeOne 控制台「缓存刷新」刷一下那条 URL,否则 30 天缓存会一直吐旧图。除此之外,基本是「传完就忘」的状态。
图床到今天已经稳稳跑了一阵子。零服务器成本、全球加速、数据自己掌控——对一个写博客的人来说,这套组合基本挑不出毛病。