Files
homelab/ansible/roles/obsidian_headless
JARVISandClaude Opus 5.5 15aeb8e222 spaceship-earth: per-host Multica PAT, root LV growth, headless Obsidian (WDWL-22)
- provision-agent-host.yml: multica_pat now comes from
  vault_multica_pats[inventory_hostname_short], one daemon-<host> token per
  host. A pre_task asserts the key exists (never prints the value) so a
  missing entry fails by host name instead of as a no_log "censored".
- provision-wong-host.yml: spaceship-earth only. Grows the root partition,
  PV and LV/filesystem with growpart + community.general.lvg/lvol;
  idempotent (second run changed=0). Then applies obsidian_headless.
- roles/obsidian_headless: Obsidian's official headless Sync client
  (obsidian-headless 0.0.14) as system user obsync under a sandboxed
  systemd unit with UMask=0077. Vault at /srv/obsidian/vault: everpure/
  and wip/ obsync-only, inbox/ granted to multica via access + default
  ACLs, vault root traverse-only. Verifies the isolation as multica.
  Sign-in to Obsidian Sync stays manual (see the role README).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:41:54 -05:00
..

obsidian_headless

Runs Obsidian's official headless Sync client (obsidian-headless, command ob, open beta) as a dedicated unprivileged user under a systemd unit. It lays out the vault folder so that other local users reach only the folders granted to them.

Written for spaceship-earth (WDWL-22). Wong's daemon user (multica) may read and write inbox/ and nothing else. everpure/ and wip/ are obsync only. Entry point: playbooks/provision-wong-host.yml.

What it does

  1. Creates the system user obsync, with a 0700 home in /var/lib/obsync. That home holds the Obsidian account token and per-vault sync state.

  2. Installs the pinned obsidian-headless into that user's npm prefix and links ob into /usr/local/bin. Node.js is not installed here. The role asserts that the runtime multica_agent_host installs is present and is at least version 22.

  3. Lays out the vault folder and its permissions:

    Path Mode ACL
    /srv/obsidian/ 0710 obsync user:multica:--x
    /srv/obsidian/vault/ 0710 obsync user:multica:--x, so multica can traverse but not list
    vault/everpure/, vault/wip/ 0700 obsync none
    vault/inbox/ 0770 obsync user:multica:rwx, plus the same as a default entry

    On a directory with an ACL, the mode's group bits are the ACL mask. A chmod 0700 would therefore void every named entry, which is why the shared paths use 0710 and 0770. The owning group is obsync's private group, so those bits grant nobody anything.

  4. Installs obsidian-sync.service (User=obsync, UMask=0077, sandboxed) and enables it. It is started only once a vault has been set up. Condition*= lines keep it inert until then, including across reboots.

  5. Verifies the isolation as the users themselves:

    • multica writes, reads and deletes in inbox/.
    • A folder and file created by obsync under umask 0077 (the way Sync creates them) stay readable and writable by multica.
    • multica is refused both listing the vault root and listing or writing everpure/ and wip/.

Do modes and ACLs survive Sync?

Obsidian Sync carries no Unix modes or ACLs. Files are created locally by obsync, so their permissions come from this host, not from the remote:

  • In inbox/, the default ACL applies and the umask is ignored, so new content is granted to multica.
  • Everywhere else, UMask=0077 applies, so new content is private to obsync. That covers any new top-level folder and .obsidian/.
  • If Sync deletes and recreates inbox/ itself, the recreated folder is private and multica loses access. The failure is closed, not open, and re-running the play restores the grant.

Manual step: sign in and set up the vault (once per host)

The role never handles the Obsidian account. Run these as obsync; -H makes HOME point to /var/lib/obsync:

sudo -u obsync -H ob login
sudo -u obsync -H ob sync-list-remote
sudo -u obsync -H ob sync-setup --vault "<vault name>" \
     --path /srv/obsidian/vault --device-name spaceship-earth
sudo systemctl start obsidian-sync
journalctl -u obsidian-sync -f

Re-running the play after this starts the unit as well. Do not also run desktop Obsidian Sync on this host: Obsidian warns that two Sync clients on one device conflict.

Tags

obsidian_user, obsidian_install, obsidian_layout, obsidian_service, obsidian_verify. The play itself is tagged obsidian.