racoon44 downloadsLive two-way sync of your vault with a folder on your own server over SSH and SFTP. Works on Windows, Linux and Android.
Live two-way sync of your Obsidian vault with a folder on your own server — over plain SSH. No cloud, no subscription, no third party: just your notes, your devices and your server.
Features · Screenshots · How it works · Quick start · Server setup · Installation · Settings · Disclosures · Troubleshooting · FAQ
ssh does, encrypts stored passwords and keys.
[ laptop ] ──┐
├── SSH/SFTP ──► [ your server: /path/to/vault ] ◄── SSH (through a small relay) ── [ phone ]
[ desktop ] ─┘
.obsidian/plugins/syncher/state.json) that remembers what
each file looked like at the last sync. Comparing then with now on both sides tells exactly who changed what.Hidden files and folders (names starting with a dot, such as .obsidian, .trash, .git) are never synced:
every device keeps its own Obsidian settings.
[!NOTE] Why a relay for phones? Obsidian on Android does not let plugins open network connections of their own, so a phone cannot talk SSH directly. The plugin sends the very same encrypted SSH stream through a WebSocket to a tiny relay next to your SSH server, and the relay just passes the bytes on. The relay never sees your data unencrypted, and the plugin still checks your server's key. Computers do not need the relay at all.
| # | What | Where | Time |
|---|---|---|---|
| 1 | Prepare the server: a folder, an SSH key, (for phones) the relay | server | 5 min |
| 2 | Install the plugin | each device | 2 min |
| 3 | Fill in the settings and press Test connection | each device | 2 min |
That's it — from then on it syncs by itself.
You need a computer that is always on and runs an SSH server (OpenSSH). A Linux server, a NAS, a VPS or a
Raspberry Pi are all fine. You must be able to log in to it with ssh.
Log in to the server and create an empty folder. One folder = one vault.
mkdir -p ~/vaults/notes
Write down the full path, you will need it later. To see it, run cd ~/vaults/notes && pwd
— it prints something like /home/<your user>/vaults/notes.
A key is a file that lets the plugin log in without a password. Do this on your computer, not on the server.
ssh-keygen -t ed25519 -f "$env:USERPROFILE\.ssh\syncher"
<user> and <server>; you will be asked for your server password once):type "$env:USERPROFILE\.ssh\syncher.pub" | ssh <user>@<server> "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
ssh -i "$env:USERPROFILE\.ssh\syncher" <user>@<server> must log you in without the server password.ssh-keygen -t ed25519 -f ~/.ssh/syncher # press Enter at every question
ssh-copy-id -i ~/.ssh/syncher.pub <user>@<server>
ssh -i ~/.ssh/syncher <user>@<server> # must log in without the server password
You now have two files: syncher (private — never share it) and syncher.pub (public, already on the server).
[!TIP] No key? The plugin can also log in with the server password, if your server allows password logins.
Skip this if you only sync computers. On the server, from a copy of this repository:
git clone https://github.com/tequrity/syncher.git
cd syncher
sudo sh server/install-relay.sh
You should see Syncher relay is running: ws://<this server>:8022 -> 127.0.0.1:22.
The relay needs only Python 3 and systemd. If the script says a firewall is active, run the command it prints
to open port 8022 (or open it only to your home network / VPN).
| Task | Command |
|---|---|
| Install (listens on 8022, forwards to the local SSH on port 22) | sudo sh server/install-relay.sh |
| SSH is on another port / use another relay port | sudo sh server/install-relay.sh --port 8022 --target 127.0.0.1:2222 |
Reinstall or update (after git pull, or to change options) |
run the install command again |
| Remove completely (stops it, disables it, deletes its files) | sudo sh server/install-relay.sh --uninstall |
| Is it running? | systemctl status syncher-relay |
| Live log (shows each phone connecting) | journalctl -u syncher-relay -f |
If you opened port 8022 in a firewall, close it again after removal (for example sudo ufw delete allow 8022/tcp).
Encrypted wss:// — recommended if the relay is reachable from the internet: start the relay with
--cert fullchain.pem --key privkey.pem (a certificate the phone trusts, e.g. Let's Encrypt — phones reject
self-signed ones) or put it behind Caddy/nginx with HTTPS, and enter wss://… as the relay address in the plugin.
An equivalent alternative to this relay is websockify 8022 127.0.0.1:22.
Syncher is not in the Obsidian community store yet. Pick one of the two ways below.
tequrity/syncher, press Add plugin.Open the latest release and download
main.js, manifest.json and styles.css.
Find your vault folder (the folder you opened in Obsidian) and inside it the hidden folder .obsidian/plugins.
Create a folder named syncher there and put the three files into it:
<your vault>/.obsidian/plugins/syncher/main.js
<your vault>/.obsidian/plugins/syncher/manifest.json
<your vault>/.obsidian/plugins/syncher/styles.css
Documents/<vault name> in the internal storage.Restart Obsidian → Settings → Community plugins → Turn on community plugins (if asked) → press the refresh button ⟳ next to Installed plugins → switch Syncher on.
git clone https://github.com/tequrity/syncher.git && cd syncher
npm install
npm run release # builds main.js and copies it to dist/syncher
node scripts/install.mjs "<path to your vault>"
Open Settings → Syncher (at the bottom of the left list). At the very top you see Syncher v… — the installed version.
/home/<user>/vaults/notes.22.syncher, not syncher.pub; on Windows it is in C:\Users\<you>\.ssh\) → Save.
The key is stored encrypted on this device; the plugin never reads files outside your vault.
The file picker hides the .ssh folder? Type %USERPROFILE%\.ssh (Windows) or ~/.ssh (Linux) into its
address bar, or paste the key text into the big field instead.<user> via <server>:22, folder … is writable."syncher) to the phone (USB cable, a message to yourself, a cloud drive…).ws://<server address>:8022).Hello.md and type something..trash, as set in
Settings → Files and links → Deleted files).| Situation | Result |
|---|---|
| You edit a note | Sent to the server a moment after you stop typing; other devices get it within seconds. |
| You create a note or folder | Appears on the server and on all devices. |
| You rename or move a note or folder | Renamed/moved everywhere (not downloaded again). |
| You delete a note or folder | Deleted on the server and on all devices — unless a device has Permanent save on. |
| Another online device deletes a note | Pop-up: "Device ⟨name⟩ deleted file ⟨file⟩". No pop-up for changes made while you were offline. |
| Two devices edit the same note | Last writer wins: the later edit is kept. |
| One device edits a note another one deleted | The edit wins; the note comes back with the new content. |
| A device was offline | On reconnect both sides are compared and merged. |
| A file cannot be synced (e.g. a name Windows does not allow) | It is skipped and listed under Not synced in the settings; everything else keeps syncing. |
Permanent save is a switch you set per device. It means: "on this device the sync never deletes anything, it only adds and updates."
sync_ignore list
(.obsidian/plugins/syncher/sync_ignore.json, also shown in the settings), so it is not uploaded again and
does not come back on the other devices.note.md → note-1.old.md (then -2.old, -3.old, …) and stays in sync_ignore; the new file syncs normally.sync_ignore, re-reads all files and uploads everything that was kept
(including the *.old files) as new — so they reappear on all devices.| Setting | What it does |
|---|---|
| Remote folder | Full path of the vault folder on the server (~/… works too). Created if missing. |
| Server address | Host name or IP of the SSH server. |
| SSH port | Default 22. Not used on phones (they go through the relay). |
| SSH user | Login on the server. |
| SSH password | Only if there is no key or the server also asks for a password. Stored encrypted. |
| SSH key → Import key… | Imports your private key once (file picker or pasted text); stored encrypted on this device. |
| Key passphrase | If the key is protected with a passphrase. Stored encrypted. |
| Connection method | Computers: Direct SSH (normal) or Through the relay (to test the relay from a computer). |
| WebSocket relay URL | Shown when the relay is used. Empty = ws://<server address>:8022; or wss://…. |
| Device name | Shown to the other devices, e.g. in deletion pop-ups. Defaults to Desktop-xxxx / Android-xxxx; give it a friendly name like "Laptop". |
| Permanent save | See above. |
| Auto-sync | Connect on start and sync every change. |
| Check server every (seconds) | How often to look for changes made by other devices (default 3). |
| Delay after typing (ms) | How long to wait after the last keystroke before sending (default 800). |
| Full re-scan every (minutes) | Safety net for missed events (default 15; 0 = only on connect). |
| Exclude patterns | Paths not to sync, one per line, e.g. Private/** or *.tmp. |
| Deletion pop-ups | Turns the "Device … deleted file …" pop-ups on or off. |
| Test connection | Checks everything a sync needs: connection, server key, login, SFTP, the remote folder and write access. |
| Trusted server key | The server key remembered on first connect. Reset only if the server was really reinstalled. |
| Not synced | Items that could not be synced and why (appears only when there are any). |
| Devices seen on the server | All devices with their plugin version and online state; ⚠ marks a device running another version. |
On first start the plugin creates .obsidian/plugins/syncher/syncher.config.json:
{
"remoteDir": "",
"host": "",
"port": 22,
"username": "",
"relayUrl": ""
}
@noble
crypto libraries), with modern algorithms only: curve25519 / ECDH key exchange, ed25519 / ECDSA / RSA-SHA2 keys,
chacha20-poly1305 and AES-GCM/CTR ciphers, and "strict KEX" protection against the Terrapin attack..ppk keys first (PuTTYgen → Conversions → Export OpenSSH key).data.json, so a copied data.json is useless on another device.wss://, or allow port 8022 only from your network / VPN.As required by the Obsidian developer policies:
ws://<server address>:8022 on a phone). It sends your vault
files there and nowhere else. No other server is ever contacted.Desktop-xxxx / Android-xxxx with a random suffix.| Message / symptom | What to do |
|---|---|
| fill in server address, user and remote folder | Fill in those three fields (or the config file). |
| SSH keys are no longer read from files on disk | You updated from an older version that used a key file: press Import key… once and pick the same key. |
| the SSH key is encrypted / wrong SSH key passphrase | Enter the (correct) passphrase in Key passphrase. |
| this is not a usable SSH private key | You picked the .pub file or a PuTTY .ppk; pick the private OpenSSH key. |
| authentication failed | Is the public key in ~/.ssh/authorized_keys on the server? Is the user right? |
| SERVER KEY CHANGED | If the server was really reinstalled, press Reset next to Trusted server key. Otherwise do not connect — something is wrong. |
| relay … is not reachable (phone) | Is the relay running (systemctl status syncher-relay)? Is port 8022 open? Is the address right (empty = ws://<server>:8022)? Test from a computer: Connection method → Through the relay → Test connection. |
| N item(s) could not be synced | Everything else is synced; see Not synced in the settings. Usual causes: a name with * " \ < > : | ? (not allowed on Windows/Android — rename it on the device that created it), two files differing only in letter case (Note.md and note.md are one file on Windows/Android — rename one), a server folder without read permission. |
| A file does not appear on another device | Press Sync now. Hidden files (starting with a dot) and excluded patterns are not synced by design. |
| Another device shows ⚠ in Devices seen on the server | It runs another plugin version — update it and restart Obsidian there. |
| Anything else | Desktop: Ctrl+Shift+I → Console shows messages starting with Syncher:. |
Only for phones. Computers connect to SSH directly.
It is built the same way as on Android and should work through the relay, but it has not been tested on iOS yet.
No. The only places are your devices and the folder on your server. The plugin keeps some bookkeeping in a hidden
.syncher folder inside the server folder (device heartbeats, a change journal, temporary upload files).
Yes: use one server folder per vault and set the matching Remote folder in each vault.
Please don't. Two sync tools on the same vault undo each other's deletions and fight over renames.
The plugin was renamed to Syncher (the Obsidian directory does not allow names containing parts of "Obsidian").
Install Syncher next to it and enable it: on its first start it takes over the old settings, sync base and
encrypted passwords, disables the old copy (you can then delete it in Settings → Community plugins), and renames
the old .obsyncher metadata folder on the server. If you used a key file, press Import key… once.
A relay installed with the old script is replaced automatically when you run sudo sh server/install-relay.sh again.
BRAT updates the plugin automatically. By hand: replace the three files with the ones from the latest release and restart Obsidian. The version shown at the top of the plugin settings tells you which one is running; see CHANGELOG.md for what changed.
npm install
npm run build # type-check + bundle main.js
npm run release # build + copy to dist/syncher (checks that all version numbers match CHANGELOG.md)
npm test # unit tests + integration tests against a real OpenSSH server (skipped when none is running)
npm run e2e # end-to-end test inside a real Obsidian (set SYNCHER_OBSIDIAN to its executable)
test/sshd/start-wsl-sshd.sh <keys dir> [port]
(SYNCHER_TEST_SSH=host:port:user, SYNCHER_TEST_KEYS, SYNCHER_TEST_WS for the relay test).manifest.json, package.json and versions.json, add a CHANGELOG.md section,
then push a tag equal to the version — GitHub Actions builds and publishes the release.Project layout: src/ssh — SSH/SFTP client, src/sync — sync engine, src/*.ts — Obsidian plugin layer,
server/ — relay and its installer, test/ — tests, docs/screenshots — images used here.
MIT © Mr.Racoon