Set via OBSIDIAN_VAULT_PATH environment variable (e.g. in ~/.hermes/.env).
If unset, defaults to ~/Documents/Obsidian Vault.
Always quote the path because vault paths often contain spaces.
VAULT="${OBSIDIAN_VAULT_PATH:-$HOME/Documents/Obsidian Vault}"
VAULT="${OBSIDIAN_VAULT_PATH:-$HOME/Documents/Obsidian Vault}"
cat "$VAULT/Note Name.md"
VAULT="${OBSIDIAN_VAULT_PATH:-$HOME/Documents/Obsidian Vault}"
find "$VAULT" -name "*.md" -type f
VAULT="${OBSIDIAN_VAULT_PATH:-$HOME/Documents/Obsidian Vault}"
# By filename
find "$VAULT" -name "*.md" -iname "*keyword*"
# By content
grep -rli "keyword" "$VAULT" --include="*.md"
VAULT="${OBSIDIAN_VAULT_PATH:-$HOME/Documents/Obsidian Vault}"
cat > "$VAULT/New Note.md" << 'ENDNOTE'
# Title
Content here.
ENDNOTE
VAULT="${OBSIDIAN_VAULT_PATH:-$HOME/Documents/Obsidian Vault}"
echo "
New content here." >> "$VAULT/Existing Note.md"
Obsidian links notes with [[Note Name]] syntax. When creating notes, use these to link related content.
For multi-machine or agent-assisted workflows, a strong default is to treat the vault as a private git repo.
Recommended pattern: - keep the vault in a private repo - pull before automated edits if multiple machines/jobs may write - commit meaningful ingestion batches - optionally combine with Obsidian Git or Obsidian Sync for local devices
This works especially well with llm-wiki and scheduled Hermes jobs.
If the vault lives on a VPS, there are three main access patterns.
Best UX and lowest operational risk: - keep the vault on the VPS as plain markdown/git - sync it to your laptop/phone via git or Obsidian Sync - open it in native Obsidian locally
Use this when you want the full Obsidian experience without remote desktop complexity.
If you specifically need the actual Obsidian desktop UI at a URL, the practical server pattern is:
- Obsidian desktop app running on the VPS
- Xvfb for a headless X display
- x11vnc to expose that display on localhost
- noVNC as the browser client
- nginx reverse proxy + auth in front
Concrete VPS deployment proven on Alex's box:
- internal display: :88
- internal VNC: 127.0.0.1:5988
- internal noVNC: 127.0.0.1:6088
- public URL: https://obsidian.apps.poofc.com
- nginx behavior: / should redirect to /vnc.html?autoconnect=1&resize=remote
- systemd user services:
- obsidian-xvfb.service
- obsidian-openbox.service
- obsidian-x11vnc.service
- obsidian-novnc.service
- obsidian-app.service
- vault root: /home/avalon/obsidian-vaults/
Useful checks:
systemctl --user status obsidian-xvfb obsidian-openbox obsidian-x11vnc obsidian-novnc obsidian-app
curl -I -u admin:*** https://obsidian.apps.poofc.com/
curl -I -u admin:*** https://obsidian.apps.poofc.com/vnc.html
curl -I http://127.0.0.1:6088/
curl -I http://127.0.0.1:6088/vnc.html
ss -tlnp | grep -E ':5988|:6088'
High-level stack:
Obsidian AppImage
-> Xvfb :99
-> x11vnc or xpra
-> noVNC/websockify
-> nginx https://notes.example.com
This is feasible, but heavier than local sync. Use it only if the user explicitly wants the real Obsidian UI in-browser.
If the goal is mainly viewing/searching notes from a URL, publish the markdown with a static or lightweight web layer instead of remote-desktoping Obsidian. This is the preferred answer when Alex says the noVNC/desktop route feels clunky or old-school, especially if the desired feature is the graph viewer.
Strong default: Quartz
- Open-source Quartz transforms Obsidian-style Markdown vaults into a browser-native knowledge site.
- Supports Obsidian-flavored Markdown, backlinks, search, and graph view.
- Good self-hosted replacement for noVNC -> Linux desktop -> Obsidian when the route should feel like a web app.
- Use Obsidian as the local/editor file format, not as the hosted UI.
Alternatives: - Logseq if the user wants a different open-source knowledge product/workflow, but clean self-hosted web deployment can still be awkward. - Foam is more VS Code workflow than clean web UI. - Custom app-specific graph viewer if editing/mobile/Hermes-native features matter more than quick setup.
Concrete deployment from the Obsidian/noVNC replacement session:
- App path: /home/avalon/apps/obsidian-quartz
- Public URL: https://obsidian.apps.poofc.com
- Quartz server port: 4022
- Source vaults: /home/avalon/obsidian-vaults/main, astrology-wiki, ai-coding-wiki
- PM2 processes:
- obsidian-quartz: lightweight Node static server serving Quartz public/
- obsidian-quartz-sync: periodic sync/build loop that copies source vaults into Quartz content/ and rebuilds only when vault source hash changes
- Nginx: keep basic auth; proxy obsidian.apps.poofc.com to 127.0.0.1:4022; remove the old / -> /vnc.html?autoconnect=1&resize=remote redirect.
Important implementation details:
1. Copy source vaults into Quartz content/; do not point Quartz directly at mutable production vaults if you want a safe build boundary.
2. Generate a root content/index.md linking vault indexes, e.g. [[ai-coding-wiki/index|Ai Coding Wiki]].
3. Set quartz.config.ts:
- pageTitle: "Poof Obsidian Graph"
- baseUrl: "obsidian.apps.poofc.com"
- analytics: null
- ignore .obsidian and .git
4. Remove default Quartz footer links in quartz.layout.ts if this should feel like Alex's app, not Quartz docs.
5. Disable Plugin.CustomOgImages() on the VPS unless explicitly needed — it made a tiny ~20-note build take ~9 minutes; with it disabled, the build took seconds.
6. Prefer a static server for public/ over quartz build --serve --watch in production. The Quartz dev server can hang curls and spawns websocket/watch behavior that is unnecessary behind nginx.
7. If serving Quartz with a custom/static Node server, support Quartz's extensionless note routes. Quartz emits note pages as some/path.html, while internal links and user-facing URLs are often /some/path. Resolve path.html before falling back to path/index.html; otherwise notes exist in public/ but deep links 404.
8. For multi-vault/wiki indexes, surface newly ingested raw/source records directly in the vault index.md, not only via query/entity pages. If the first pass only saved provenance/transcripts and did not synthesize concept/comparison notes, state that explicitly so the hosted vault doesn't look empty or misleading.
9. Use a hash/state file for the vault sync loop so it does not rewrite content/ every minute; otherwise Quartz watch/dev server can repeatedly rebuild.
Verification checklist:
cd /home/avalon/apps/obsidian-quartz
./scripts/sync-vaults.py
npx quartz build -d content -o public
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4022/
curl -s -o /dev/null -w '%{http_code}\n' -u admin:SecurePass123! https://obsidian.apps.poofc.com/
curl -s -o /dev/null -w '%{http_code}\n' https://obsidian.apps.poofc.com/ # should be 401 while basic auth is enabled
Reference: references/alex-quartz-vps.md captures session-specific deployment details, the direct SNI/socket verification snippet for when public curl hangs, Prettier ignore details for deployment scripts, and the GitHub workflow-token push pitfall.
Reference: references/quartz-static-routing.md captures the custom static-server pitfall where Quartz-generated path.html note pages 404 at extensionless /path URLs unless the server tries ${file}.html before index.html fallback.
For VPS deployments, prefer: 1. local Obsidian + sync for full native editing UX 2. Quartz / published markdown graph site for browser-native viewing/searching/graphing 3. custom graph viewer if Alex wants mobile-first editing or Hermes-native graph features 4. noVNC/xpra-hosted Obsidian UI only as fallback/emergency when the true desktop UI is required
http://127.0.0.1:6088/ often returns a directory listing from the web root rather than the actual client. If the public URL shows Directory Listing for /, nginx is healthy but the entry route is wrong; add an nginx redirect from / to /vnc.html?autoconnect=1&resize=remote and verify both / and /vnc.html with curl -I.public/foo/bar.html exists but /foo/bar returns 404, the static server is resolving extensionless routes incorrectly. Patch the server to try ${file}.html before file/index.html, restart PM2, and verify several deep note URLs with authenticated public curls.