Daemon CLI reference
Complete reference for the obsidian-remote-server binary. The plugin invokes this for you on every connect (see Plugin auto-deploy); this page is for operators running it manually under systemd, in containers, or for debugging.
Synopsis
obsidian-remote-server --vault-root=<path> [--socket=<path>] [--token-file=<path>] [--verbose]
obsidian-remote-server --version
Flags
Required
--vault-root <path>
Absolute path of the vault directory on this host. The daemon refuses to start if:
- The flag is missing or empty
- The path does not exist
- The path is not a directory
The daemon will reject any RPC operation whose resolved path escapes this root (PathOutsideVault error, code -32015).
obsidian-remote-server --vault-root=/home/me/notesRelative paths are accepted but resolved to absolute via filepath.Abs at startup. Symlinks in the vault root path are followed.
Optional
--socket <path>
Unix socket the daemon listens on. Default: <state-dir>/server.sock (state-dir is normally ~/.obsidian-remote/).
The daemon:
- Removes any existing file at this path (cleanup of dangling sockets from a crashed prior run)
- Creates the parent directory with mode
0700if missing - Binds the Unix socket
- Chmods the socket to
0600so only the daemon’s user can connect
obsidian-remote-server --vault-root=/srv/vault --socket=/srv/vault-state/server.sock--token-file <path>
Path the daemon writes its session token to at startup. Default: <state-dir>/token.
The token is 32 random bytes (hex-encoded → 64 chars), generated via crypto/rand. The file is written with mode 0600 and removed when the daemon exits cleanly. Plugins read this file via SFTP and present it on the auth RPC.
--verbose
Enable debug-level logging to stderr (slog text format). Without this, logging is discarded entirely (io.Discard).
The plugin’s auto-deploy passes --verbose so the daemon’s stderr ends up in ~/.obsidian-remote/server.log (the spawn redirects stderr → that log file). For systemd-managed setups, decide based on whether you want noise in journalctl.
--version
Print the daemon version (one line) and exit 0. Used by plugin-side diagnostics + script health checks. Bypasses all other flags.
obsidian-remote-server --version
# → 0.1.0State directory layout
When --socket and --token-file are not given, both default into <state-dir>. State-dir resolves to:
| OS | Path |
|---|---|
| Linux / macOS / BSD | $HOME/.obsidian-remote/ |
| Windows | (daemon doesn’t run on native Windows; see Server overview) |
So a typical invocation with all defaults plants:
~/.obsidian-remote/
server.sock # the Unix socket the daemon listens on (mode 0600)
token # 32-byte hex token (mode 0600); auto-removed on clean exit
You can override either path independently — useful for multi-vault setups (one socket per vault on the same OS user; see Multi-user hosting).
Invocation patterns
Manual smoke test
~/.obsidian-remote/server \
--vault-root=$HOME/notes \
--verbose \
> ~/.obsidian-remote/server.log 2>&1 &
disownAfter this, the plugin’s reuse probe will attach without redeploying. To stop:
pkill -f obsidian-remote-serverSame as the plugin’s auto-deploy
nohup ~/.obsidian-remote/server \
--vault-root=/home/pi/notes \
--socket=/home/pi/.obsidian-remote/server.sock \
--token-file=/home/pi/.obsidian-remote/token \
--verbose \
> /home/pi/.obsidian-remote/server.log 2>&1 < /dev/null &Reverse-engineered from ServerDeployer. The plugin uses nohup … < /dev/null & so the daemon survives the SSH session that spawned it.
Under systemd (per-user)
See the full unit at systemd-managed daemon. Key fragment:
ExecStart=/usr/local/bin/obsidian-remote-server \
--vault-root=%h/notes \
--socket=%h/.obsidian-remote/server.sock \
--token-file=%h/.obsidian-remote/token \
--verbose%h expands to the user’s home; lets one unit file work for any user via systemctl --user.
Multi-vault on the same user
Different daemons need different sockets:
# Daemon for the work vault
~/.obsidian-remote/server \
--vault-root=$HOME/work-notes \
--socket=$HOME/.obsidian-remote/work.sock \
--token-file=$HOME/.obsidian-remote/work.token &
# Daemon for the personal vault
~/.obsidian-remote/server \
--vault-root=$HOME/personal-notes \
--socket=$HOME/.obsidian-remote/personal.sock \
--token-file=$HOME/.obsidian-remote/personal.token &In the plugin profile for each, set the matching socket + token paths. See multi-vault recipe.
Exit codes
| Code | Meaning |
|---|---|
0 | Clean shutdown (SIGINT / SIGTERM received and listener drained, or --version printed) |
1 | Runtime error after startup (cannot bind socket, token write failed, vault root vanished, etc.) — message goes to stderr |
2 | Argument parse error (missing required flag, invalid value) — flag.ContinueOnError surfaces this |
Signal handling
The daemon installs a SIGINT + SIGTERM handler that closes the listener (which unwinds Serve), removes the socket file + token file, then exits 0. This is graceful shutdown.
kill -9 (SIGKILL) skips the cleanup. The next daemon start will find the stale socket file at <socket> and the existing handler removes it before binding fresh — so a hard kill doesn’t permanently jam the path.
Environment variables
The daemon does not read any environment variables for configuration — all config goes through CLI flags. Things that DO affect the daemon implicitly:
| Env var | Effect |
|---|---|
HOME | Determines the default state-dir ($HOME/.obsidian-remote/) when --socket / --token-file are not given |
TZ | Affects slog’s timestamp output when --verbose is on; otherwise irrelevant |
The plugin’s environment (Obsidian’s process.env) is irrelevant to the daemon — they’re separate processes on different hosts.
What the daemon does NOT do
- It does not detach from its terminal on its own. Use
nohup … &or run under systemd to background it. (Plugins do this for you.) - It does not rotate its own log file. When run via the plugin, stdout+stderr are piped to
~/.obsidian-remote/server.logand that file truncates only on daemon restart. Under systemd, journalctl handles retention. - It does not bind a TCP port. Unix socket only — see Firewall, ports & NAT.
- It does not retry-on-fail. Process-level supervision (systemd
Restart=on-failure, the plugin’s reuse-probe-then-redeploy fallback) handles that.
See also
- Plugin auto-deploy — what the plugin does to invoke the daemon
- systemd unit — production unit-file template
- Release & deploy pipeline — how the binary is built + signed
- API overview — the JSON-RPC the daemon speaks once it’s up