9. 基于CloudFlare的图床搭建
零成本搭建专属图床:CloudFlare ImgBed 开源项目部署与深度体验
在日常的博文记录时,原始图片都是和教程放在一起的,这样的好处是所有的相关信息都很完整,不至于因为外部的存储的各种问题(比如备案、被攻击、价格因素等)导致数据缺失;当然缺点也很明显,在将本地的文章分享到各平台时,还得手动再传一遍图,就有点麻烦
当然经常做分享的小伙伴,大概率都会维护一个自己的图床。最近在github上发现一个基于CloudFlare的个人免费图床搭建的方案,试了一下,门槛很低,效果不错,推荐给有兴趣的小伙伴
效果预览
我的图床部署在CloudFlare,绑定了自己的域名,为了安全起见,上传图添加了密码限制🤣
上传页面如下:

上传的方式多种,支持拖拽、粘贴、选中文件上传;同时也支持外链批量转存


后台提供了所有的图片管理,如下

每个文件支持点击查看详情

从使用者的角度来看,属实是非常方便了
当然从管理员的角度出发,也有很多使用的设置(比如统计、安全设置、存储通道配置、个性化的设置等等)

快速部署
这个项目的部署成本真不算高,官方文档写的也挺清晰了,比如我是选择的 Cloudflare + Discord 方案
- CloudFlare:部署项目工程
- Discord: 作为图床存储渠道,保存上传的内容
前期准备
准备CloudFlare账号,注册免费,如果需要使用 Cloudflare R2 作为存储渠道,那么需要绑定支付方式(注意:需要支持境外支付的信用卡)
Discord账号
注册免费,使用免费
创建 Discord Bot
- 访问 Discord Developer Portal
- 点击 "New Application" 创建应用
- 进入 "Bot" 页面,获取你的token(如果没有则点击
Reset Token) - 复制 Bot Token
- 点击 OAuth2,在
Scopes区域勾选bot - 在下面的BotPermissons勾选权限 (不知道选择哪些权限的话,就都选上)
- 保存最下面的
Generated URL

获取 Channel ID
- 进入主页:https://discord.com/
- 在 Discord 客户端中启用开发者模式(用户设置 → 高级 → 开发者模式)
- 添加服务器
- 在服务器内,创建一个用于存储文件的频道
- 右键点击频道,选择 "复制频道 ID"
- 将 Bot 添加到服务器并授予发送文件的权限(这一步就是访问上面获取到的 URL)
配置成功之后,就会发现我们通过图床上传的文件就会在这个频道内展示,如下

CloudFlare部署
接下来我们就可以直接通过Cloudflare Pages来实现图床的部署。 CF提供免费托管、全球 CDN 加速和无需服务器维护,绝对是部署的首选方式
1. fork项目
fork原始项目到自己的仓库: https://github.com/MarSeventh/CloudFlare-ImgBed
2. 创建Pages项目
2.1 访问 Cloudflare Dashboard
- 登录 Cloudflare Dashboard
- 选择左侧菜单的 "Compute & AI" -> "Workers & Pages"
- 点击 "创建应用程序"
- 在最下方
Looking to deploy Pages?选择Get started - 在 "导入现有 Git 存储库" 处点击 "开始使用"
2.2 连接 GitHub 仓库
- 如果首次使用,需要授权 Cloudflare 访问 GitHub
- 选择您 Fork 的 CloudFlare-ImgBed 仓库
- 点击 "开始设置"
2.3 配置项目设置
| 配置项 | 值 | 说明 |
|---|---|---|
| 项目名称 | cloudflare-imgbed(或自定义) | 项目标识符 |
| 生产分支 | main | 生产环境分支 |
| 构建命令 | npm install | 重要:v2.0 新构建命令 |
| 构建输出目录 | / | 保持默认 |

