9. 基于CloudFlare的图床搭建

一灰灰blog工具ChromeChrome约 3254 字大约 11 分钟

零成本搭建专属图床:CloudFlare ImgBed 开源项目部署与深度体验

在日常的博文记录时,原始图片都是和教程放在一起的,这样的好处是所有的相关信息都很完整,不至于因为外部的存储的各种问题(比如备案、被攻击、价格因素等)导致数据缺失;当然缺点也很明显,在将本地的文章分享到各平台时,还得手动再传一遍图,就有点麻烦

当然经常做分享的小伙伴,大概率都会维护一个自己的图床。最近在github上发现一个基于CloudFlare的个人免费图床搭建的方案,试了一下,门槛很低,效果不错,推荐给有兴趣的小伙伴

效果预览

我的图床部署在CloudFlare,绑定了自己的域名,为了安全起见,上传图添加了密码限制🤣

上传页面如下:

260212-01.webp
260212-01.webp

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

260212-02.webp
260212-02.webp
260212-03.webp
260212-03.webp

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

260212-04.webp
260212-04.webp

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

260212-05.webp
260212-05.webp

从使用者的角度来看,属实是非常方便了

当然从管理员的角度出发,也有很多使用的设置(比如统计、安全设置、存储通道配置、个性化的设置等等)

260212-06.webp
260212-06.webp

快速部署

这个项目的部署成本真不算高,官方文档写的也挺清晰了,比如我是选择的 Cloudflare + Discord 方案

  • CloudFlare:部署项目工程
  • Discord: 作为图床存储渠道,保存上传的内容

前期准备

准备CloudFlare账号,注册免费,如果需要使用 Cloudflare R2 作为存储渠道,那么需要绑定支付方式(注意:需要支持境外支付的信用卡)

Discord账号

注册免费,使用免费

创建 Discord Bot

  • 访问 Discord Developer Portalopen in new window
  • 点击 "New Application" 创建应用
  • 进入 "Bot" 页面,获取你的token(如果没有则点击 Reset Token
  • 复制 Bot Token
  • 点击 OAuth2,在 Scopes 区域勾选 bot
  • 在下面的BotPermissons勾选权限 (不知道选择哪些权限的话,就都选上)
  • 保存最下面的 Generated URL
260212-07.webp
260212-07.webp

获取 Channel ID

  • 进入主页:https://discord.com/open in new window
  • 在 Discord 客户端中启用开发者模式(用户设置 → 高级 → 开发者模式)
  • 添加服务器
  • 在服务器内,创建一个用于存储文件的频道
  • 右键点击频道,选择 "复制频道 ID"
  • 将 Bot 添加到服务器并授予发送文件的权限(这一步就是访问上面获取到的 URL)

配置成功之后,就会发现我们通过图床上传的文件就会在这个频道内展示,如下

260212-08.webp
260212-08.webp

CloudFlare部署

接下来我们就可以直接通过Cloudflare Pages来实现图床的部署。 CF提供免费托管、全球 CDN 加速和无需服务器维护,绝对是部署的首选方式

1. fork项目

fork原始项目到自己的仓库: https://github.com/MarSeventh/CloudFlare-ImgBedopen in new window

2. 创建Pages项目

2.1 访问 Cloudflare Dashboard

  • 登录 Cloudflare Dashboardopen in new window
  • 选择左侧菜单的 "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 部署项目

  1. 点击 "保存并部署"
  2. 等待首次部署完成(约 2-3 分钟)

3. 配置数据库

数据库用于存储文件元数据,是必需的组件,可选数据库为 KV 数据库和 D1 数据库。两者对比如下表所示,根据自己使用场景从其中选择一种配置即可

特点KV 数据库D1 数据库
读写性能较低
免费额度
大文件上传支持不支持

KV 数据库和 D1 数据库只需要配置其中一个即可,不需要同时配置两个!建议根据上表选择适合自己的数据库类型。

接下来以 D1 数据库配置进行说明

创建 D1 数据库

  1. 在 Cloudflare Dashboard 中选择 "存储和数据库"
  2. 点击 "D1 SQL 数据库"
  3. 点击 "创建数据库"
  4. 输入数据库名称:img_d1(建议使用此名称)
  5. 点击 "创建"

初始化 D1 数据库

  1. 创建完成后,点击进入数据库详情页
  2. 选择 "控制台" 选项卡
  3. 在 SQL 输入框中粘贴并执行注释区域以下的内容(见https://github.com/MarSeventh/CloudFlare-ImgBed/blob/main/database/init.sqlopen in new window
  4. 点击 "执行"

绑定 D1 到项目

  1. 返回您的 Pages 项目
  2. 选择 "设置" → "绑定"
  3. 点击 "添加" → "D1 数据库"
  4. 填写绑定信息:
    • 变量名称img_d1(必须是这个名称)
    • D1 数据库:选择刚创建的数据库
  5. 点击 "保存"

4. 重新部署

绑定数据库后需要重新部署以生效:

  1. 进入项目的 "部署" 页面
  2. 找到最新的部署记录
  3. 点击右侧的 "..." 菜单
  4. 选择 "重试部署"
  5. 等待部署完成

配置

到上面这一步,我们的图床服务基本搭建完成,接下来就可以直接进入后台做一些配置

🥘 配置 Discord 渠道

在管理后台的 Discord 渠道配置中填入:

  • 渠道名称:自定义名称
  • Bot Token:Discord Bot Token
  • Channel ID:Discord 频道 ID
  • Is Nitro:是否为 Nitro 用户(Nitro 用户单文件限制为 25MB,普通用户为 10MB)
  • 代理 URL:(可选)自定义代理地址

🔒 安全设置

安全相关设置,在管理后台的 "系统设置" → "安全设置" 中配置

认证管理

  • 用户端认证:用于 Web 端用户登录和 API 认证
  • 管理端认证: 管理员用户名和密码,用于访问管理后台

上传管理

图像审查

审查渠道支持 nsfwjsmoderatecontent.com,可根据如下步骤自行配置。

1.moderatecontent.comopen in new window

  • 访问 ModerateContentopen in new window
  • 注册并获取免费 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链接
logoLinkLogo跳转链接字符串只支持字符串类型,设置为点击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默认转换 WebPboolean支持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 方式进行鉴权,而不是原文中的请求参数携带

如何发现的呢?源码的实现鉴权逻辑如下🤣

260212-09.webp
260212-09.webp

接口上传方式:

  • 端点:/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 支持跨域访问

项目源码:MarSeventh/CloudFlare-ImgBedopen in new window

Loading...