Obsidian Self-hosted LiveSync (CouchDB) выведен в отдельный docker-compose stack и GHA workflow. Любой стек теперь редеплоится независимо. * docker-compose.obsidian.yml: только couchdb в shared external network * docker-compose.prod.yml: убрана couchdb-секция; caddy подключён к shared network для маршрута obsidian.gendsgn.ru → couchdb:5984 * .github/workflows/deploy-obsidian.yml: новый workflow с path-filters (триггерится только при изменениях obsidian-related файлов) * .github/workflows/deploy.yml: + path-filters (триггерится только при main-related файлах) + создание shared network в bootstrap * docs/obsidian-livesync.md: обновлены инструкции под split-архитектуру После push: 1. ssh gendesign 'docker network create gendesign_shared' (один раз) 2. Прописать COUCHDB_USER/PASSWORD в backend/.env.runtime 3. Добавить DNS A-record obsidian.gendsgn.ru → IP VPS 4. git push → GHA задеплоит обе части независимо Преимущества: - Изменения main не разрывают LiveSync клиентов - Изменения obsidian не рестартуют main - Падение obsidian-стека не влияет на основное приложение
11 KiB
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 | .github/workflows/deploy.yml |
.github/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-vaultdatabase - Все пользователи логинятся как
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.jsonlknowledge graph → .md файлы в vault