用 [[Obsidian]] 记笔记这么多年,有一个需求一直没有被很好地解决,那就是在浏览器里直接访问自己的笔记库。Obsidian 官方一直没有推出 Web 版本,过去想要在别人的电脑上、或者在不方便安装客户端的环境里查看和编辑笔记,要么依赖远程桌面这种笨重的方案,要么就只能把笔记渲染成静态网站,牺牲掉编辑能力,或者通过 SSH 登录我的 macOS 通过命令行方式访问。最近我发现了一个叫 Ignis 的开源项目,它的口号非常直接:Run Obsidian as a self-hosted web app. Not remote desktop, an actual web app。它不是远程桌面,而是让 Obsidian 真正跑在浏览器里,体验下来确实让我眼前一亮,这篇文章就来聊聊它。

为什么浏览器访问 Obsidian 一直是个难题
Obsidian 是一个基于 Electron 的桌面应用,它的编辑器、插件系统、文件访问都建立在 Electron 提供的 Node.js 能力之上,而浏览器出于安全考虑并不提供这些 API,这是官方迟迟没有 Web 版的根本原因。在 Ignis 出现之前,想远程访问自己的笔记库大致有几类办法。
第一类是远程桌面方案,比如用 KasmVNC 或者类似 linuxserver 的 Obsidian 容器镜像,把整个桌面版 Obsidian 的画面通过 VNC 串流到浏览器。这类方案功能上最完整,但体验很差,字体渲染模糊、剪贴板不通、延迟明显,在手机上更是几乎不可用。
第二类是发布类方案,比如 Obsidian Publish、[[Quartz]]、Flowershow 这些工具,把笔记库渲染成静态网站。它们适合对外分享,但本质上是只读的,无法在浏览器里编辑笔记,也用不了任何插件。
第三类是换用天生就是 Web 应用的笔记工具,比如 SiYuan、AFFiNE 之类,但这意味着放弃 Obsidian 的整个插件生态和已经养成的工作流,迁移成本太高。
Ignis 走的是第四条路:它是一个兼容层(compatibility shim),为 Obsidian 所依赖的 Electron API 提供了浏览器端的实现,让原版 Obsidian 的代码直接在浏览器里运行,笔记库则保存在服务器上。值得一提的是,Ignis 本身不包含也不分发任何 Obsidian 的代码和资源,Docker 容器在首次启动时会从 Obsidian 官方源下载程序本体。项目采用 AGPL-3.0 协议开源,作者还专门写了一份 LEGAL.md,援引欧盟软件指令中关于互操作性的条款说明合法性,并明确表示无意损害 Obsidian 官方的商业利益,这种认真程度在同类项目里并不多见。
Ignis 能做到什么
我最关心的当然是兼容性,毕竟一个残缺的 Obsidian 没有意义。实际情况比我预期的好很多,Obsidian 的核心功能基本都能用:编辑器、Canvas 白板、Bases 数据库视图、命令面板、右键菜单、主题和 CSS 片段都正常工作,绝大多数基于 Obsidian 插件 API 开发的社区插件也能直接加载。图谱视图、大纲这些功能在正确配置 HTTPS 之后也都可用,这一点后面讲部署时会展开。
在 Web 化之后,Ignis 还带来了一些桌面版没有的能力。它支持通过工具栏、右键菜单或者直接拖拽来上传文件到笔记库,也可以把单个文件或整个文件夹打包成 ZIP 下载下来。多仓库支持做得很完整,可以创建、切换、重命名、删除 vault,不同的浏览器标签页甚至可以打开不同的 vault。多个标签页之间通过 WebSocket 实时同步,在一个标签页里的编辑会在一秒内出现在另一个标签页中。另外还有两个很实用的 URL 参数:?workspace= 可以在独立标签页中打开某个保存好的工作区布局,?file= 可以通过 URL 直接打开某篇笔记,这让 Obsidian 的笔记第一次拥有了可以分享给自己其他设备的链接。小屏幕设备上 Ignis 会切换到移动端 UI,手机浏览器里的体验接近 Obsidian 移动客户端。
| 同步方面,官方的 Obsidian Sync 可以在登录的标签页里正常工作,Ignis 还提供了服务端的 Headless Sync,即使浏览器标签页全部关闭,服务器也能继续在后台同步,这个设计解决了 Web 应用”关掉页面就停止工作”的天然缺陷。对于我这种用第三方方案同步的用户,obsidian-livesync 这类走 WebSocket 或 HTTP 的插件也能配置成功,只是要注意一些网络上的细节,后面避坑部分会提到。我在 [[2020-11-23-obsidian-sync-acrose-devices-solution | 我的 Obsidian 笔记跨设备同步方案]] 里梳理过各种同步方式,Ignis 相当于给这些方案又加了一个随时可用的 Web 入口。 |
性能上作者也下了功夫。Ignis 用一次预压缩的 bootstrap 请求就把 vault 信息、元数据树、插件列表全部交付给浏览器,配合索引器预取(indexer pre-fetch)预热内容缓存,让 Obsidian 启动时的索引过程命中缓存而不是反复走网络。服务端用 LRU 缓存控制内存占用,默认 50MB,不会把整个笔记库都加载进内存,这些参数都可以在设置面板里调整。我的笔记库有几千个文件,加载速度完全在可接受范围内。
用 Docker 部署 Ignis
Ignis 的部署非常简单,官方提供了 Docker 镜像,一个 docker-compose 文件就能跑起来:
services:
ignis:
image: nobbe/ignis:latest
ports:
- "8080:8080"
environment:
# 运行 id 命令查看自己的 uid/gid 并填入
- PUID=1000
- PGID=1000
volumes:
- ./vaults:/vaults
- ./data:/app/data
- obsidian-app:/app/obsidian-app
restart: unless-stopped
volumes:
obsidian-app:
保存为 docker-compose.yml 之后执行 docker compose up -d,首次启动时容器会从官方源下载 Obsidian 和 obsidian-headless CLI,大概需要一两分钟,可以用 docker compose logs -f 观察进度。之后访问 http://localhost:8080,如果 vaults 目录下已经有笔记库会自动加载,否则会打开 vault 管理器引导创建第一个。
有几个部署细节值得注意。PUID 和 PGID 要和宿主机用户匹配,用 id 命令查一下自己的 uid 和 gid 填进去,否则 Ignis 写入的文件归属会出问题。如果笔记库放在 NAS 挂载或者 NFS 上,可以直接把外部目录挂载到 /vaults 下面的子目录;对于 rclone mount、FUSE、NFS、SMB 这类较慢的文件系统,还可以设置 WRITE_COALESCE_MS 环境变量开启写入合并去抖,减少频繁的小写入。
我自己的做法是把 Ignis 指向已有的同步目录,这样桌面版 Obsidian、手机客户端和 Ignis 操作的是同一份数据,Ignis 只是多出来的一个访问入口,不需要改变原有的同步链路。
远程访问与安全:最重要的避坑点
这一部分是使用 Ignis 之前必须搞清楚的,官方文档也用了醒目的警告来强调。核心有两点:Ignis 没有内置任何身份验证,以及浏览器的安全上下文(secure context)要求。
先说安全上下文。Obsidian 依赖的一些浏览器 API,比如加密和剪贴板相关的接口,只在 HTTPS 或者 localhost 环境下可用。所以如果你通过 http://192.168.1.10:8080 这样的局域网地址裸访问 Ignis,会发现图谱视图、大纲、Sync 等一系列功能默默失效,这不是 bug,而是浏览器的安全策略。解决办法有两类:正经的做法是在前面加一层 TLS,用 Caddy、nginx 或 Traefik 做反向代理(官方 examples 目录里有现成配置),或者用 tailscale serve、Cloudflare Tunnel 这类免证书管理的方案;偷懒的做法是在每个客户端浏览器里把 Ignis 的地址加入安全源白名单,Chromium 系浏览器在 chrome://flags/#unsafely-treat-insecure-origin-as-secure 设置,但这种方式只适合局域网,Safari 没有对应选项只能上 TLS。
再说身份验证。Ignis 默认监听纯 HTTP 且没有登录机制,任何能访问到这个端口的人都可以读写你的整个笔记库。所以绝对不要把 Ignis 直接暴露到公网。如果需要在外网访问,务必在前面加一层认证:反向代理的 Basic Auth 是最简单的,Authelia、Authentik、OAuth2 Proxy 这类 SSO 方案更完善,也可以用 Cloudflare Access 配合 Tunnel,或者干脆走 Tailscale、WireGuard 这样的 VPN 只在私有网络里访问。官方 examples 里提供了两套完整的 Caddy 配置,分别对应 Basic Auth 和 Authelia,可以直接拿来用。路线图里提到未来会支持内置认证和多用户 OIDC,但在那之前,认证完全是自己的责任。
我个人的建议是家庭网络内用 tailscale serve 一条命令解决 HTTPS 和访问控制两个问题,既不用管证书,也天然只有自己的设备能访问,是最省心的组合。
还有一个容易踩的坑是第三方同步插件的连通性。出于防止恶意网络扫描的考虑,Ignis 服务端默认拒绝中继指向私有地址、回环地址的 HTTP 请求,所以如果你的 CouchDB 或者其他同步服务器跑在局域网或同一台 Docker 主机上,需要通过 PROXY_ALLOW_PRIVATE_HOSTS 环境变量显式放行对应的 IP 或 CIDR(注意只接受 IP 不接受主机名),或者在设置里配置 direct-fetch 让浏览器直连(这要求同步服务器开启 CORS)。走 WebSocket 的同步插件则是浏览器直连,当 Ignis 本身是 HTTPS 时,浏览器会拒绝明文的 ws:// 连接,同步服务器也需要提供 wss://,用受信任的证书或者同样套一层 tailscale serve 就能解决。
限制与不完美的地方
把 Electron 应用塞进浏览器不可能没有代价,有些限制需要提前知晓。最主要的是需要 Node 原生模块或 child_process 的插件无法加载,比如依赖本地执行命令的插件(典型如调用本地 Git 二进制、执行 shell 脚本的那一类)在 Ignis 里是跑不起来的,官方文档维护了一个插件兼容性页面,重度依赖某个插件的话建议先去查一下。
另一个需要留意的是密钥存储。桌面版 Obsidian 的插件可以用 Electron 的 safeStorage 借助操作系统加密敏感数据,浏览器没有等价能力,所以 Ignis 里插件存储的 API key 之类的秘密目前是明文保存的,服务端加密在计划中但尚未实现。在共享或安全性存疑的服务器上部署时,这一点要纳入考虑。
还有一些小的差异:浏览器无法弹出真正的本地文件选择器,所以像 Importer 这类插件导入文件要分两步操作,先选择文件暂存再重新执行动作;拼写检查语言跟随浏览器设置而不是应用内设置;依赖 Electron 菜单 API 的原生菜单选项被禁用。这些都属于可以接受的妥协。
最后要提醒的是,Ignis 还是一个很年轻的项目,虽然作者自己已经把它当作日常笔记工具在用,GitHub 上也已经收获了超过 1200 个 star,但处于活跃开发阶段意味着可能遇到未记录的问题。好在它只是数据的一个访问层,笔记本体始终是磁盘上的 Markdown 文件,就算 Ignis 出问题,数据本身也不会受影响,这也是我敢直接把它指向主力笔记库的原因。当然,任何时候都不要忘了备份。
最后
Ignis 解决的是一个存在了很多年的真实痛点:Obsidian 的本地优先哲学和随时随地访问之间的矛盾。此前的答案要么是体验糟糕的远程桌面,要么是丧失编辑能力的静态发布,而 Ignis 用兼容层的思路给出了第三种答案,让你在浏览器里得到一个接近原生的、插件可用的、可编辑的 Obsidian,而数据依然完整地躺在自己服务器的文件系统里。
对我来说,它最大的价值是让 Obsidian 的访问入口从”装了客户端的设备”扩展到了”任何一个有浏览器的地方”,配合 Tailscale 之后,在公司的电脑、朋友的电脑、甚至 iPad 的浏览器里打开自己的笔记库都只是一个 URL 的事情。如果你也是 Obsidian 的自托管爱好者,手边有一台跑着 Docker 的小主机或 NAS,非常值得花十几分钟把 Ignis 跑起来体验一下。项目的 GitHub 仓库 和官方文档都写得相当清楚,部署前把安全章节读一遍,就可以放心使用了。