Fast Note Sync Service:自托管 Obsidian 同步、管理与 AI 接口
Obsidian 把笔记保存为本地文件,这让数据很容易掌握,却把多台电脑和手机之间的同步留给了使用者。只同步文件夹可以解决一部分问题,但设备同时离线编辑、附件分片传输、历史版本、回收站和远程自动化都需要额外机制。
Fast Note Sync Service(下文简称 FNS)是 Obsidian Fast Note Sync 插件的自托管服务端。插件通过 WebSocket 与服务端交换笔记、目录、附件和配置变更;浏览器可以管理笔记库与用户;脚本和 AI 客户端则通过 REST API 或 MCP 访问同一份内容。服务端数据可以落在 SQLite、MySQL 或 PostgreSQL,附件还能接入本地文件系统、S3、R2、OSS、MinIO 或 WebDAV。
这种设计带来一个重要变化:同步不再只是复制目录,FNS 会维护用户、笔记库、历史记录、令牌和同步状态。换来的代价也很明确,部署者需要负责服务端安全、备份、升级以及客户端版本兼容。
GitHub 仓库信息
| 信息 | 内容 |
|---|---|
| 项目标题 | Fast Note Sync Service |
| 项目描述 | 一个面向 Obsidian 的高性能、低延迟笔记同步服务平台,同时提供在线管理、REST API 和 MCP 接入能力。 |
| GitHub 仓库 | haierkeys/fast-note-sync-service |
| 官网地址 | 未知(已检索仓库、README、作者主页与公开博客,但未确认独立项目官网) |
| 主要开发语言 | Go 92.49%、Shell 4.27%、JavaScript 2.27% |
| 开源许可证 | Apache-2.0 |
| 最近代码更新 | 2026-08-14(GitHub pushed_at,核对日期:2026-09-10) |
项目轮廓
FNS 3.6.1 把常见的笔记同步需求放进一套服务中:WebSocket 负责设备间实时同步,Web 管理界面处理用户、笔记库和配置,REST API 面向自动化,MCP 让兼容客户端能够按授权范围读写笔记。服务端还记录历史版本、软删除内容和同步日志,并提供定时备份与 Git 同步能力。
第一次采用时,最好先把目标限定为“在两台设备之间同步一个测试笔记库”。外部对象存储、OIDC、Cloudflare Tunnel、Git 自动提交和 AI 接入都可以稍后添加。一次启用全部能力会扩大故障面,也更难判断数据究竟在哪一层出了问题。
当前稳定 Release 是 3.6.1,发布于 2026 年 8 月 14 日。固定提交中的发布工作流为 Docker Hub、GHCR 和 CNB 构建 linux/amd64、linux/arm64 与 linux/arm/v7 镜像;对应 push-docker 任务已经成功。本文使用 Docker Hub 的版本标签,不使用会随上游变化的 latest。
三条使用路径
多端同步保留了笔记语义
普通目录同步看到的是文件变化,FNS 的 WebSocket 路由还区分笔记、目录、附件和 Obsidian 设置。服务端为这些对象注册不同处理器,附件支持分片上传下载,离线重连时由同步协议补齐变更。历史版本和回收站建立在服务端记录之上,因此误删或误改不必只依赖文件系统快照。
这不表示冲突会自动消失。仓库路线图仍把离线合并和冲突处理列为持续优化方向。多个设备长期离线、再同时修改同一篇重要笔记时,应先在非关键 Vault 中验证实际行为,并保留独立备份。
浏览器和 API 面向不同操作
Web 管理界面适合创建用户、管理 Vault、查看笔记和历史、配置存储及备份。REST API 提供笔记、目录、附件、分享和同步日志等接口,适合脚本或其他系统集成。GET /api/health 会同时检查进程和数据库连接,可以作为容器健康探针。
服务端并不把所有接口都交给同一种令牌。固定提交中的 API 路由明确把用户、Vault、存储、备份和令牌管理等操作放进 WebGUI 专用路由组;用户令牌中间件则检查令牌轮换状态、客户端、User-Agent、可选 IP 绑定、协议权限和 Vault 范围。部署完成后应为不同客户端分别签发令牌,而不是共享一个长期管理员凭据。
MCP 让 AI 在授权范围内操作笔记
FNS 原生提供 StreamableHTTP 和兼容旧客户端的 SSE 两种 MCP 传输。较新的客户端使用 /api/mcp,只支持旧式 SSE 的客户端使用 /api/mcp/sse。请求通过 Authorization: Bearer <Token> 鉴权,并可用 X-Default-Vault-Name 指定默认笔记库。
MCP 接入改变的是访问入口,不会消除数据风险。允许 AI 写笔记和附件,相当于给自动化程序开放真实数据修改能力。正式接入前应创建权限受限、可轮换的独立 Token,在测试 Vault 中确认读、写、重命名和删除边界。
工作原理
下面的关系来自固定提交中的启动、路由和服务容器代码。图中没有展开每个 API,只保留理解部署和数据责任所需的模块。
正在准备渲染...
查看源码
flowchart LR
obsidian[Obsidian 插件] --> ws[WebSocket 同步入口]
browser[Web 管理界面] --> http[HTTP API 路由]
automation[脚本与集成] --> http
ai[AI / MCP 客户端] --> mcp[MCP 路由]
ws --> services[笔记、目录、附件与设置服务]
http --> services
mcp --> services
services --> db[(SQLite / MySQL / PostgreSQL)]
services --> files[本地或对象存储]
services --> history[历史、回收站与同步日志]
scheduler[定时任务] --> backup[备份与 Git 同步]
backup --> files
backup --> remote[远程存储或 Git 仓库]容器启动时,入口脚本切换到 /fast-note-sync,准备日志目录,再运行服务的 run 命令。如果挂载的 config/ 为空,程序会创建 config/config.yaml,并把示例中的默认认证密钥替换为随机字符串。随后服务初始化日志、存储目录和数据库,执行数据库升级任务,再启动 HTTP、WebSocket、MCP 和计划任务。
默认只有 9000 端口监听 HTTP API、Web 管理界面、WebSocket 和 MCP。仓库中的另一个 Compose 示例额外映射 9001,但默认配置的独立 WebGUI 端口为空;没有显式设置 server.webgui-port: ":9001" 时,映射 9001 不会产生可访问服务。
Docker Compose 部署
下面的路径面向一台已经安装 Docker Engine 与 Compose V2 的 Linux 主机。建议至少准备 1 个 CPU 核心、1 GB 可用内存和能够容纳笔记、附件、数据库、历史及备份增长的磁盘;这些是保守的入门规划,不是上游发布的性能承诺。正式容量应根据附件规模、并发设备数、全文索引和备份保留策略测量。
镜像版本、端口、卷和健康接口已经与固定提交及发布工作流核对。本文没有拉取或运行目标容器,也没有执行真实同步、备份恢复或升级。
创建工作目录
mkdir -p fast-note-sync/{storage,config}
cd fast-note-sync在该目录创建 compose.yaml:
services:
fast-note-sync-service:
image: haierkeys/fast-note-sync-service:3.6.1
container_name: fast-note-sync-service
restart: unless-stopped
ports:
- "127.0.0.1:9000:9000"
volumes:
- ./storage:/fast-note-sync/storage
- ./config:/fast-note-sync/config
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:9000/api/health"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30sstorage/ 保存 SQLite 数据库、日志、临时文件、全文索引以及使用本地存储时的附件;config/ 保存自动生成的服务配置。两个目录必须一起纳入备份。端口先绑定 127.0.0.1,避免初始化完成前直接暴露在公网。如果 Docker 位于远程服务器,可以使用 SSH 转发访问:
ssh -L 9000:127.0.0.1:9000 user@server.example.com然后在本机打开 http://127.0.0.1:9000。需要局域网访问时,可以在安全配置完成后把端口改为 9000:9000,并使用防火墙限制来源;公网部署应由支持 WebSocket 的 HTTPS 反向代理提供入口,不要直接开放容器端口。
启动与检查
在 compose.yaml 所在目录执行:
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 fast-note-sync-service
curl -fsS http://127.0.0.1:9000/api/health基础成功信号包括:容器状态进入 healthy;日志显示配置文件路径且没有持续数据库错误;健康接口返回包含 "status":"healthy" 和 "database":"connected" 的 JSON;浏览器能够打开 Web 管理界面。
如果 config/config.yaml 没有生成,先检查 config/ 的宿主机写权限。不要直接复制上游示例配置后原样公网运行,因为示例包含公开的默认 security.auth-token-key;源码会对默认值发出安全警告,而自动随机化只发生在程序创建新配置时。
完成一次有效同步
服务可访问后,在 Web 管理界面注册第一个账号并创建测试 Vault。随后安装官方 Obsidian Fast Note Sync 插件,在管理界面复制客户端 API 配置并粘贴到插件设置。先用不含敏感内容的笔记完成以下闭环:
- 在设备 A 创建
fns-sync-check.md,等待同步完成; - 在设备 B 或 Web 管理界面确认笔记出现;
- 在设备 B 修改一行,再确认设备 A 收到更新;
- 重启容器,确认同一 Vault、账号和测试笔记仍然存在。
四步都完成,才能说明“服务启动”和“核心同步路径”同时成立。本文没有执行这些运行时步骤,因此结果需要部署者在自己的设备和插件版本上验收。
公网入口与 MCP
Nginx、Caddy 或其他反向代理需要把普通 HTTP 请求和 WebSocket 升级都转发到 127.0.0.1:9000。上游 Nginx 示例为 /api/user/sync 设置了 Upgrade 与 Connection 请求头;如果页面能打开而插件始终离线,应先检查这条 WebSocket 路径,而不是反复重装插件。
启用 HTTPS 并确认代理转发正确后,再把服务器地址填写到 Obsidian 插件或 MCP 客户端。StreamableHTTP 的最小配置形态如下:
{
"mcpServers": {
"fns": {
"url": "https://notes.example.com/api/mcp",
"type": "http",
"headers": {
"Authorization": "Bearer <FNS_TOKEN>",
"X-Default-Vault-Name": "<VAULT_NAME>",
"X-Client": "<CLIENT_NAME>"
}
}
}
}notes.example.com、FNS_TOKEN、VAULT_NAME 和 CLIENT_NAME 都是占位值。Token 应由管理界面生成并保存到客户端的秘密存储中,不能写进公开仓库。连接后先执行只读查询,再在测试 Vault 中创建一篇可删除的测试笔记,确认权限范围与预期一致。
安全收口
第一轮同步验证完成后,至少处理这些直接影响数据安全的设置:
- 将
config/config.yaml中的user.register-is-enable改为false,重启服务后确认匿名用户不能继续注册; - 检查
security.auth-token-key已经是独立随机值,并限制config/目录的宿主机读取权限; - 只通过 HTTPS 暴露公网入口,代理必须正确处理
/api/user/syncWebSocket 和/api/mcp长连接; - 为 Obsidian、脚本和 MCP 客户端分别签发最小权限 Token,设置合理有效期并测试轮换;
- 默认关闭不需要的独立 WebGUI、分享端口、附件静态入口、OIDC、OAuth 和 Cloudflare Tunnel;
- 使用远程对象存储、Git 或 Tunnel 时,把访问凭据留在受保护配置或密钥系统中,不写入 Compose 和公开日志。
WebGUI 登录 Token 的 IP 绑定配置默认为启用。使用 Cloudflare Tunnel 或出口 IP 经常变化的代理时可以关闭这一绑定,但这会减少一道限制;应先保证 HTTPS、代理信任范围和令牌权限已经收紧。
备份、升级与回滚
SQLite 默认数据库位于 storage/database/db.sqlite3,但完整恢复还依赖附件、日志索引和配置。最稳妥的基础备份是短暂停止写入,并把 storage/ 与 config/ 作为一个恢复单元:
docker compose stop
tar -czf ../fast-note-sync-backup-$(date +%F-%H%M%S).tar.gz storage config
docker compose start备份完成不等于可恢复。定期在隔离目录解压备份,使用相同镜像版本启动,再检查登录、Vault 列表、笔记、附件和历史。若通过 Web 管理界面把附件镜像到 S3、R2、OSS、MinIO 或 WebDAV,还要单独验证远端对象和服务端元数据能够共同恢复。
升级前阅读目标 Release,完成备份,然后把 compose.yaml 中的镜像标签改成目标版本:
docker compose pull
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:9000/api/health程序启动时会自动执行数据库升级任务。升级后应再次验证登录、同步、附件和历史,而不只看容器是否运行。需要回滚时,先停止新版本并保留当前 storage/、config/,再恢复升级前备份并把镜像标签改回原版本。不要直接让旧二进制读取已经迁移过的新数据库。
停止服务但保留数据使用:
docker compose down只有明确完成独立备份且确定不再需要数据时,才手动处理 storage/ 和 config/。普通 docker compose down 不会删除这两个绑定目录。
常见问题
| 现象 | 定位与处理 |
|---|---|
| 容器反复重启 | 查看 docker compose logs;检查 config/、storage/ 写权限,以及配置文件 YAML 是否能解析。修复后重新检查健康接口。 |
| 健康接口显示数据库异常 | 检查 SQLite 文件目录权限和磁盘空间;使用外部数据库时核对网络、账号、数据库名及 TLS 配置。 |
| Web 页面正常,Obsidian 一直离线 | 检查 /api/user/sync 的 WebSocket 升级头、代理超时和客户端服务地址。 |
9001 无法访问 | 默认配置没有启用独立 WebGUI 端口;继续使用 9000,或者显式配置 server.webgui-port 后再映射新端口。 |
| MCP 返回未授权 | 确认地址是 /api/mcp 或 /api/mcp/sse,Header 使用 Bearer Token,并检查 Token 的协议、客户端和 Vault 权限。 |
| 重启后配置或笔记消失 | 确认 Compose 正在使用预期工作目录,且两个绑定目录没有被临时路径或另一份 Compose 覆盖。 |
适用边界
FNS 更适合希望自托管 Obsidian 同步、愿意维护服务器,并且确实需要 Web 管理、开放 API、MCP、历史版本或多存储备份的人。个人和小团队都可以从 SQLite 开始;并发、隔离或运维要求提高后,再评估 MySQL、PostgreSQL、OIDC 和外部对象存储。
如果只需要在自己的几台设备之间同步普通文件,Syncthing 一类文件同步工具组件更少,但不会提供 FNS 的用户、Vault、历史、Web 管理和 API 语义。希望完全省去服务器维护时,Obsidian 官方 Sync 更直接。已经围绕 CouchDB 建立 Obsidian 同步流程的用户,也可以按客户端兼容、冲突模型、移动端体验和运维成本评估 Self-hosted LiveSync,而不是只比较功能数量。
正式迁移前,最有价值的下一步是复制一个非关键 Vault,连续测试设备离线、同时修改、附件上传、历史恢复和服务端备份恢复。只有这组结果符合自己的数据习惯,才适合把主笔记库迁入。
版本与参考
本文基于 Fast Note Sync Service 3.6.1 的源码提交 7a6c787,源码与动态仓库信息核对日期为 2026 年 9 月 10 日。项目采用 Apache-2.0 许可证。
本文进行了仓库、配置、Compose、Dockerfile、入口脚本、启动链路和健康接口的静态核验,并确认了版本发布与容器构建任务状态;没有执行上游代码、拉取镜像、启动容器、真实同步、恢复或升级。