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

255 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Obsidian Self-hosted LiveSync (на CouchDB)
Single-tenant self-hosted vault на VPS. Multi-device sync через
[Self-hosted LiveSync plugin](https://github.com/vrtmrz/obsidian-livesync).
## Архитектура (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` (НЕ в репо!):
```bash
COUCHDB_USER=obsidian
COUCHDB_PASSWORD=<сгенерированный 32-байтный пароль>
```
Сгенерировать пароль:
```bash
openssl rand -base64 32
```
### 3. Первое создание shared network на VPS (один раз)
```bash
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).
Для ручного старта впервые:
```bash
git push # любой из 2 workflow задеплоит свою часть
```
Или вручную с VPS:
```bash
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`.
Если нужно вручную:
```bash
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. Проверка работы
```bash
# из любой точки интернета:
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
- https://obsidian.md/download
### 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 базы:
```bash
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:
```json
PUT /gendesign-vault/_security
{
"admins": {"names": ["obsidian"], "roles": []},
"members": {"names": ["viewer"], "roles": []}
}
```
## Backup
```bash
# 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