udarent33 downloadsUpload attachments to your own S3-compatible storage and keep a local cache, so images still render with no network.
English · 简体中文 —— 中文版在本文下方
中文摘要 —— 把笔记附件上传到你自己的 S3 兼容存储,本地留一份可丢弃的缓存副本:断网、存储停机也能看。 需要 Obsidian 1.13.0+;界面跟随系统语言;完整中文说明见下方「中文版」。
Upload your attachments to your own S3-compatible storage — Cloudflare R2, AWS S3, MinIO, Backblaze B2 or any other S3 endpoint — and keep a local copy that does the rendering. Paste a file and it uploads; the note keeps a portable, shareable link while the copy stays behind, so files render with zero remote requests.
Install · Releases · Report a problem · Requires Obsidian 1.13.0+ (why)

Recorded from the plugin running in Obsidian: paste an image, a PDF and an audio clip → each one uploads → the note keeps a link while a copy of each stays in the vault's cache folder. The last step stops the storage to show that all three still work — the image, the PDF page, and an audio player.
Everything here has been exercised for real — see How far it is verified. Not proven yet: iOS never run; Android never run on a real device.
Upload plugins break your notes the moment you are offline; "localize" plugins only help after you have been online once. This does both — the file goes to your bucket, and the copy that renders stays behind:
| Upload-only | Localize-only | This plugin | |
|---|---|---|---|
| Offline | broken | after one online pass | works — zero remote requests |
| A new device | links work online | re-download everything | copies back-filled on demand |
| Vault size | small | grows with every file | small — copies are disposable |
| Who holds the original | a third party | you, but locally only | you, in your own storage |
{hash}.{ext}), so the same bytes are stored once.From inside Obsidian: Settings → Community plugins → Browse → search Attachment Cloud Cache → Install → Enable.
Manually: put main.js, manifest.json and styles.css from the
latest release into
<vault>/.obsidian/plugins/attachment-cloud-cache/ (⚠️ the folder name must equal the plugin id).
Then fill in the storage settings below.
In Settings → Attachment Cloud Cache (the Chinese names are in the 中文版 half):
| Setting | What it does |
|---|---|
| Endpoint · Bucket · Region | Where your storage lives (us-east-1 is the usual filler for self-hosted). |
| Access key ID | A plain text field; capitals are normal. |
| Secret access key | Goes into the OS keychain, never into data.json. |
| Public URL prefix | Optional. Empty means endpoint/bucket/key, which requires anonymous reads. |
| Test connection | One signed request, then one credential-free request to the address your links would use. |
| Import from a credentials file | MinIO's "Download credentials" JSON fills in endpoint, key and addressing mode; no copy is kept. |
| Upload new attachments automatically | On by default; off returns all of it to Obsidian, leaving files local only. |
| Where the local copy goes | Cache folder (default), attachments folder, or none. "None" turns caching off: the plugin uploads and rewrites links, and never fetches a copy back — so nothing works offline. |
| Cache folder | Relative to the vault root. Disposable: deleting it costs one re-download. |
| Cache size limit (MB) | Trims least-recently-used copies past this; 0 means no limit. |
| Download missing copies | Auto-downloads our own objects that have no local copy — never anything from other sites. Hidden when "none" is selected above, because caching is off then. |
| Cache files from other sites | Off by default; while it is off, nothing off-site is touched. |
| When a note links to a file on another site | Leave it alone (default) or Cache straight away. |
| Pick specific files | Tick individual off-site files; only those are fetched. |
| Attachments folder override · Object key template · Compatibility mode | Advanced: override Obsidian's attachment folder; change the key template ({hash}, {ext}, {filename}, {date}); use path-style addressing (keep on for R2 and MinIO). |
| Command | What it does |
|---|---|
| Show cache usage | How much the cache holds, and how much could be reclaimed. |
| Repair the local-copy index | Drops index entries whose files are already gone. |
| Clean up unused cache files | Deletes cache files no note points at any more. Cannot be undone. |
| Upload existing attachments | Uploads what your notes link to, rewrites those links, moves each file into the cache folder. |
| Cache files from other sites… | Tick individual off-site files to fetch. Needs the off-site feature turned on. |
| Clean up unused objects in the cloud… | Lists objects no note here refers to — with count and size — then deletes what you confirm. |
tiff, heic and ico are inserted as plain links, not embeds — Obsidian cannot preview them in an embed, so a
remote ![]() would be a broken image. Your files are untouched; only the link shape changed in this release..cache-index.json first — it records where this
device keeps its copies. The secret access key is not in the folder at all (it lives in Obsidian's keychain).Common failures
| Symptom | What it means |
|---|---|
| No appropriate version found. | Your Obsidian is older than 1.13.0 — the installer refusing, not a broken plugin. |
| Links open for you but not for others | No anonymous read and no public URL prefix; Test connection says exactly that. |
| Broken on a second device | No local copy there, and it could not download one. |
| An off-site file refused as "a web page or plain text" | That address serves HTML, so it is refused on purpose. |
text/html and other text/* answers are refused rather than uploaded.data.json. The access key ID is written to
data.json: an identifier, not a secret, and Obsidian's keychain accepts only lowercase IDs.npm run verify:real-storage.Open an issue: https://github.com/udarent/obsidian-plugins-attachment-cloud-cache/issues — say what you saw, your
Obsidian version and which storage provider you use; the errors name the step that failed. Working on the plugin?
npm install, then npm run dev (watch build) or npm test (build + suites).
English · 简体中文
把笔记附件上传到你自己的 S3 兼容存储 —— Cloudflare R2、AWS S3、MinIO、Backblaze B2 或任何 S3 端点 —— 同时在 本地留一份负责渲染的缓存副本。粘贴一个文件就自动上传,笔记里留下一条可迁移、可分享的链接,而渲染走本地副本, 零远端请求。
安装 · 版本发布 · 反馈问题 · 需要 Obsidian 1.13.0+(为什么)

动图取自真实运行中的 Obsidian:粘贴图片、PDF 和音频 → 各自上传 → 笔记里各留一条链接,同时 vault 的缓存目录里各留一份副本。最后一步把存储整个停掉,用来证明图片、PDF 页和音频播放器都照常工作。
下面写的每条行为都真机跑过 —— 见已验证到什么程度。 还没验证的: iOS 从未运行过;Android 也没在真机上跑过。
上传类插件一断网就让笔记裂图;「本地化」类插件只有在联网一次之后才有用。本插件两件都做 —— 文件进你的桶, 负责渲染的副本留在本地:
| 只上传 | 只本地化 | 本插件 | |
|---|---|---|---|
| 断网时 | 打不开 | 联网一次之后可用 | 可用 —— 零远端请求 |
| 换新设备 | 在线能看 | 得把所有文件重下一遍 | 副本按需自动补回 |
| vault 体积 | 小 | 每存一个文件就大一分 | 小 —— 副本是可丢弃的 |
| 原件归谁 | 第三方 | 归你,但只在本机 | 归你,在你自己的存储里 |
{hash}.{ext}),同一份字节只存一份。在 Obsidian 里装: 设置 → 第三方插件 → 浏览 → 搜 Attachment Cloud Cache → 安装并启用。
手动安装: 从最新 release
下载 main.js、manifest.json、styles.css,放进 <vault>/.obsidian/plugins/attachment-cloud-cache/
(⚠️ 目录名必须等于插件 id)。
然后填下面的存储设置。
在 设置 → Attachment Cloud Cache 里(英文名见本文英文半):
| 设置项 | 说明 |
|---|---|
| 服务地址 · 存储桶 · 区域 | 你的存储在哪(自建服务填 us-east-1 之类的占位值即可)。 |
| 访问密钥 ID | 普通输入框,含大写是正常的。 |
| 秘密访问密钥 | 进系统钥匙串,绝不写进 data.json。 |
| 公开访问前缀 | 可留空。留空就用 服务地址/存储桶/键,那要求存储桶允许匿名读取。 |
| 测试连接 | 先发一次签名请求,再不带凭据请求一次「你笔记里会写的那条地址」。 |
| 从凭据文件导入 | MinIO「下载凭据」的 JSON 会填好服务地址、密钥与寻址方式;不留副本。 |
| 新增附件自动上传 | 默认开启;关闭后这些全交回 Obsidian,文件只存在本地。 |
| 本地副本的处理 | 缓存目录(默认)/ 附件目录 / 不留。选「不留」等于关闭缓存:只上传并改写链接,也不会把副本补回来,所以离线不可用。 |
| 缓存目录 | 相对 vault 根目录。可丢弃:删掉只会多下载一次。 |
| 缓存大小上限(MB) | 超过后按最近最少使用清理;0 表示不限制。 |
| 缺本地副本时自动下载 | 只自动下载本存储没有副本的对象,站外文件永不下载。上面选「不留」时这一项不显示(那一档已关闭缓存)。 |
| 缓存站外文件 | 默认关闭;关着时站外的东西一步都不会被碰。 |
| 遇到站外文件链接时 | 什么都不做(默认)或 直接缓存。 |
| 挑选要缓存的文件 | 勾选具体的站外文件,只有勾中的会被取。 |
| 附件目录覆盖 · 对象 key 模板 · 兼容模式 | 高级:覆盖 Obsidian 的附件目录;改 key 模板({hash}、{ext}、{filename}、{date});按「地址/桶/键」寻址(R2 与 MinIO 都要开着)。 |
| 命令 | 做什么 |
|---|---|
| 查看缓存占用 | 缓存里有多少、其中多少可以回收。 |
| 自检并修复本地副本索引 | 丢掉那些文件已经不在的索引记录。 |
| 清理未使用的缓存文件 | 删掉已经没有笔记指向的缓存文件。无法撤销。 |
| 上传已存在的附件 | 上传笔记里引用着的附件、改写链接,并把每个文件移入缓存目录。 |
| 缓存站外文件(可挑选)… | 勾选具体的站外文件去下载。需要先打开站外文件功能。 |
| 清理云端未使用对象… | 列出「本库没有笔记引用」的对象(含个数与体积),确认后删除。 |
tiff、heic、ico 插入的是普通链接,不再嵌入 —— 宿主无法在嵌入里预览它们,写 ![]() 只会得到一个坏图。
你的文件没被动;这一版变的只是链接形态。.cache-index.json —— 它记的是这台设备的副本在哪。秘密访问密钥
根本不在目录里(它存在 Obsidian 的钥匙串中)。常见故障
| 现象 | 含义 |
|---|---|
| 社区目录说 No appropriate version found. | 你的 Obsidian 低于 1.13.0 —— 安装机制在拒绝,不是插件坏了。 |
| 链接自己打得开、别人打不开 | 没开匿名读,也没填公开前缀;测试连接 会明确报出这一条。 |
| 换台设备就裂 | 那台设备没有本地副本,也补不下来。 |
| 站外文件被以「返回的是网页或纯文本」拒收 | 那个地址回的是 HTML,所以刻意拒收。 |
text/html 与其它 text/* 一律拒收,而不是传上去。data.json。访问密钥 ID 会写进 data.json:它是标识符而不是
秘密,而且 Obsidian 的钥匙串只接受小写 ID。npm run verify:real-storage 复现。到 https://github.com/udarent/obsidian-plugins-attachment-cloud-cache/issues 提 issue —— 请说清你看到的、你的
Obsidian 版本和用的哪家存储;插件的报错都写明了失败在哪一步。
想改插件本身?npm install,然后 npm run dev(监听构建)或 npm test(构建 + 全部套件)。