From 0e4b2f7d1a105f6fcb7dcbe04bceb79e94f3ec84 Mon Sep 17 00:00:00 2001 From: jeremy Date: Sat, 11 Jul 2026 12:03:15 -0500 Subject: [PATCH] feat: deploy CouchDB on hf-pdocker-02 for Obsidian LiveSync (:5984) Backs the Obsidian 'Second Brain' vault (private repo: git.hobbs.farm/jeremy/ second-brain) with self-hosted multi-device sync. LAN-only for now; no public Traefik route yet. - couchdb:3.4 pinned, Watchtower disabled, mem_limit 1g. - Data on LOCAL disk (/var/lib/couchdb) -- CouchDB file locking breaks over NFSv3, same class as guacamole-db and semaphore-db. - local.ini mounted READ-WRITE, deliberately: CouchDB 3.x writes runtime config back into the last-loaded ini, and with :ro it exits 1 and logs NOTHING -- a silent crash-loop that is very hard to diagnose. - CORS allows app://obsidian.md and capacitor://localhost (LiveSync desktop + mobile origins); a wildcard origin is not allowed alongside credentials. - require_valid_user everywhere EXCEPT /_up, so the blackbox probe can health check it without credentials. Anonymous callers get 401 on all data. - Admin credentials in Vaultwarden ('CouchDB - Obsidian LiveSync'); .env is gitignored, .env.example carries a placeholder. Prometheus probe added (probe_success=1). Vault database: 'secondbrain'. Co-Authored-By: Claude Opus 4.8 --- compose/hf-pdocker-02/couchdb/.env.example | 2 ++ .../hf-pdocker-02/couchdb/docker-compose.yml | 27 +++++++++++++++++ compose/hf-pdocker-02/couchdb/local.ini | 30 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 compose/hf-pdocker-02/couchdb/.env.example create mode 100644 compose/hf-pdocker-02/couchdb/docker-compose.yml create mode 100644 compose/hf-pdocker-02/couchdb/local.ini diff --git a/compose/hf-pdocker-02/couchdb/.env.example b/compose/hf-pdocker-02/couchdb/.env.example new file mode 100644 index 0000000..a0ec207 --- /dev/null +++ b/compose/hf-pdocker-02/couchdb/.env.example @@ -0,0 +1,2 @@ +COUCHDB_USER=obsidian +COUCHDB_PASSWORD=REPLACE_AT_DEPLOY diff --git a/compose/hf-pdocker-02/couchdb/docker-compose.yml b/compose/hf-pdocker-02/couchdb/docker-compose.yml new file mode 100644 index 0000000..d84e095 --- /dev/null +++ b/compose/hf-pdocker-02/couchdb/docker-compose.yml @@ -0,0 +1,27 @@ +services: + couchdb: + image: couchdb:3.4 + container_name: couchdb + restart: unless-stopped + ports: + - "5984:5984" + environment: + - COUCHDB_USER=${COUCHDB_USER} + - COUCHDB_PASSWORD=${COUCHDB_PASSWORD} + - TZ=America/Chicago + volumes: + # LOCAL disk, not NFS: CouchDB's file locking breaks over NFSv3, the same + # way it did for guacamole-db (MySQL) and semaphore-db. + - /var/lib/couchdb/data:/opt/couchdb/data + # NOT :ro -- CouchDB 3.x writes runtime config back into the last-loaded ini. + # With a read-only mount it exits 1 immediately and logs NOTHING at all. + - /var/lib/couchdb/config/local.ini:/opt/couchdb/etc/local.d/local.ini + labels: + - "com.centurylinklabs.watchtower.enable=false" + mem_limit: 1g + healthcheck: + test: ["CMD", "curl", "-fsS", "http://localhost:5984/_up"] + interval: 60s + timeout: 10s + retries: 3 + start_period: 30s diff --git a/compose/hf-pdocker-02/couchdb/local.ini b/compose/hf-pdocker-02/couchdb/local.ini new file mode 100644 index 0000000..68cfc43 --- /dev/null +++ b/compose/hf-pdocker-02/couchdb/local.ini @@ -0,0 +1,30 @@ +; CouchDB config for Obsidian LiveSync. +; Obsidian talks to CouchDB from an app:// origin, so CORS must allow it explicitly -- +; a wildcard origin is not permitted alongside credentials. + +[couchdb] +single_node = true +max_document_size = 50000000 + +[chttpd] +require_valid_user = true +; ...but leave /_up open, so the Prometheus blackbox probe can health-check it +; without credentials. Everything else still returns 401 to anonymous callers. +require_valid_user_except_for_up = true +max_http_request_size = 4294967296 +bind_address = 0.0.0.0 + +[chttpd_auth] +require_valid_user = true +authentication_redirect = /_utils/session.html + +[httpd] +WWW-Authenticate = Basic realm="couchdb" +enable_cors = true + +[cors] +credentials = true +; Obsidian desktop is app://obsidian.md; mobile uses capacitor://localhost. +origins = app://obsidian.md,capacitor://localhost,http://localhost +methods = GET,PUT,POST,HEAD,DELETE +headers = accept,authorization,content-type,origin,referer,x-csrf-token