Skip to content

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/amd64linux/arm64linux/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,只保留理解部署和数据责任所需的模块。

Mermaid 流程图
查看源码
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 可用内存和能够容纳笔记、附件、数据库、历史及备份增长的磁盘;这些是保守的入门规划,不是上游发布的性能承诺。正式容量应根据附件规模、并发设备数、全文索引和备份保留策略测量。

镜像版本、端口、卷和健康接口已经与固定提交及发布工作流核对。本文没有拉取或运行目标容器,也没有执行真实同步、备份恢复或升级。

创建工作目录

bash
mkdir -p fast-note-sync/{storage,config}
cd fast-note-sync

在该目录创建 compose.yaml

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: 30s

storage/ 保存 SQLite 数据库、日志、临时文件、全文索引以及使用本地存储时的附件;config/ 保存自动生成的服务配置。两个目录必须一起纳入备份。端口先绑定 127.0.0.1,避免初始化完成前直接暴露在公网。如果 Docker 位于远程服务器,可以使用 SSH 转发访问:

bash
ssh -L 9000:127.0.0.1:9000 user@server.example.com

然后在本机打开 http://127.0.0.1:9000。需要局域网访问时,可以在安全配置完成后把端口改为 9000:9000,并使用防火墙限制来源;公网部署应由支持 WebSocket 的 HTTPS 反向代理提供入口,不要直接开放容器端口。

启动与检查

compose.yaml 所在目录执行:

bash
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 配置并粘贴到插件设置。先用不含敏感内容的笔记完成以下闭环:

  1. 在设备 A 创建 fns-sync-check.md,等待同步完成;
  2. 在设备 B 或 Web 管理界面确认笔记出现;
  3. 在设备 B 修改一行,再确认设备 A 收到更新;
  4. 重启容器,确认同一 Vault、账号和测试笔记仍然存在。

四步都完成,才能说明“服务启动”和“核心同步路径”同时成立。本文没有执行这些运行时步骤,因此结果需要部署者在自己的设备和插件版本上验收。

公网入口与 MCP

Nginx、Caddy 或其他反向代理需要把普通 HTTP 请求和 WebSocket 升级都转发到 127.0.0.1:9000。上游 Nginx 示例为 /api/user/sync 设置了 UpgradeConnection 请求头;如果页面能打开而插件始终离线,应先检查这条 WebSocket 路径,而不是反复重装插件。

启用 HTTPS 并确认代理转发正确后,再把服务器地址填写到 Obsidian 插件或 MCP 客户端。StreamableHTTP 的最小配置形态如下:

json
{
  "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.comFNS_TOKENVAULT_NAMECLIENT_NAME 都是占位值。Token 应由管理界面生成并保存到客户端的秘密存储中,不能写进公开仓库。连接后先执行只读查询,再在测试 Vault 中创建一篇可删除的测试笔记,确认权限范围与预期一致。

安全收口

第一轮同步验证完成后,至少处理这些直接影响数据安全的设置:

  • config/config.yaml 中的 user.register-is-enable 改为 false,重启服务后确认匿名用户不能继续注册;
  • 检查 security.auth-token-key 已经是独立随机值,并限制 config/ 目录的宿主机读取权限;
  • 只通过 HTTPS 暴露公网入口,代理必须正确处理 /api/user/sync WebSocket 和 /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/ 作为一个恢复单元:

bash
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 中的镜像标签改成目标版本:

bash
docker compose pull
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:9000/api/health

程序启动时会自动执行数据库升级任务。升级后应再次验证登录、同步、附件和历史,而不只看容器是否运行。需要回滚时,先停止新版本并保留当前 storage/config/,再恢复升级前备份并把镜像标签改回原版本。不要直接让旧二进制读取已经迁移过的新数据库。

停止服务但保留数据使用:

bash
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、入口脚本、启动链路和健康接口的静态核验,并确认了版本发布与容器构建任务状态;没有执行上游代码、拉取镜像、启动容器、真实同步、恢复或升级。

全部公开文章由同一个站点构建和发布。