【教程】用 Cloudflare 免费搭一个私人图床:从部署到上线的完整实战(含避坑)

【教程】用 Cloudflare 免费搭一个私人图床:从部署到上线的完整实战(含避坑)

时间煮雨-Master
2026-09-13 / 0 评论 / 7 阅读 / 正在检测是否收录...
写这篇文章,是因为我自己刚用 Cloudflare 把开源项目 JSimages 跑通上线了。过程中踩了一堆坑,也做了不少定制,干脆整理成一篇「教程 + 成品展示」,供想自建图床的朋友参考。

一、为什么不直接用图床?

写博客、做笔记、发社群,图片托管永远是个绕不开的问题。第三方图床要么限速限容,要么哪天就跑路了;大厂的对象存储又要绑卡、还要操心账单。

Cloudflare 给出的方案很香:

  • Workers:Serverless 跑后端逻辑,免费额度每天 10 万次请求;
  • R2:对象存储,免费 10GB,且 出口流量免费(不像 S3 那样被流量计费);
  • D1:边缘 SQLite,存图片元数据够用。

三者组合,个人图床几乎可以做到「零成本、不绑卡焦虑」。

二、成品先睹为快

我已经上线了一个,地址在这里 👉 https://tc.861409665.xyz/

它目前具备这些能力:

  • 🖼️ 游客可直接上传 / 访问图片(也可关掉登录后使用);
  • 🔐 带管理后台 /admin,登录后可查看、删除图片;
  • 📦 单张上限 10MB,支持常见图片格式;
  • 💡 超出 9GB 存储配额后自动拒绝新上传,不再继续吃额度;
  • 🛑 紧急情况可一行配置 DISABLED=true 全站停用,杜绝误扣费。

页面底部放了我的个人博客和个人主页:

三、技术选型与架构

浏览器 ──► Cloudflare Worker(_worker.js)
                ├── D1(media 表:url + size)
                └── R2(图片二进制存储)

请求进来后,Worker 负责鉴权、写库、读写 R2,并顺手用 caches.default 做一层边缘缓存,加速图片回源。

四、开始部署

1. 准备材料

  • 开源仓库:https://github.com/0-RTT/JSimages (根目录就是 _worker.js,是个 Worker 项目,不是 Pages)
  • Cloudflare 账号,并创建一个 API Token,权限勾选:Workers 脚本:编辑D1:编辑R2:编辑
  • 在 Cloudflare 控制台 开启 R2(首次需要绑卡验证,但免费额度内不扣费)
  • 一个域名(我用的 861409665.xyz,最终绑到子域 tc.861409665.xyz

2. 写 wrangler.toml

JSimages 仓库本身没有 wrangler.toml,需要自己建。核心配置如下:

name = "jsimages"
main = "_worker.js"
compatibility_date = "2024-09-23"

[[d1_databases]]
binding = "DATABASE"
database_name = "jsimages"
database_id = "91dd6235-d95b-4b2a-8423-e2beaf7f64ab"

[[r2_buckets]]
binding = "R2_BUCKET"
bucket_name = "jsimages"

[vars]
DOMAIN = "tc.861409665.xyz"
USERNAME = "admin"
ADMIN_PATH = "admin"
ENABLE_AUTH = "false"
MAX_SIZE_MB = "10"
QUOTA_STORAGE_MB = "9000"
APP_VERSION = "v3"
# PASSWORD 用 secret 存放,不要写进文件
⚠️ 密码类敏感信息请用 wrangler secret put PASSWORD 注入,别明文落在配置文件里。

3. 创建云端资源

# 建 R2 桶
wrangler r2 bucket create jsimages

# 建 D1 数据库
wrangler d1 create jimages

# 建表(注意加了 size 列,用于配额统计)
wrangler d1 execute jsimages --remote --command \
  "CREATE TABLE IF NOT EXISTS media (url TEXT PRIMARY KEY, size INTEGER DEFAULT 0);"

4. 部署

wrangler deploy

部署成功后你会拿到一个 *.workers.dev 默认域名(我的是 https://jsimages.sjzy.workers.dev)。

5. 绑定自定义域名

JSimages 用 [[domains]] 字段的方式在某些 wrangler 版本不被识别,稳妥做法是走 Zone 的 Workers Routes,或直接在 DNS 里加一条:

tc.861409665.xyz  A  192.0.2.1  代理(Proxied)

加上之后,访问子域就会落到这个 Worker。

五、我的定制改动

开源版界面比较素,我按自己的需求改了 _worker.js

  1. 标题JSimages时间煮雨の图床title、描述、关键词、div.title 全改);
  2. 页脚:原本的「开源声明」换成个人博客 / 个人主页链接;
  3. 游客访问ENABLE_AUTH=false,无需登录即可上传;
  4. 免责声明:底部加红色提示,严禁上传违法、色情、暴力、侵权等内容;
  5. 防超额:上传/访问时比对 QUOTA_STORAGE_MB(我设 9000),超了就拒;再加 DISABLED 开关一键全站 403;
  6. 缓存根治:首页缓存键带上 cv=APP_VERSION,每次改版升一版(现在是 v3),旧缓存自然失效。

关键代码片段(缓存键带版本号):

const cacheKey = new Request(
  request.url + (request.url.includes('?') ? '&' : '?') + 'cv=' + config.appVersion,
  request
);

六、踩坑记录(都是真金白银的时间)

现象解决办法
R2 未开启部署后 API 报 10042控制台手动 Enable R2
wrangler 中文路径找不到入口部署报找不到 _worker.js把项目拷到纯 ASCII 路径(如 C:/jsimages_deploy)再 deploy
secret put 顺序限制4.x 报 latest version isn't currently deployed先 deploy,再 secret put,或改为可选跳过
[[domains]] 不识别部署报 Unexpected fields改用 Zone Workers Routes / DNS 记录
DNS 需手动加Token 无 DNS:Edit 权限,403控制台手动加 A 记录并代理
改版不生效刷新/Purge 都没用,还是旧界面caches.default 程序化缓存顶住默认 URL,靠 APP_VERSION 缓存键根治
最阴的一坑是缓存:Cloudflare 的 caches.default 是 Worker 自己写的程序化缓存,和 CDN 的 Purge 不是一回事,后台清缓存清不掉它。改版后必须让缓存键变化,否则用户永远看到旧页面。

七、安全提醒(很重要)

  • 部署用的 API Token 用完建议吊销重建,别长期留着;
  • Cloudflare 账号密码定期更换
  • 敏感配置走 secret,别进版本库;
  • 对外公开上传的图床,务必加免责声明 + 内容审核,避免被滥用。

八、结语

整套下来,一个属于自己的、免费、可控、还能随时停用的图床就跑起来了。源码开放、部署简单,适合想摆脱第三方图床的朋友。

想看效果直接访问:https://tc.861409665.xyz/

如果你也搭了,欢迎在评论区贴出你的地址,一起交流踩坑经验 🚀

Test

本文由 时间煮雨の图床 实战整理。更多内容见个人博客 https://chun7.top/ 与个人主页 https://zy.chun7.top/

0

评论 (0)

取消