上网冲浪多年,近年来鉴于对网络上各种资源遗失的不安全感越来越深,尤其是打开自己过去的文章,各种链接失效(部分是图床自己的链接url路径的变更),担心各类图床跑路的风险,那么还是靠自己来,于是制作了一套用作图床的工具。
需求
给自己静态博客上博客内容中插图提供静态资源访问,作为个人不知名小博客,数据量小,流量也小,也不用太在意24小时的资源可用性。
架构
上传图片使用django的即开即用的admin管理后台,将所有上传的图片都写入到一个目录下,图片名称采用图片本身的hash值1,为了防止单个文件夹下过多的文件,取hash值前两位作为存储文件夹名。举例:bf1645ab265fa931fe3797ea5b812f2b.jpg
保存的路径是bf/bf1645ab265fa931fe3797ea5b812f2b.jpg
。同时基本的管理上传图片数据的功能由django admin来提供,图片文件的各种信息等都存储在SQLite数据库中,毕竟个人blog后台管理也不需要并发。
图片的静态资源访问并不由django提供,django只提供admin后台用来上传和对单个图片的基本记录和管理功能。也就是说上传图片的部分和提供图片访问的部分是完全分离,单独运行,互不干扰。
静态资源的访问由caddy来提供,同时采用一定的策略来防止盗链。防盗链的策略思路来自一种新的可应对空白 referer 的防盗链策略。
总结起来如下表所示:
Referer\Accept | image开头 | 其他开头 |
---|---|---|
符合要求的 | ✅ | ✅ |
不符合要求的 | ❌ | ❌ |
不带referre请求头 | ❌ | ✅ |
caddy v2 配置文件举例如下:
[host]:[port] {
file_server
root * [path] # 存放静态资源路径
@imghost { # 对访问的url进行重写成实际静态文件的存储路径
path_regexp img ^([a-f0-9]{2})([a-f0-9]+)\.(\w+)$
# 文件名为文件hash值的16进制数值
}
@noRefimgAccept {
header !Referer
header Accept image*
}
@wrongRef {
header Referer *
not header Referer https://[host]/*
}
rewrite @wrongRef /000.png
rewrite @noRefimgAccept /000.png
rewrite @imghost /{re.img.1}/{re.img.1}{re.img.2}.{re.img.3}
}
如果有用其他web服务器的,可以用我写的脚本方便测试防盗链策略是否成功.
这下满足了基本的图床功能。
有了图片上传的渠道,存储的空间,有了静态资源的访问,同时配合ddns来保证通过域名访问静态资源。剩下就是需要考虑的图片资源的备份,万一图片丢失了就全完蛋了。由于是所有图片都是存储在一个文件夹下,所以配合备份的321原则.
热备:自动远程备份到网盘中。
冷备:手动通过网络备份到本地的另一台设备的机械硬盘上。
这样满足了除了原始数据外还有两个备份,热备满足了备份和原始数据保存异地,冷备满足了备份和原始数据不在同一存储介质中。
实际部署
在树莓派上挂载一个移动硬盘(独立供电)存储图片,同时跑一个django app作为上传图片的后台,图片保存在移动硬盘中,通过caddy提供静态资源访问,路由器配置好端口映射,同时对公网IP做ddns来提供域名访问。
缺陷和待改进方向
因为是利用家庭宽带,有端口被封的危险,虽然图片的资源很好转移,但是因为目前图片url的设置,在完成文件转移后重新部署访问的话,需要修改所有的URL,应该是当初设计的时候没有考虑到相关情况,应该给图床图片URL部署一个专用域名方便切换(现在使用的域名有其他用途不太方便修改)同时在用的ddns工具也需要做一定的调整.批量修改blog文章中所有的图片url也还需要写一个脚本文件批量处理.
这个缺点其实和工具没太大关系,是实际部署的时候没有周全考虑,运行后发现修改有一定困难,但是暂不影响运行.
实际缺点是和其他集成度很高的图床工具相比较只能说是半自动化,并不能实现粘贴图片到编辑器中即可完成图片上传同时插入图片链接到编辑器中.好在小站没有大量插图,半自动化操作还可以接受,有需求后再改进吧.
总结
看我这套系统能够用多久吧,我一直用的Jekyll的静态生成blog包括这套主题快十年了.