Self-Hosting
- Putting n8n behind Cloudflare Access: policies can't match paths, so `/api/v1` and `/webhook` need their own Bypass applications โ and if you create them in the wrong order, the API and webhooks go dark in between
Two n8n instances and a container-management UI had their login pages open to the internet, so they went behind Cloudflare Zero Trust Access. An Access application is hostname + path, and policies have no path condition โ so the machine-facing paths, /api/v1 (API key) and /webhook (inbound webhooks), each got a separate Bypass application, and only the web UI got an email one-time-PIN Allow policy. Access answers an unauthenticated request with a 302 to its login page, so machines can't get through. Create the Bypass apps first and the Allow app last, or the API and webhooks are cut off in between.
- Notes deleted in the app that stay on the server โ how livesync-bridge loses deletions permanently
A note was deleted in Obsidian, the file survived on the server, and the leftover file made an auto-generated note skip a number and duplicate itself. The `since` value the bridge persists is the literal string `"now"`, so nothing that happened while it was down is ever replayed โ and the offline scan only runs filesystem โ CouchDB, so there's no path back.
- Obsidian LiveSync's CouchDB grew to 20ร the vault โ finding and deleting orphaned chunks
2.7MiB of markdown, a 55.9MiB database file, 27,101 documents. Compaction is the wrong tool for it: orphaned leaf chunks aren't stale revisions, they're live documents nothing references. Here's the query that finds them, the safety check to run before deleting anything, and why 5,739 of them were back three weeks later.
- A PouchDB `changes` feed that hangs forever with no error โ `heartbeat` was never the missing piece
Pull kept stalling with no error, and the watchdog was restarting the container several times a day. I diagnosed it as a missing `heartbeat` on `.changes({live:true})` and added two lines. When I read the deployed pouchdb-adapter-http 9.0.0 source today, the diagnosis turned out to be wrong: continuous feeds get `heartbeat=10000` by default, and the `requestTimeout` the adapter computes in that path is never used again. The watchdog log shows pull kept stalling after those two lines went in.
- Why an auto-generated file that changes every 10 minutes causes sync conflicts in Obsidian โ and the dotfile that fixes it
Putting a monitoring heartbeat inside the vault produced sync conflicts on the other devices โ a file that rewrites itself diverges every time a device reconnects, and the user has to pick a version. Here's the move to a dot-prefixed file that ended it, and the trap I invented for myself along the way.
- A heartbeat cron for sync that dies without errors โ and why a watchdog that only restarts is half a watchdog
Nothing in a log tells you that one direction of a sync has quietly stopped. So the authoritative machine writes a timestamp every 10 minutes, and the watching machine restarts the container when that timestamp is more than 25 minutes old. Plus the part I added a day later: making the alert say 'recovered' or 'still broken' instead of just 'restarted'.
- livesync-bridge pushing but never pulling โ one direction of a two-way sync can die silently
After moving the sync hub, the bridge on the Raspberry Pi stopped receiving from CouchDB entirely. Not one error in the log, and pushes still worked, so nothing looked broken. Meanwhile I was on that Pi, uploading stale files and resurrecting edits other devices had deleted โ here's the log check that finds it and the reconcile that loses nothing.
- A Deno file watcher that dies on atomic writes โ livesync-bridge restarting 14 times a day
The livesync-bridge container died and came back 169 times over twelve days while sync looked perfectly healthy. The log said `Uncaught NotFound: No such file or directory` and nothing else. The watcher was stat-ing the temp file of an atomic write after the rename had already removed it โ and patching our own code only fixed half of it.
- Obsidian LiveSync: manual Replicate works, automatic push doesn't โ one clean reset and no more DB wipes
Manual Replicate works, automatic push doesn't. I diagnosed it as a broken sync checkpoint โ the result of deleting and recreating the server database over and over while debugging. This covers that state, the separate silent failure where saving a note does nothing at all, and the recovery: one clean reset to a fresh vault and DB, and no more wiping after that.
- When Obsidian LiveSync won't connect to CouchDB behind Cloudflare Access โ the CORS preflight is blocked
Putting Cloudflare Access in front of the CouchDB that backs Obsidian LiveSync stopped the plugin from connecting here โ the CORS preflight was blocked. Where it breaks, the bypass setting I never found at the time, the WAF compromise, why this ended up on tailscale, and the '100-second limit' misdiagnosis along the way.
- A CouchDB Docker container that exits with no logs and keeps restarting โ it's the `:ro` config mount
You bring CouchDB up under docker compose, the container exits with code 1, and the log is empty. The cause is mounting local.ini with :ro โ the official image's entrypoint needs that mount to be writable before CouchDB ever starts. Plus what really happens when a vault path starts with _ โ the file syncs under a different name, and from the app it splits in two.
- Self-hosted Obsidian instead of Notion โ what a note system needs before an AI agent can write to it
What does a note system have to satisfy before an AI agent can read and write to it directly? Here's where Notion, AppFlowy, Anytype and Syncthing each fall short of that bar โ plus a table of contents for everything that quietly broke afterward.