title: “Self-Hosted Digital Garden: Obsidian + Live Sync + CouchDB + Quartz v4” date: 2026-04-14 description: “A fully self-hosted pipeline to publish Obsidian notes as a Quartz v4 digital garden using CouchDB and a custom sync script.” tags:

  • obsidian
  • quartz
  • couchdb
  • self-hosted
  • digital-garden

A digital garden is not a blog. It has no posts ordered by date, no polished articles written for an audience. It’s more like a public second brain — a living, evolving collection of notes, ideas, and links. The goal isn’t to publish finished thoughts; it’s to think in public.

I use Obsidian as my primary note-taking tool across all devices. I wanted my notes to be accessible as a website without having to manually export or copy anything. This is the pipeline I built to make that happen — fully self-hosted, no third-party sync services.


The Stack at a Glance

Obsidian (desktop / mobile)
  │
  │  obsidian-livesync plugin
  ▼
CouchDB  ←──────────────────── self-hosted on VPS
  │
  │  couch-sync (Node.js, _changes feed)
  ▼
content/  (markdown files)
  │
  │  Quartz v4 build
  ▼
public/  →  nginx  →  obsidian.myui.in
ComponentRole
ObsidianNote editor on all devices
obsidian-livesyncSyncs vault to/from CouchDB in real time
couch-syncWatches CouchDB change feed, writes markdown files
Quartz v4Builds a static site from the markdown files

Obsidian + obsidian-livesync

obsidian-livesync is a community plugin that replaces Obsidian’s native sync with a self-hosted CouchDB backend. It supports end-to-end encryption — notes are encrypted before leaving your device.

Setup in brief:

  1. Install Self-hosted LiveSync from Obsidian’s community plugin browser.
  2. Point it at your CouchDB instance (http://your-vps:5984, database obsidian).
  3. Enable end-to-end encryption with a passphrase — store it safely.
  4. Install the same plugin on every device; all sync through the same database.

obsidian-livesync does not store plain markdown in CouchDB. Each file is chunked and encrypted into leaf documents, with a parent document (named after the file, e.g. my-note.md) holding references to those chunks. This is efficient for sync but means external tools cannot read note content without the decryption key.

Deep dive: Obsidian + obsidian-livesync


CouchDB

CouchDB is a document database that speaks HTTP natively — every read, write, and change notification is a plain HTTP call. No drivers, no special clients.

Install on Debian/Ubuntu:

curl -fsSL https://couchdb.apache.org/repo/keys.asc | gpg --dearmor \
  | sudo tee /etc/apt/trusted.gpg.d/couchdb.gpg > /dev/null
echo "deb https://apache.jfrog.io/artifactory/couchdb-deb/ $(lsb_release -sc) main" \
  | sudo tee /etc/apt/sources.list.d/couchdb.list
sudo apt update && sudo apt install -y couchdb

The key feature for this pipeline is the _changes feed — a continuous HTTP stream that delivers a JSON line for every document write. couch-sync subscribes to this and reacts in real time with no polling.

Deep dive: CouchDB + couch-sync


couch-sync

couch-sync is a ~200-line Node.js script that bridges CouchDB and Quartz:

  1. Opens a persistent connection to _changes?feed=continuous.
  2. Filters for documents whose _id ends in .md.
  3. Writes a markdown file to content/ using the document’s extracted_text field.
  4. Schedules a debounced Quartz build (2-second delay).
  5. Auto-reconnects on disconnect.
function transform(doc) {
  return `---\ntitle: ${doc._id.replace(/\.md$/, "")}\n---\n\n${doc.extracted_text || ""}`
}

Setting published: false on a CouchDB document removes the corresponding file and triggers a rebuild — a lightweight way to unpublish without deleting.

Deep dive: CouchDB + couch-sync


Quartz v4

Quartz is a static site generator built for Obsidian markdown. It handles wikilinks, backlinks, graph views, tags, and full-text search out of the box.

npx quartz build reads all .md files from content/ and compiles a static site into public/. nginx then serves public/ at obsidian.myui.in — no upload or deploy step, every build is immediately live.

The graph view in the left sidebar is the most interesting part: every wikilink between notes becomes an edge. Pages that reference each other cluster together visually.

Deep dive: Quartz v4 + Deployment


End-to-End Flow

  1. Edit a note in Obsidian → obsidian-livesync pushes encrypted chunks to CouchDB.
  2. CouchDB emits a change event on _changes.
  3. couch-sync receives it, writes a .md file to content/.
  4. couch-sync fires a debounced npx quartz build.
  5. Quartz compiles content/ into public/.
  6. nginx serves the update instantly.

Total latency from saving in Obsidian to live on the web: ~5–10 seconds.


Key Gotchas

  • E2E encryption means couch-sync cannot read actual note content — extracted_text stays empty unless you disable encryption or run a separate decryption step.
  • Hardcoded credentials in couch-sync (admin:admin) — always replace with a strong password and use environment variables.
  • The debounce coalesces rapid saves into one build. For bulk imports, pause couch-sync first.
  • RemoveDrafts silently excludes any note with draft: true or publish: false — check frontmatter if a page isn’t appearing.