使用R2作为图床

-
-
2024-08-25

自建图床总是崩溃?探索一种全新的图床方式。

我用过兰空图床,太庞大且架构比较古老。因为更新之后爆炸了,数据库表结构一直有问题被迫放弃。

从这之后我愈发觉得,把我的所有数据抽离出来,单独维护是很重要的。

然后我去用了picsur,比较轻量,也比较现代,基本功能都有,但数据方面还是不满意,而且没有中文。

我现在觉得更好方式是把存储和元数据解耦,把图片放在云上,然后把图片的元信息包括标题、文件名、外链等信息单独放在数据库里

这样数据和图片可以分离,不会一起爆炸丢失数据。

架构

主要是三个部分,图片、数据和关联的方法

图片

图片我想放在 R2 比较理想,毕竟CF是赛博活菩萨,有现成的API,上传后可以直接拿到外链,甚至可以直接通过cf优化访问速度

R2免费空间有10G,看着不大,但我把图片统一转为webp格式上传,一般webp图片的大小在50~100kb, 也就是说10G可以放十万到二十万个图片,我觉得给我的Trilium笔记/博客用是足够了。不够用后续也只要$0.015 / GB-month,就是大概 ¥0.1/GB/mo ,其实并不贵(对比良心云和套路云

数据库

我觉得把图片的元数据剥离对数据安全性有很大的提升。数据库可以放服务器,也可以用云平台的Paas, 比图床这种单体应用更加健硕。

方法

就是包括上传图片、维护数据库、查询外链等方法,我用Django来做了一个Web应用,我管祂叫POTO ,已经在github开源。

其实可以直接用Picgo, 但我更喜欢用BS架构,因为网页在哪都能用。另外Picgo也要安装插件才能用S3

用Django其实是因为它和数据库交换方便,而且可以轻易的更换数据库。(我也是最近才了解Django这个框架,正好练练手

把图片和数据解耦也可以更方便的在两个视图(文件和数据)进行操作。

过程

存储

查阅CourFlar R2文档,R2可以通过两种方式使用

  • Workers : 可以直接操作文件,上传、下载、修改、设置访问全新等等
  • S3 API :部分兼容AWS的API, 因为这个API通用性很强,多数云存储工具都支持。

我选择使用S3 API,

  • 一是通用性更强,(写完接口才发现是S3, 这样这个poto工具也可以在和很多平台使用,比如Alist, 可以关联到百度网盘、OneDrive等几十种云介质)
  • 二是写Workers比较麻烦,使用Workers还可能遇到网络问题

数据库

通用的关系型数据库我选择了MariaDB,因为这是Arch linux默认用的,尽量把这些数据放在服务器的系统数据库里集中管理,也好备份。

表结构:

  • id 主键 维护数据和图片关系的键,选这个键是作为文件名,因为上传到R2不会重名,R2 API重名会覆盖文件,这是一个棘手的问题,重名需要很多逻辑去处理,包括查询有无同名文件,上传的错误捕获等。文件不重名就省事了。也考虑过用hash或时间戳,但是这些也有几率重名的,比较麻烦
  • title 后面想做查找图片的功能,title可以标记文件主要信息,方便以后复用。
  • upload_at 上传时间
  • url : 外链,其实可以用外链的域和id拼接,但考虑到以后可能会拓展到不同的云存储,外链可能不同,就新建了一个字段

在数据库方面,用Django的好处就体现出来了,可以灵活的切换数据库,通过model绑定键值信息,我原来不是很喜欢Python, 尤其是写Web应用,但。。真香

方法

  • 上传页面,处理元信息,转换为Webp上传R2, 最后写入数据库。
  • 获取外链,直接查询数据库,拿到外链,在页面渲染图片,展示外链。
  • Todo:批量上传
  • Todo:格式转换
  • Todo:查询图片,通过搜索title找到图床有的图片。
  • Todo:多用户,复用Django的用户管理,把图床开放给其他用户。
  • Todo:维护工具,获取文件列表比对数据库,修改图片和数据等

poto怎么用?

  • 克隆我的仓库

    $ git clone https://github.com/tsaitang404/poto
    $ cd poto
  • 配置虚拟环境

    $ python -m venv django
    $ source django/bin/activate
  • 安装依赖

    $ pip install -r requirements.txt
  • 构造表结构

    $ python manage.py makemigrations
    $ python manage.py migrate
  • 创建管理员用户

    $ python manage.py createsuperuser
    ## 按照指引新建管理员用户
  • 运行poto

    $ python manage.py runserver 0.0.0.0:8000

一些其他的生产部署的设置,参见Django发布到生产, 还有我的笔记版

  • 设置反向代理

    ## nginx配置模板
    server {
            listen 80;
            server_name your.domain;
            return 301 https://$server_name$request_uri; # 重定向到https
    
    
    }
    
    server {
            listen 443 ssl;
            server_name your.domain;
    
            ssl_certificate /path/to/cert.pem;  # 指定 SSL 证书
            ssl_certificate_key /path/to/key.pem;  # 指定 SSL 密钥         
            client_max_body_size 200M; # 指定body最大长度, 决定可上传图片的最大大小
    
    
            location / {
                    proxy_pass http://127.0.0.1:8000;  # 将请求转发到 Django 服务器
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $scheme;
            }
            location /static/ {
                    alias /path/to/staticfiles/; # 静态文件位置,注意文件权限是否能被nginx用户读取,否则会403错误
            }
    }
    
  • 作为服务运行

    ## 修改potp.service的WorkingDirectory和ExecStart的路径
    # ln poto.service  /etc/systemd/system/poto.service 
    # systemctl restart poto nginx

结果咋样?

  • 部署完成后进入your.domain/admin
  • 用管理员登录
  • 进入Configuration设置
  • 右上角 Add configuration
  • 填写以下字段:
    • endpoint:R2的终结点,形如https://<account-id>.r2.cloudflarestorage.com ,也可以是其他s3终结点
    • access_id :S3 API的访问ID
    • secret_access_key:S3 API的Token 可以在R2页面右侧→ 管理 R2 API 令牌页面生成
    • bucket : 储存桶名字
    • access_url: 外链地址 可以进入储存桶在设置中设置连接你的子域或使用r2.dev 子域,设置允许公开访问,或者设置CORS 策略限制访问。
    • password :访问密码

进入上传页面your.domain/upload ,登录,选择、粘贴、拖拽图片,填写title,上传。

直接获取外链 eg. 我的头像 点击链接复制外链

然后去要用的地方粘贴即可! 

 

后来我发现Alist也更新了S3 接口,可以用poto工具上传Alist的各种介质,真不错。

但我还是选择了R2,因为作为外链太方便了!

 

 

“您的支持是我持续分享的动力”

微信收款码
微信
支付宝收款码
支付宝

目录