-
Notifications
You must be signed in to change notification settings - Fork 0
Syncing
(added in v2.2.0)
SnipVault can keep one library in sync across several computers through a small server you host yourself (a homeserver, NAS, or spare PC). Each desktop app keeps its own local database and reconciles with the server, so your snippets are always available — even offline — and every machine converges on the same set.
Syncing is entirely opt-in and per-machine. With no server configured, SnipVault behaves exactly as before: a purely local library, no network, no account.
Every snippet has a stable id (a uuid) and a last-modified time, so the same snippet is recognised across machines. On each sync the app makes a single request that pushes its records and pulls the server's, and both sides converge:
- Both directions merge. Snippets that exist on only one side are copied to the other — the result is the union of everything.
-
Newest edit wins. If the same snippet was changed on two machines, the one with the most recent
updated_atis kept (the older edit is overwritten). Since v4.0.0, the overwritten version isn't lost: it's saved to that prompt's History, and after the sync a notice tells you how many prompts were updated from another device — so you can open History and recover the earlier text if you need it. - Deletes propagate. Deleting a snippet marks it as removed (a tombstone) rather than erasing it; that flag syncs, so the snippet disappears everywhere and can't be silently resurrected by a machine that still had a copy.
Sync runs automatically on app startup (when a server is configured) and on demand via Settings → Sync now. Between syncs you keep working against your local copy.
See Data Storage for the uuid/deleted schema and API and Commands for the /api/sync endpoint and the desktop sync commands.
- Open Settings (gear icon), or choose Connect to a sync server on the first-run screen of a fresh install.
- Enter the server URL (e.g.
http://192.168.1.50:3000) and the access token. - Test & save. The app verifies the server, stores it, and runs a first sync — pulling the server's snippets into this machine's local library.
Repeat on every machine with the same URL and token. To stop syncing, use Remove server in Settings; your local library is left untouched.
The server is the SnipVault web app in a container.
One command (v3.5.5) — for a single-user server with a generated token, no checkout needed:
curl -fsSL https://raw.githubusercontent.com/FranciszekRyszka/Snippet-Vault/main/install.sh | shinstall.sh pulls the prebuilt image, generates a strong token, writes a .env + docker-compose.yml into ./snipvault/, starts the container, and prints the URL and token to paste into the desktop app. Re-running is safe — it keeps your token and data and just pulls the latest image (that's also how you update). On a Portainer/Unraid host, add a Stack with the minimal image-based compose from docs/self-hosting.md instead.
Or with a full checkout (needed for TLS, multiple users, or building locally):
git clone https://github.com/FranciszekRyszka/Snippet-Vault.git
cd Snippet-Vault
cp .env.example .env # set SNIPVAULT_TOKEN to a long random value
docker compose up -dIt listens on port 3000 and stores its database in the snipvault-data volume. A prebuilt image is also published to ghcr.io/franciszekryszka/snippet-vault (see Continuous Integration).
Full instructions — a bare Node + systemd alternative, TLS via a reverse proxy, and security notes — are in docs/self-hosting.md in the repo.
By default a server is single-user: one SNIPVAULT_TOKEN guards one shared library. To let several people share the same server while keeping their snippets private to each of them, set SNIPVAULT_TOKENS instead — a comma-separated list of user:token pairs:
# in .env — one token per user, e.g. openssl rand -base64 32
SNIPVAULT_TOKENS=alice:ALICE_TOKEN,bob:BOB_TOKENEach user gets their own database file at data/users/<user>/snippets.db, keyed by their token. Isolation is structural — every request is routed to the caller's own file — so one user physically cannot read or sync another's data.
- Nothing changes in the desktop app — each person just enters the server URL and their own token in Settings → Sync server.
- If both
SNIPVAULT_TOKENSandSNIPVAULT_TOKENare set, the multi-user list wins. - Adding or removing a user is an
.envedit plus a restart. The./datavolume already persists every user's file. - With several people on one box, use HTTPS (see below) and give each user a strong, unique token.
The docker-compose.yml is set up so you can see the server's health and read its logs without extra configuration.
The container runs a built-in health check against /api/health (which also confirms the database is readable). Docker reports the result in docker ps under STATUS as (healthy) / (unhealthy):
docker ps
# ... snipvault ... Up 2 minutes (healthy) ...
# just the health state:
docker inspect --format '{{.State.Health.Status}}' snipvaultDetails of the check (interval 30s, a 20s start-up grace period, 3 retries):
- Because
/api/healthsits behind the token gate, the check sends the sameSNIPVAULT_TOKENfrom the container's environment. - It uses Node (always present in the image) rather than
curl/wget, which the slim runtime image doesn't include.
For richer, per-user monitoring, v3.0.0 adds a token-gated GET /api/status that returns the library size, last-write time, and server version (in multi-user mode it reflects the caller's own vault).
The app logs to stdout using Docker's json-file driver with rotation (max-size: 10m, max-file: 3), so logs stay bounded and are readable by any Docker log viewer:
docker logs -f snipvault # follow the logs
docker compose logs -f snipvault # same, via composeDozzle and similar web log viewers work out of the box — they read the Docker socket, so once running they'll list the snipvault container and stream its logs. docker-compose.yml includes an optional, commented-out dozzle service: uncomment it to run Dozzle alongside SnipVault, then open http://<this-host>:8080. (You typically run one Dozzle per host, so skip it if you already have one.)
Access is protected by a bearer token you choose (SNIPVAULT_TOKEN, or SNIPVAULT_TOKENS for multiple users). A token is required on every /api request, checked in constant time by proxy.ts — and in multi-user mode the whole list is scanned in full so timing can't reveal which token matched. Always set a token on a real deployment — with none set, a production server refuses every request rather than exposing the library.
Since v3.0.0, repeated failed auth attempts from one client are rate-limited with a 429 (a sliding window keyed by client IP) to blunt brute force on a weak token; valid clients are never throttled (tune via SNIPVAULT_RATELIMIT_MAX / SNIPVAULT_RATELIMIT_WINDOW_MS).
HTTPS is optional. By default the server runs on plain HTTP (port 3000) with no reverse proxy — a bare docker compose up -d is a fully working sync server, and on a trusted home LAN that's usually all you need. HTTPS is an opt-in extra, not a requirement.
To expose the server more widely — or once several users share it — you can terminate HTTPS in front. docker-compose.yml ships ready-to-enable, commented services for three reverse proxies — Caddy, nginx, and Traefik — so you can use whichever you prefer (Caddy and Traefik auto-provision Let's Encrypt certificates; nginx uses certs you supply). They're off unless you uncomment one; enable it, then point the app at the https:// URL. Details and setup steps for all three are in docs/self-hosting.md.
- Keep clocks roughly in sync. "Newest wins" compares each machine's clock; a badly-wrong clock could let a stale edit win. On a normal LAN this is a non-issue.
- Editing the same snippet on two offline machines before they next sync keeps the most recent version as the live one; the other edit is preserved in that prompt's History (since v4.0.0) rather than lost. Sync often to keep things tidy.
-
First launch of v2.2.0 upgrades the local database in place (adds the
uuid/deletedcolumns and backfills). This is automatic and lossless, but it means a v2.2.0 database shouldn't be opened by an older v2.1.0 build afterward. - History: v2.1.0 shipped a live "remote mode" (the app talked to the server directly, no local copy). v2.2.0 replaced it with the local-first two-way sync described here.
Using SnipVault
Development
Operations