date: 2026-09-06 tags: [obsidian, livesync, couchdb, 同步, 运维记录] status: 已跑通 version: 脱敏公开版
Obsidian 多端实时同步搭建记录
一句话总结:两台电脑的 Obsidian 通过自建 CouchDB 做双向实时同步,云端存密文数据库,各端本地保留完整 md 文件;最大的坑不是配置,是插件复制被"挂起"需要手动放行。
本文已脱敏:服务器地址、账号、密码、内部库名等敏感信息均以占位符表示,替换为自己的实际值即可复用。
一、架构与原理
| 组成 | 说明 |
|---|---|
| 服务器 | 云服务器(我用的是腾讯云轻量),CouchDB 3.4(Docker 容器,端口 5984) |
| 客户端 | 笔记本 + 台式机,各装 Obsidian + Self-hosted LiveSync v1.0.26 |
| 数据形态 | 云端是 CouchDB 数据库(JSON 文档),不是 md 文件;md 文件只存在各端本地 vault |
| 同步机制 | 笔记被切成小块(文档 ID 以 h: 开头),双向增量复制,改动秒级推送 |
| 加密 | 端到端加密开启(E2EE v2),服务器上全是密文,截获也读不出来 |
⚠️ 文件名会被统一小写(handleFilenameCaseSensitive: false),如何把Obsidian...md 在云端是 如何把obsidian...md,比对时先转小写。
二、最终配置参数
| 项 | 值 |
|---|---|
| URI | http://<服务器IP>:5984 |
| 数据库 | <笔记库名> |
| 账号 | <同步账号> |
| 密码 | <同步账号密码> |
| 端到端加密 | 开启,两台的 passphrase 必须完全一致 |
| 必开开关 | LiveSync(实时同步) |
| 建议开 | Sync on Start(启动即同步)、Periodic Replication(定时复制) |
新设备接入最快方式:在已配好的那台用「复制配置 URI / Copy setup URI」生成 obsidian://setuplivesync?...,新设备打开即完成配置(URI、库名、账号、加密口令一次带全)。
新设备首次动作选 Fetch from remote,千万别选"以本地为准重建"——会把云端数据冲掉。
三、踩过的坑与解法(按时间顺序)
| # | 症状 | 真实原因 | 解决办法 |
|---|---|---|---|
| 1 | Obsidian 装插件卡住,只下了 manifest.json | 自带下载走 GitHub 不稳,缺 main.js 插件根本不加载 |
从 GitHub release 手工下载 main.js+styles.css,下完核对字节数(网络不稳会截断,curl exit 23) |
| 2 | 插件装好了没反应 | 四个自动开关(liveSync/syncOnSave/syncOnStart/periodicReplication)默认全 false |
至少开 liveSync |
| 3 | 判断"服务器没有数据" | 判据用错:只看了有没有新库名,没看已有库内容 | 笔记其实写进了已存在的库 |
| 4 | 判断"另一台从没连过服务器" | 两机在同一家庭宽带下,NAT 后公网 IP 相同,靠 IP 根本区分不了设备 | 改用 hostname 区分机器 + _local_docs 检查点计数 |
| 5 | 以为云端多出的笔记是另一台传来的 | 该文档元数据是 "deleted": true,是本机建了又删的 |
看文档元数据里的 deleted 字段 |
| 6 | 新设备连不上 | 老账号在 _users 里是 deleted 状态,老设备靠认证缓存硬撑,新设备登录必失败 |
新建专用同步账号 |
| 7 | 向导报「访问被禁止 / Access forbidden」 | 向导会试着建数据库(服务器级操作),普通成员账号无权限 | 见下方"权限三连坑" |
| 8 | 连上了却不传数据(最坑) | 插件处于挂起态,反复读 sync_parameters 却不启动复制 |
Ctrl+P → Self-hosted LiveSync: Toggle LiveSync |
权限三连坑(第 7 条展开)
- 账号建好后默认可能无权访问该库——若库的
_security是{roles:["_admin"]},必须单独授权:PUT /<db>/_security里加members.names: ["<同步账号>"] - 想在
_users里塞"roles":["_admin"]会被拒绝:No system roles (starting with underscore) in users db——系统角色只能写进服务器配置 - 账号同时存在于
_users和 admins 配置时_users优先,管理员身份不生效——必须删除_users里那条
最终解法:
# 写进 admins 配置
curl -X PUT -u 管理员:密码 http://127.0.0.1:5984/_node/_local/_config/admins/<同步账号> \
-H 'Content-Type: application/json' -d '"<同步账号密码>"'
# 删除 _users 里的同名记录,否则 roles 仍是 []
curl -X DELETE -u 管理员:密码 \
"http://127.0.0.1:5984/_users/org.couchdb.user:<同步账号>?rev=<rev>"
四、验收方法(三条硬指标,缺一不可)
| 指标 | 命令 / 位置 | 成功标准 |
|---|---|---|
| 文档总数增长 | GET /<db> 的 doc_count |
新笔记传上去后变大 |
| 设备检查点增加 | GET /<db>/_local_docs |
每接入一台新设备 +2 条(一推一拉) |
| 出现真实复制 | 容器日志 | 有 _changes / _revs_diff / _bulk_docs |
挂起态的典型特征:日志里几十上百次 GET /<db>/_local/obsidian_livesync_sync_parameters,但没有任何 _changes/_bulk_docs。看到这个就说明插件在等你放行,不是故障。
最终验收:在其中一台新建一篇测试笔记,另一台本地 vault 里能看到它 = 真正双向打通。
五、排查速查命令
# 本机机器名(区分设备的关键,别信公网 IP)
hostname
# 插件配置状态
cat "<vault>/.obsidian/plugins/obsidian-livesync/data.json" | grep -E \
'"liveSync"|"syncOnStart"|"isConfigured"|"encrypt"'
# 本地文件清单(比对前统一小写)
find "<vault>" -type f \( -name "*.md" -o -name "*.base" \) -not -path "*/.obsidian/*" \
-printf "%P\n" | tr 'A-Z' 'a-z' | sort
# 服务器端
docker logs --since 5m <容器名> | grep -cE '_changes|_bulk_docs' # 有没有真在传
curl -s -u 管理员:密码 http://127.0.0.1:5984/<db>/_local_docs # 几台设备
六、遗留事项
| 事项 | 现状 | 建议 |
|---|---|---|
| 数据库混用 | 笔记库与其他项目数据共用一个库 | 笔记量还小时拆库成本最低;先备份 |
| 账号权限 | 同步账号目前是服务器管理员 | 跑稳后可降权(降权后不能新建库,日常同步不受影响) |
| 冲突副本 | 云端有撞名产生的副本文件 | 直接删 |
| 传输安全 | 5984 明文 HTTP,但内容已端到端加密 | 稳妥起见可给 5984 套 HTTPS |
| 云端备份 | 全量导出 JSON 存于服务器 | 保留作后悔药 |
七、经验教训
- 先确定判据再下结论——今天三次判断失误("服务器没数据""另一台没连过""台式机传上来了"),全部源于用错了判据或只看了表面。
- 同网多台机器公网 IP 相同,排查多端问题必须靠 hostname 和服务端检查点。
- "没报错"不等于"在同步"——挂起态就完全静默,必须看服务端日志里的
_changes才算数。