gendesign/docs/obsidian-livesync.md
bot-backend 9c46689da1
All checks were successful
Deploy Obsidian / deploy-obsidian (push) Successful in 1m59s
fix(devops): переносим deploy-obsidian.yml в .forgejo/workflows/ (#2416) (#2439)
2026-07-05 15:34:55 +00:00

11 KiB
Raw Blame History

Obsidian Self-hosted LiveSync (на CouchDB)

Single-tenant self-hosted vault на VPS. Multi-device sync через Self-hosted LiveSync plugin.

Архитектура (split deploy)

Obsidian-стек отделён от основного приложения (backend/frontend/postgres/redis). Каждый деплоится своим GHA workflow, никто не блокирует другого:

                   ┌────────────────────────────────────┐
[laptop / mobile]──┤  Caddy (main-stack)                │
                   │   обслуживает gendsgn.ru + api     │
                   │   + reverse_proxy obsidian.* →     │
                   │     ───shared network───┐          │
                   └─────────────────────────┼──────────┘
                                             │
                                             ▼
                   ┌──────────────────────────────────┐
                   │  CouchDB (obsidian-stack)        │
                   │   gendesign_shared network        │
                   │   volumes couchdb_data            │
                   └──────────────────────────────────┘
Main stack Obsidian stack
Compose docker-compose.prod.yml docker-compose.obsidian.yml
Project gendesign (docker compose -p gendesign) gendesign-obsidian
Workflow .forgejo/workflows/deploy.yml .forgejo/workflows/deploy-obsidian.yml
Триггер push paths backend/**, frontend/**, Caddyfile, main compose docker-compose.obsidian.yml, scripts/setup-couchdb.sh, docs
Сервисы backend, frontend, postgres, redis, worker, beat, caddy couchdb
Восстанавливается отдельно

Связь: внешняя docker-сеть gendesign_shared (создаётся вручную или в первом деплое). Caddy в main-stack подключён к ней + к default — маршрут obsidian.gendsgn.ru ходит в couchdb:5984.

При отсутствии obsidian-стека main работает без проблем (Caddy просто вернёт 502 на obsidian-route).

Deploy

1. DNS

A-запись:

obsidian.gendsgn.ru.   A   <VPS_IP>

(тот же IP что gendsgn.ru)

2. Secrets на VPS

Добавить в backend/.env.runtime (НЕ в репо!):

COUCHDB_USER=obsidian
COUCHDB_PASSWORD=<сгенерированный 32-байтный пароль>

Сгенерировать пароль:

openssl rand -base64 32

3. Первое создание shared network на VPS (один раз)

ssh gendesign
docker network create gendesign_shared

(автоматически создаётся в каждом из двух workflow если её нет, но для первого ручного запуска удобнее самому).

4. Деплой

Изменения в docker-compose.obsidian.yml / scripts/setup-couchdb.sh / docs/obsidian-livesync.md → GHA триггерит deploy-obsidian.yml (не трогает main!).

Изменения в backend/**, frontend/**, docker-compose.prod.yml, Caddyfile → триггерит deploy.yml (main).

Для ручного старта впервые:

git push   # любой из 2 workflow задеплоит свою часть

Или вручную с VPS:

cd /opt/gendesign
# main:
docker compose -p gendesign -f docker-compose.prod.yml up -d
# obsidian:
docker compose -p gendesign-obsidian -f docker-compose.obsidian.yml up -d

Caddy автоматически получит Let's Encrypt сертификат для obsidian.gendsgn.ru при первом обращении (если DNS уже резолвится).

5. Bootstrap CouchDB (один раз, идемпотентный)

deploy-obsidian.yml запускает bootstrap автоматически после up -d. Если нужно вручную:

cd /opt/gendesign
source backend/.env.runtime  # подгружаем COUCHDB_PASSWORD
COUCHDB_HOST=http://localhost:5984 \
COUCHDB_PASSWORD="$COUCHDB_PASSWORD" \
docker compose -p gendesign-obsidian -f docker-compose.obsidian.yml \
    exec -T couchdb bash -c "$(cat scripts/setup-couchdb.sh)"

Скрипт:

  • конвертирует CouchDB в "configured single-node" mode
  • создаёт database gendesign-vault
  • включает CORS (нужно для мобильных Obsidian)
  • увеличивает лимиты на размер документов (для крупных attachments)
  • настраивает auth-timeout (для длинных sync-сессий)

Идемпотентен — повторный запуск безопасен.

5. Проверка работы

# из любой точки интернета:
curl https://obsidian.gendsgn.ru/_up
# → {"status":"ok",...}

curl -u obsidian:<password> https://obsidian.gendsgn.ru/gendesign-vault
# → {"db_name":"gendesign-vault","doc_count":0,...}

Настройка клиента (Obsidian Desktop)

1. Установить Obsidian

2. Создать vault

  • "Create new vault" → название "gendesign" → выбрать локальную папку

3. Установить Self-hosted LiveSync plugin

  • Settings → Community plugins → "Browse"
  • Search: "Self-hosted LiveSync" (автор: vrtmrz)
  • Install → Enable

4. Настроить подключение

Settings → Self-hosted LiveSync → Setup wizard (рекомендуется первый раз):

Поле Значение
URI https://obsidian.gendsgn.ru
Username obsidian (или то что в COUCHDB_USER)
Password <COUCHDB_PASSWORD>
Database name gendesign-vault
End-to-End Encryption OFF (см. ниже про trade-off)

Затем:

  • "Test Database Connection" → должно быть зелёное ✓
  • "Check database configuration" → если требует — выполнить "Fix all"
  • "Apply settings"
  • "LiveSync" → "Enable LiveSync"

5. Первичный sync

При первом подключении vault пустой и в БД ничего нет. После первой правки .md файла LiveSync запушит изменение в CouchDB.

С другого устройства/у другого пользователя:

  • Та же установка
  • При first sync клиент скачает всё содержимое БД в локальный vault

6. Mobile (iOS / Android)

  • Установить Obsidian из App Store / Google Play
  • Создать пустой vault
  • Установить Self-hosted LiveSync (как на desktop)
  • Те же настройки → первый sync скачает всё с сервера

⚠️ На iOS: включить Background App Refresh для Obsidian, иначе sync только при открытом приложении.

End-to-End Encryption (E2EE)

E2EE ON E2EE OFF (default у нас)
Контент в БД Зашифрован (admin сервера не может прочитать) Plain text
Производительность Тяжелее на клиенте Быстрее
Claude (через MCP/HTTP) сможет писать извне? Нет (нужен passphrase у Claude) Да
Восстановление при потере passphrase Невозможно Возможно (через CouchDB admin)

Рекомендую OFF — vault это рабочие заметки, не банковская тайна. HTTPS + basic auth + закрытый DNS защищают от внешнего читателя.

Если позже потребуется E2EE — переключить в plugin, ребутнуть БД (replicate from scratch).

Multi-user

CouchDB поддерживает per-user permissions, но для простого MVP:

  • Один shared gendesign-vault database
  • Все пользователи логинятся как obsidian (один аккаунт)

Для разделения (read-only для одних, write — для других) — нужно добавить users в _users DB и настроить security object базы:

curl -X PUT -u obsidian:PWD https://obsidian.gendsgn.ru/_users/org.couchdb.user:viewer \
    -H "Content-Type: application/json" \
    -d '{"name":"viewer","password":"VIEWER_PWD","roles":[],"type":"user"}'

Затем в vault DB:

PUT /gendesign-vault/_security
{
  "admins": {"names": ["obsidian"], "roles": []},
  "members": {"names": ["viewer"], "roles": []}
}

Backup

# Snapshot DB → tar.gz на VPS (можно поставить в cron)
docker compose exec couchdb tar czf /tmp/vault-backup-$(date +%F).tar.gz /opt/couchdb/data
docker cp gendesign-couchdb:/tmp/vault-backup-*.tar.gz /opt/gendesign-backups/

Опционально — _replicate через CouchDB API на S3-совместимое хранилище.

Troubleshooting

Failed to connect в LiveSync

  • Проверить DNS: dig obsidian.gendsgn.ru
  • Проверить HTTPS: curl https://obsidian.gendsgn.ru/_up (должен вернуть {"status":"ok"})
  • Проверить пароль: curl -u obsidian:PWD https://obsidian.gendsgn.ru/gendesign-vault

CORS errors на mobile

  • Запустить setup-couchdb.sh ещё раз (или проверить через _config/cors/origins)

Большие attachments не синкаются

  • В LiveSync plugin: "Customization & advanced" → "Chunk size" = 100 KB
  • На сервере: couchdb/max_document_size уже = 50 MB

Конфликты при одновременной правке

  • LiveSync создаёт conflict-маркер в файле
  • Plugin показывает UI для merge ("Show conflict resolution dialog")

Что дальше

После того как multi-device sync работает:

  • Решить как Claude пишет в vault: MCP filesystem + bridge / самописный CouchDB-MCP / headless Obsidian
  • Мигрировать существующий memory-gendesign.jsonl knowledge graph → .md файлы в vault