셀프호스팅
- Cloudflare Access 뒤에 n8n을 넣을 때 — 정책에는 경로를 못 넣으니 `/api/v1`·`/webhook`은 Bypass 애플리케이션을 따로 만들어야 하고, 만드는 순서를 틀리면 그 사이 API와 웹훅이 막힌다
인터넷에 노출돼 있던 n8n 두 대와 컨테이너 관리 UI의 로그인 화면을 Cloudflare Zero Trust Access 뒤로 넣은 기록. Access는 애플리케이션 = 호스트명 + 경로 단위이고 정책에는 경로를 넣을 수 없어서, 기계가 붙는 /api/v1(API 키)과 /webhook(외부 웹훅)은 Bypass 애플리케이션을 각각 따로 만들고 웹 UI만 이메일 OTP로 막았다. 인증 없는 요청은 302로 로그인 화면에 보내지므로 기계는 못 통과한다. Bypass 앱을 먼저, Allow 앱을 마지막에 만들어야 그 사이에 API·웹훅이 끊기지 않는다.
- 앱에서 지운 노트가 서버에는 그대로 남을 때 — livesync-bridge가 삭제만 영구히 흘리는 이유
노트를 지웠는데 서버 파일이 남았고, 그 유령 파일 때문에 자동 생성 노트의 번호가 튀고 중복이 생겼다. 브리지가 저장하는 `since` 값은 리터럴 `"now"`다 — 프로세스가 죽어 있던 동안의 변경은 재시작해도 절대 재생되지 않고, 오프라인 스캔은 파일시스템→CouchDB 한 방향뿐이라 자가교정도 없다.
- Obsidian LiveSync CouchDB가 볼트의 20배로 부풀 때 — 쌓이기만 하는 고아 청크 정리하기
볼트 마크다운은 2.7MiB인데 CouchDB 파일은 55.9MiB, 문서는 27,101개였다. 어떤 노트도 참조하지 않는 leaf 청크가 계속 쌓이는데, compaction은 그걸 걷어내는 도구가 아니다 — 고아 청크를 찾는 쿼리, 지우기 전 반드시 확인할 안전조건, 그리고 3주 만에 5,739개가 다시 쌓인 이야기.
- PouchDB `changes` 피드가 에러도 없이 영원히 멈출 때 — `heartbeat`는 빠진 적이 없었다
pull이 에러 없이 멈춰 감시 크론이 컨테이너를 재시작하는 일이 하루에도 몇 번씩 반복됐다. 나는 `.changes({live:true})`에 `heartbeat`가 없어서라고 진단하고 두 줄을 넣었다. 배포돼 있는 pouchdb-adapter-http 9.0.0 소스를 오늘 열어보니 그 진단이 틀렸다 — continuous 피드에는 `heartbeat=10000`이 기본으로 붙고, 어댑터의 changes 코드가 계산해둔 `requestTimeout`은 그 뒤로 쓰이지 않는다. 감시 로그를 세보니 두 줄을 넣은 뒤에도 pull이 멈추는 사건은 계속됐다.
- 10분마다 바뀌는 자동 생성 파일이 Obsidian에서 충돌을 만들 때 — hidden 파일로 옮긴 이유
감시용 하트비트 파일을 볼트에 두자 다른 기기의 Obsidian에서 동기화 충돌이 났다. 볼트에 보이는 자동 갱신 파일은 기기가 다시 붙을 때마다 버전이 갈리고, 사용자가 어느 쪽을 남길지 고르게 만든다. 점으로 시작하는 hidden 파일로 옮겨 해결한 과정과, 그 사이에 내가 지어냈던 함정 하나.
- 조용히 죽는 동기화를 잡는 하트비트 크론 — 재시작만 하고 끝내는 감시는 반쪽이다
에러 한 줄 없이 한쪽 방향만 멎는 동기화를 사람이 눈으로 감시할 수는 없다. 정본 기기가 10분마다 시각을 적고, 감시 기기가 그 시각이 25분 넘게 낡으면 컨테이너를 재시작하는 크론. 그리고 '재시작했다'가 아니라 '복구됐다'까지 알려주도록 자가검증을 붙인 이유.
- livesync-bridge가 push만 하고 pull은 죽어 있을 때 — 에러 한 줄 없이 한쪽 방향만 멎는다
서버를 옮긴 뒤 파이 쪽 브리지가 CouchDB에서 내려받는 방향만 완전히 멈췄다. 로그에 에러는 0건이고 push는 정상이라 겉으로는 멀쩡했다. 그 사이 나는 파이에서 오래된 파일을 밀어 올려 다른 기기가 지운 내용을 되살리고 있었다 — 진단 명령과 손실 없이 정합시킨 절차.
- livesync-bridge가 하루 14번씩 조용히 재시작할 때 — 파일 감시자가 atomic write 임시파일에 걸린다
Deno로 도는 livesync-bridge 컨테이너가 12일 동안 169번 죽고 되살아났다. 앱은 멀쩡해 보였고 로그에는 `Uncaught NotFound`만 남았다. 원인은 감시자가 atomic write의 임시파일을 stat하려다 그 파일이 rename으로 사라진 것 — 그리고 소스 패치로는 절반만 잡혔다.
- LiveSync 수동 Replicate는 되는데 자동 push만 안 될 때 — 새 볼트·새 DB로 재설정하고 DB wipe를 멈추자 풀렸다
수동 Replicate는 되는데 자동 push만 안 되는 상태 — 디버깅하며 서버 DB를 반복해서 지웠다 만든 것이 동기화 체크포인트를 깨뜨린 것으로 진단했다. 그 상태의 정체, 저장해도 아무 일이 안 일어나는 또 다른 증상, 그리고 새 볼트·새 DB로 한 번 재설정하고 wipe를 중단하자 두 증상이 함께 사라진 과정.
- Cloudflare Access 뒤의 CouchDB에 Obsidian LiveSync가 안 붙을 때 — preflight OPTIONS가 막힌다
Cloudflare Tunnel로 CouchDB를 열고 Access로 게이트를 걸었더니 LiveSync가 붙지 못했다. preflight OPTIONS가 막히는 지점, 그때 내가 못 찾았던 우회 설정, 게이트를 WAF로 내린 절충, 결국 tailscale로 간 이유, 그리고 '100초 제한이 원인'이라는 오진까지.
- CouchDB 도커 컨테이너가 로그 한 줄 없이 죽고 재시작만 반복할 때 — 설정 파일 `:ro` 마운트가 원인
docker compose로 CouchDB를 띄웠는데 컨테이너가 에러 메시지도 없이 exit 1로 죽고 재시작 루프에 빠진다. local.ini를 `:ro`로 마운트한 게 원인 — 공식 이미지 엔트리포인트가 CouchDB를 띄우기 전에 그 설정 파일 마운트에 쓸 수 있어야 하기 때문이다. 덤으로 볼트 루트 기준 경로가 `_`로 시작하면 그 파일이 다른 이름으로 갈라져 올라가는 문제까지.
- 노션 대신 Obsidian 자가호스팅 — AI 에이전트가 직접 읽고 쓸 노트 시스템의 조건
AI 에이전트가 노트를 직접 읽고 쓰려면 노트 시스템이 뭘 만족해야 하나. 그 조건으로 노션·AppFlowy·Anytype·Syncthing이 각각 어디서 걸리는지, 그리고 그렇게 만든 시스템이 조용히 깨져온 기록의 목차.