Sign inSign up

yusoltsev/obsidian-crdt-sync-server

By yusoltsev

•Updated 6 months ago

Self-hosted sync server for Obsidian with SQLite storage and optional Git backups.

Image
0

2.0K

yusoltsev/obsidian-crdt-sync-server repository overview

⁠obsidian-crdt-sync-server

Build Status GitHub Release Docker Image (docker.io) Docker Image (ghcr.io) Docker Image Size

⚠️ Early development — This server is in active early development. Use at your own risk.

A self-hosted sync backend for the obsidian-crdt-sync⁠ Obsidian plugin. It keeps your vault state in one place so your devices can stay in sync without giving your notes to a third-party service.

⁠What you get

  • A real-time sync hub for every device: connect desktop, mobile, and other clients to the same vault state.
  • Support for the full vault, not just note text: notes, attachments, folder structure, renames, moves, and deletes are all part of the sync model.
  • SQLite-backed vault storage: the latest synced state is persisted locally, so the server keeps your vault between restarts.
  • Consistent file identity across clients: the server validates structural changes so two devices do not quietly drift into conflicting paths or broken renames.
  • Optional Git backups: you can periodically materialize the vault into a normal Git repository and push it to a remote for history and disaster recovery.
  • Straightforward self-hosting: run it on your own infrastructure behind a reverse proxy, without relying on a third-party sync service.

⁠Usage

Copy .env.example to .env and set AUTH_TOKEN:

cp .env.example .env
# edit .env and set AUTH_TOKEN

Generate a token with:

openssl rand -base64 32

Then start the server:

docker compose up -d
⁠Docker
docker run -d \
  -p 3000:3000 \
  -v ./data:/data \
  -e AUTH_TOKEN="your-random-secret-at-least-32-chars" \
  -e DATA_DIR=/data/db \
  -e BACKUP_GIT_WORKTREE_DIR=/data/git \
  yusoltsev/obsidian-crdt-sync-server:latest
⁠From source
bun install
bun src/index.ts

Set environment variables via a .env file or export them before running. See .env.example for all options.

⁠Environment Variables

VariableRequiredDefaultDescription
AUTH_TOKEN✅—Shared secret for WebSocket auth (min 32 chars)
PORT3000Port to listen on
DATA_DIR./data/dbDirectory for the SQLite database
BACKUP_GIT_INTERVAL_MINUTES—Enable periodic Git backup (positive integer)
BACKUP_GIT_URLwhen backup enabled—HTTPS remote URL
BACKUP_GIT_USERNAMEwhen backup enabled—Git HTTPS username
BACKUP_GIT_PASSWORDwhen backup enabled—Git HTTPS password or token
BACKUP_GIT_BRANCHmainBranch to push backups to
BACKUP_GIT_WORKTREE_DIR./data/gitLocal worktree directory
BACKUP_GIT_AUTHOR_NAMEObsidian SyncGit author name for backup commits
BACKUP_GIT_AUTHOR_EMAILobsidian-sync@localhostGit author email for backup commits

⁠Health Check

GET /health returns {"status":"ok"} with HTTP 200.

⁠Security

  • TLS: The server does not terminate TLS itself. Put it behind a reverse proxy (e.g. nginx, Caddy, Traefik) with a valid TLS certificate. Never expose it on a public network without TLS.
  • Auth token: The shared token is the only authentication mechanism. Use a strong random value and rotate it if compromised.
  • Data at rest: Vault data is stored unencrypted in SQLite. Secure the host and the DATA_DIR accordingly.
  • Git backup credentials: BACKUP_GIT_PASSWORD is used as a plain HTTPS password or personal access token. Use a token with minimal required permissions.

⁠Docker Images

This server is published as a multi-platform Docker image for linux/amd64 and linux/arm64.

Images are available from:

⁠Releasing

Create a release tag from a clean main branch:

bun run release patch
# or: bun run release minor
# or: bun run release major

The local release script computes the next semantic version from existing Git tags, creates the new X.Y.Z tag, and pushes it to GitHub.

The GitHub Actions release workflow then runs GoReleaser⁠ on that tag. GoReleaser installs dependencies, builds a bundled main.js, creates the GitHub release, and builds/publishes the Docker image to both Docker Hub and GHCR by copying only that file into the runtime image.

For a local dry run of the release pipeline:

goreleaser release --snapshot --clean

For a plain local image build without GoReleaser:

bun run build
docker build -t obsidian-crdt-sync-server:test .

⁠Versioning

This project uses Semantic Versioning⁠. Release tags use the plain X.Y.Z format and drive both GitHub releases and Docker image tags.

⁠Contributing

Pull requests are welcome. For larger changes, open an issue first, especially if the change affects the wire protocol, on-disk storage format, or release packaging.

⁠License

MIT⁠

Tag summary

Content type

Image

Digest

sha256:219cf3971…

Size

49.4 MB

Last updated

6 months ago

docker pull yusoltsev/obsidian-crdt-sync-server