Feat/obsidian livesync #5

Merged
darman merged 2 commits from feat/obsidian-livesync into master 2026-08-28 05:16:37 +02:00
Owner
No description provided.
darman added 2 commits 2026-08-28 05:13:32 +02:00
Adds services/dev/obsidian-livesync.nix — CouchDB 3 from the native
nixpkgs module, tuned as the backend for the Self-hosted LiveSync plugin
— and publishes it as notes.mgaction.town through neptun.

It goes out over the public reverse proxy rather than staying on the LAN
because Obsidian's mobile apps refuse cleartext HTTP and *.jupiter.sol
cannot hold a publicly trusted cert. That makes the hardening load-bearing
rather than decorative:

  - require_valid_user in both [chttpd] and [chttpd_auth], so nothing
    answers unauthenticated on the open internet;
  - neptun's vhost matches on CouchDB's own naming rule (system endpoints
    all begin with `_`, user databases never can), so Fauxton, /_all_dbs
    and /_node/_local/_config — which rewrites the server config given
    admin credentials — 404 at the proxy while any number of per-vault
    databases pass. Verified against both sets of paths with caddy run
    against a stub backend;
  - the plugin's own E2EE carries the actual confidentiality: jupiter only
    ever stores ciphertext. Its passphrase is deliberately NOT in sops —
    it never leaves the clients, and pairing it with the server credential
    would defeat the point.

flush_interval -1 is required, not tuning: replication rides a continuous
_changes feed that caddy would otherwise buffer into a stall.

Storage sits on the array with RequiresMountsFor, since a CouchDB that
starts without /mnt/data would create an empty database on the eMMC and
LiveSync would replicate that emptiness back to every client. Logs go to
journald rather than the unrotated /var/log/couchdb.log, for the same
29G-eMMC reasons as the rest of jupiter.

The admin password reaches CouchDB as an [admins] ini fragment via
extraConfigFiles; services.couchdb.adminPass would have rendered it into
the world-readable store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TLN5nkLBtCciD3ZnUwtw2b
Gives the Hermes agent a real directory of markdown for the luna_wiki
vault, at /var/lib/livesync-bridge/vault and mounted into her container at
/opt/data/vault (inside HERMES_WRITE_SAFE_ROOT, so she can write, not only
read). Obsidian itself is an Electron GUI with no headless mode, and an
agent wants files rather than an app.

livesync-bridge is Deno, not packaged, and publishes no image — upstream
ships only a `build: .` compose file. So it comes in as a pinned non-flake
input and runs under systemd. Two things that are not obvious:

  - The source is COPIED to a fixed path rather than run from /nix/store.
    Deno keys localStorage — where the bridge records per-file sync state —
    by the main module's origin. Verified by running one source tree from
    two paths against a single DENO_DIR: two origin directories appear. Run
    from the store, every input bump would silently reset both peers to a
    full rescan.
  - It runs as uid 986/gid 983, the same identity the hermes container
    uses. Two uids in a shared group only works while every file stays
    group-writable, and one 0644 file dropped by the agent would stall sync
    on that path.

Talks to CouchDB over the tailnet (jupiter.orbit.sol:5984), so neptun's
vhost, its TLS and its path allowlist are all out of the picture.

Verified before deploying: `deno check` passes on nixpkgs' 2.8.3 (upstream
pins 2.6.9), and the bridge starts, reads LSB_CONFIG, detects a file and
writes its health heartbeat. Both directions confirmed working on mars
afterwards.

Credentials are currently the `obsidian` admin account and the personal
vault's passphrase, which means mars can decrypt every vault database and
not just luna's. Deliberate reuse of what existed; hosts/mars/secrets.nix
records the two independent ways to narrow it.

⚠️ Upstream has three open, unanswered issues on the storage->couchdb
direction (#50, #23, #46) and all fail silently — the log reports the
upload and the database is never updated. Do not treat this directory as
durable storage for anything luna cannot regenerate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TLN5nkLBtCciD3ZnUwtw2b
darman merged commit 45e08e35a2 into master 2026-08-28 05:16:37 +02:00
darman deleted branch feat/obsidian-livesync 2026-08-28 05:16:37 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: darman/homelab#5