2.4 部署项目
- 点击 "保存并部署"
- 等待首次部署完成(约 2-3 分钟)
3. 配置数据库
数据库用于存储文件元数据,是必需的组件,可选数据库为 KV 数据库和 D1 数据库。两者对比如下表所示,根据自己使用场景从其中选择一种配置即可。
| 特点 | KV 数据库 | D1 数据库 |
|---|---|---|
| 读写性能 | 高 | 较低 |
| 免费额度 | 少 | 多 |
| 大文件上传 | 支持 | 不支持 |
KV 数据库和 D1 数据库只需要配置其中一个即可,不需要同时配置两个!建议根据上表选择适合自己的数据库类型。
接下来以 D1 数据库配置进行说明
创建 D1 数据库
- 在 Cloudflare Dashboard 中选择 "存储和数据库"
- 点击 "D1 SQL 数据库"
- 点击 "创建数据库"
- 输入数据库名称:
img_d1(建议使用此名称) - 点击 "创建"
初始化 D1 数据库
- 创建完成后,点击进入数据库详情页
- 选择 "控制台" 选项卡
- 在 SQL 输入框中粘贴并执行注释区域以下的内容(见https://github.com/MarSeventh/CloudFlare-ImgBed/blob/main/database/init.sql)
- 点击 "执行"
绑定 D1 到项目
- 返回您的 Pages 项目
- 选择 "设置" → "绑定"
- 点击 "添加" → "D1 数据库"
- 填写绑定信息:
- 变量名称:
img_d1(必须是这个名称) - D1 数据库:选择刚创建的数据库
- 变量名称:
- 点击 "保存"
4. 重新部署
绑定数据库后需要重新部署以生效:
- 进入项目的 "部署" 页面
- 找到最新的部署记录
- 点击右侧的 "..." 菜单
- 选择 "重试部署"
- 等待部署完成

配置
到上面这一步,我们的图床服务基本搭建完成,接下来就可以直接进入后台做一些配置
🥘 配置 Discord 渠道
在管理后台的 Discord 渠道配置中填入:
- 渠道名称:自定义名称
- Bot Token:Discord Bot Token
- Channel ID:Discord 频道 ID
- Is Nitro:是否为 Nitro 用户(Nitro 用户单文件限制为 25MB,普通用户为 10MB)
- 代理 URL:(可选)自定义代理地址
🔒 安全设置
安全相关设置,在管理后台的 "系统设置" → "安全设置" 中配置
认证管理
- 用户端认证:用于 Web 端用户登录和 API 认证
- 管理端认证: 管理员用户名和密码,用于访问管理后台
上传管理
图像审查
审查渠道支持 nsfwjs 和 moderatecontent.com,可根据如下步骤自行配置。
- 访问 ModerateContent
- 注册并获取免费 API Key(目前已不再支持免费注册)
- 在管理后台 "系统设置" → "安全设置" 中填入 API Key
2.nsfwjs
- 使用 Docker 部署
nsfwjs审查服务
# 参考命令
docker run -d -p 127.0.0.1:5000:5000/tcp \
--env PORT=5000 \
--restart=always \
eugencepoi/nsfw_api:latest
- 在管理后台 "系统设置" → "安全设置" 中填入审查服务地址,如
https://nsfwjs.your.domain
访问管理
- 域名过滤
- 放行域名:允许访问的域名列表(留空放行所有域名,否则需要手动添加图床自身域名)
- 白名单模式:启用后仅允许加入白名单的文件被访问
🌐 网页设置
前端网页相关设置,在管理后台的 "系统设置" → "网页设置" 中配置
| 字段名 | 用途 | 类型 | 内容规范 |
|---|---|---|---|
| siteTitle | 网站标题 | 字符串 | 只支持字符串类型,设置为你自定义的网站标题 |
| siteIcon | 网站图标 | 字符串 | 只支持字符串类型,设置为你自定义的网站图标链接 |
| ownerName | 图床名称 | 字符串 | 只支持字符串类型,设置为你自定义的图床名称(默认为Sanyue) |
| logoUrl | 图床Logo | 字符串 | 只支持字符串类型,设置为你自定义的图床Logo链接 |
| logoLink | Logo跳转链接 | 字符串 | 只支持字符串类型,设置为点击Logo时跳转的链接,留空则使用默认GitHub链接。仅对上传页面生效 |
| bkInterval | 背景切换间隔 | 正整数 | 设置为背景图的轮播时间,默认3000,单位ms。例如你希望10s切换一次,设置为 10000即可。 |
| bkOpacity | 背景图透明度 | (0,1]的浮点数 | 展示的背景图透明度,默认为1。如果你觉得显示效果不佳,可以自定义,如 0.8 |
| urlPrefix | 默认 URL 前缀 | 字符串 | 只支持字符串类型,设置为自定义的全局默认链接前缀,该前缀会覆盖原始默认前缀,但不会覆盖用户自定义的链接前缀 |
| announcement | 公告 | 字符串 | 只支持字符串类型,可以为 HTML 格式,设置为你自定义的公告内容(如有) |
| defaultUploadChannel | 默认上传渠道 | 字符串 | 只支持字符串类型,设置为你自定义的默认上传渠道,支持telegram(Telegram 渠道)、cfr2(Cloudflare R2)、s3(S3 渠道)、discord(Discord 渠道)和huggingface(HuggingFace 渠道) |
| defaultChannelName | 默认渠道名称 | 字符串 | 只支持字符串类型,指定默认使用的渠道名称,需先选择上传渠道。当同一渠道类型配置了多个渠道时,可通过此项指定默认使用哪个渠道 |
| defaultUploadNameType | 默认命名方式 | 字符串 | 只支持字符串类型,设置为你自定义的默认上传文件命名方式,支持default(默认)、index(仅前缀)、original(仅原名)和short(短链接) |
| loginBkImg | 登录页背景图 | 列表/字符串 | 1、当字段类型为列表时,列表中元素为需要添加到轮播列表中的图片链接(列表中只有一张图时即为固定背景),形如["1.jpg","2.jpg"]2、当字段类型为 字符串时,目前仅支持字符串值为bing,设置为该值时启用bing随机图片轮播模式。 |
| uploadBkImg | 上传页背景图 | 列表/字符串 | 同loginBkImg |
| footerLink | 页脚传送门链接 | 字符串 | 只支持字符串类型,设置为你自定义的传送地址(如个人博客链接) |
| disableFooter | 隐藏页脚 | boolean | 支持boolean类型,设为true时禁用页脚,默认false |
| defaultConvertToWebp | 默认转换 WebP | boolean | 支持boolean类型,设为true时默认开启 WebP 转换,默认false |
| defaultCustomerCompress | 默认开启压缩 | boolean | 支持boolean类型,设为true时默认开启客户端压缩,默认true |
| defaultCompressBar | 默认压缩阈值 | 数字 | 图片大小超过此值将自动压缩,单位 MB,范围 1-20,默认5 |
| defaultCompressQuality | 默认期望大小 | 数字 | 压缩后图片大小期望值,单位 MB,范围 0.5-压缩阈值,默认4 |
| adminLoginBkImg | 管理页登录背景图 | 列表/字符串 | 同loginBkImg |
| adminBkImg | 管理页背景图 | 列表/字符串 | 同loginBkImg |
上传API
除了通过网页的控制台进行图片上传之外,还提供了API的上传方式,这样服务器开发的小伙伴,也是可以使用的,但是需要注意的是官方的文档有个bug,authCode是放在请求头中,通过 HTTP 的 Authorization 方式进行鉴权,而不是原文中的请求参数携带
如何发现的呢?源码的实现鉴权逻辑如下🤣

接口上传方式:
- 端点:/upload
- 方法:POST
- 认证:使用上传认证码或
API Token(需要upload权限) - 内容类型:multipart/form-data
- 文件大小限制:根据存储渠道而定
请求示例
curl --location --request POST 'https://your.domain/upload' \
--header 'Authorization: Bearer 你的token' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--form 'file=@"D:\\杂文件\\壁纸\\genshin109.jpg"'
Java请求示例
/**
* 上传文件
*
* @param bytes 文件字节数组
* @param fileType 文件类型(如: jpg, png)
* @return 上传后的文件URL
*/
public static String upload(byte[] bytes, String fileType) {
try {
RestClient restClient = RestClient.builder()
.baseUrl(HOST)
.build();
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
// 创建 ByteArrayResource
body.add("file", new ByteArrayResource(bytes) {
@Override
public String getFilename() {
return MD5.create().digestHex(bytes) + "." + fileType;
}
});
String ans = restClient.post()
.uri("/upload")
.header("Authorization", "Bearer " + AUTH_CODE)
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(body)
.retrieve()
.body(String.class);
List<ImgBedRes> list = JsonUtil.toList(ans, ImgBedRes.class);
return HOST + list.get(0).src;
} catch (Exception e) {
log.error("文件上传异常", e);
throw new RuntimeException("文件上传异常: " + e.getMessage());
}
}
public record ImgBedRes(String src) {
}
除了上面的API方式之外,这个项目还提供了 WebDAV 并支持了 PicGo图床工具的搭配使用,有兴趣的小伙伴可以自行尝试
WebDAV 支持
- 标准协议:支持 WebDAV 标准方法(PROPFIND, GET, PUT, DELETE 等)
- 目录浏览:支持通过 WebDAV 客户端浏览和管理文件
- 文件操作:支持上传、下载、删除文件和目录
第三方集成
- PicGo 支持:完美兼容 PicGo 图床工具
- 跨域支持:API 支持跨域访问