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
| Component | Role |
|---|---|
| Obsidian | Note editor on all devices |
| obsidian-livesync | Syncs vault to/from CouchDB in real time |
| couch-sync | Watches CouchDB change feed, writes markdown files |
| Quartz v4 | Builds 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:
- Install Self-hosted LiveSync from Obsidian’s community plugin browser.
- Point it at your CouchDB instance (
http://your-vps:5984, databaseobsidian). - Enable end-to-end encryption with a passphrase — store it safely.
- 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 couchdbThe 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:
- Opens a persistent connection to
_changes?feed=continuous. - Filters for documents whose
_idends in.md. - Writes a markdown file to
content/using the document’sextracted_textfield. - Schedules a debounced Quartz build (2-second delay).
- 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
- Edit a note in Obsidian → obsidian-livesync pushes encrypted chunks to CouchDB.
- CouchDB emits a change event on
_changes. - couch-sync receives it, writes a
.mdfile tocontent/. - couch-sync fires a debounced
npx quartz build. - Quartz compiles
content/intopublic/. - 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_textstays 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.
RemoveDraftssilently excludes any note withdraft: trueorpublish: false— check frontmatter if a page isn’t appearing.