背景

Obsidian 本地粘贴图片后默认存在本地文件夹。本地备份方案使用远程 Git 仓库(稳定的定期备份)、远程同步插件(不稳定的多端同步)等方案。相比于云端存储,本地存储方式存在多个缺陷:

  1. Git 仓库在存储图片等资源时,会导致仓库膨胀过快
  2. 使用多种形式备份时,同一图片被重复存储浪费资源
  3. 远端存储可以通过反向代理定制统一的图片访问链接,后续更换图片位置时无需考虑图片链接变动
  4. 通过插件上传到 Halo 站点时,无法同步上传图片,发布后无法显示图片

该方式的缺点:如果云盘、Nginx 中的某一环节出现问题,则全量图片均无法访问。

最终效果展示

[!undo] 待补充

概要方案

image.png

详细方案

1. 配置图床服务

image.png

image.png

在储存策略中创建新的储存策略

  1. 角色组:选择管理员,避免无上传权限
  2. 储存策略:选择 WebDav 类型
  3. 访问域名:设置为图片上传后期望的访问地址,该地址可自由定制。后续流程中会通过反向代理将该路径作为图片的统一访问地址使用。最终图片地址组成为:访问域名+路径命名规则(角色组控制)+文件命名规则(角色组控制),例如:

    访问域名:https://pic.linkerlau.com/s
    路径命名规则:{y}/{m}
    文件命名规则:{timestamp}

    最终地址:

  4. 连接地址:填写从 NextCloud 中拿到的 WebDav 的地址。对于 NextCloud 网盘,如果地址后不追加斜杠 / 会导致图床上传图片时上传失败,原因不明
  5. 认证方式:选择 Basic
  6. 路径前缀:填写在 NextCloud 中的上传文件夹。例如我的上传目录是在根目录下的 /Photos/BlogPicture 文件夹中,注意开头不要带斜杠 /
  7. 用户名:从 NextCloud 中创建应用密钥,位置为 /个人设置/安全/设备和活动链接。创建新应用后得到用户名与密码
  8. 密码:同上

至此已完成从图床到网盘的上传通道,可以通过图床上传图片进行测试。注意切换上传策略为新创建的策略

2. 配置 NextCloud 共享文件夹

由于 WebDav 的安全机制,直接访问 WebDav 的资源地址需要进行鉴权。我们的目标是无感访问,此处给出的解决方案是使用反向代理将通用访问链接代理到公开共享链接,意即:借助公开共享链接的无授权特性实现无感访问

image.png

从任一位置选择某文件夹作为该业务的根存储目录,并设置权限为 仅查看 的公开共享。拷贝共享链接备用:https://cloudpan.linkerlau.com/s/qjYsGTHJa7jA6G2

3. 借助反向代理实现通用访问链接

从上述步骤我们已具备如下资源:

  1. 通用访问链接:https://pic.linkerlau.com/s/{y}/{m}/{timestamp}.webp
  2. 云盘共享链接:https://cloudpan.linkerlau.com/s/qjYsGTHJa7jA6G2

接下来,将对于通用访问链接的请求反代到云盘共享链接上。由于云盘共享链接的最终位置为共享目录,若要访问该目录下的 /{y}/{m}/{timestamp}.webp 文件,需观察云盘共享链接的文件访问路径的特征。

旧方案

[!Tip]
该方案配置繁琐,非最优方案,可使用下一节的![[#^perf]]

image.png

image.png

此处取任一已上传到共享文件夹的文件作为示例,具体位置见上图:
https://cloudpan.linkerlau.com/s/qjYsGTHJa7jA6G2?dir=undefined&path=%2F25%2F01&openfile=1268。该链接中的 openfile=1268 指代访问的文件 ID,由于通用共享链接未携带该属性(只具备文件目录与文件名),且 NextCloud 未提供可访问该属性的 Api,因此通过该链接无法实现反向代理。

随后发现,通过下载按钮下载图片后再查看下载链接可得:https://cloudpan.linkerlau.com/s/qjYsGTHJa7jA6G2/download?path=%2F25%2F01&files=1735985070.webp&downloadStartSecret=xxx。该链接中的 path 和 files 属性可以从通用访问链接中截获,因此该方案可行。

现在,我们有如下资源:

  1. 通用访问链接:https://pic.linkerlau.com/s/{y}/{m}/{timestamp}.webp
  2. 云盘任一共享文件的链接:https://cloudpan.linkerlau.com/s/qjYsGTHJa7jA6G2/download?path=%2F25%2F01&files=1735985070.webp&downloadStartSecret=xxx

随后,开始配置反向代理。实现思路:通过正则表达式匹配通用访问链接中的目录位置 /{y}/{m} 与文件名 {timestamp}.webp 分别作为 $date 变量与 $file_name 变量,并将该变量作为云盘共享链接的 path 参数与 files 参数。详细转发配置如下所示:

if ($uri ~ "^/s/(\d{2}/\d{2})/(.*)$") {
            set $date $1;
            set $file_name $2;
}
proxy_pass https://127.0.0.1:私密端口/s/qjYsGTHJa7jA6G2/download?path=$date&files=$file_name;

以上配置完成后,便可测试通用访问链接是否可用

优化方案 ^perf

后续在更新文章的时候发现网盘共享文件的链接和先前测试的不一致。排查后发现:

  • 当共享权限包含编辑权限时,链接格式为上述方案所示
  • 当共享权限为仅共享时,链接格式为 https://cloudpan.linkerlau.com/public.php/dav/files/qjYsGTHJa7jA6G2/25/01/1735986949.webp

观察该链接格式,上述方案的实现方式可以去除正则表达式匹配这个操作,直接将 https://pic.linkerlau.com/s 反向代理到 https://cloudpan.linkerlau.com/public.php/dav/files/qjYsGTHJa7jA6G2 即可

4. 配置本地上传插件

Obsidian 本地使用 obsidian-lskypro-upload 插件进行上传。原作者的插件已长久未维护,测试不可用。下面给出的是另一个 fork 仓库的地址,可在 Github 下载后本地安装。

GitHub - woodchen-ink/obsidian-lskypro-upload: 支持直接上传图片到图床Lsky,基于https://github.com/renmu123/obsidian-image-auto-upload-plugin.git改造。

插件配置中的 Token 与 StrategyId 可调用兰空图床的 Api 获取

image.png