К содержимому
Linux22 мин чтения0 просм.

Свой сервер синхронизации Obsidian: LiveSync, CouchDB и ИИ через MCP - со всеми граблями

Часть 2 из 2Устройства: ПК и iPhone

Первое устройство: ПК

Кто первый, тот заливает хранилище на сервер. В базе ещё ничего нет, поэтому первым беру устройство, где удобнее вводить данные, то есть ПК. Сначала пробовал iPhone: ввод сложных паролей на телефоне и падающая проверка сервера заставили переключиться.

Хранилище создаётся обычное, в обычной папке, не в OneDrive, Dropbox или iCloud Drive: одно хранилище синхронизируется одним способом. Дальше шестерёнка слева внизу, "Сторонние плагины", включить их, "Обзор", Self-hosted LiveSync, "Установить" и "Включить".

Мастер настройки

Плагин переведён на русский частично. На первом экране выбираю "Я настраиваю это впервые", второй вариант про добавление устройства пригодится позже для телефона.

Экран "Сквозное шифрование": ставлю галочку, в появившемся поле "Парольная фраза" вставляю COUCHDB_PASSPHRASE, только значение, без имени и =, и сверяю края через кнопку показа пароля. Пункт Obfuscate Properties выключен, с ним MCP не найдёт заметки. Advanced не трогаю, алгоритм по умолчанию и E2EE v2 с MCP работают. Плагин честно предупреждает, что passphrase не проверяется до начала синхронизации и ошибка всплывёт только потом, поэтому её надо вставлять, а не набирать.

В способе подключения выбираю "Configure a remote manually" и CouchDB: Setup URI ещё нет, его создаст первое устройство.

На экране CouchDB Configuration: URL https://obsidian.example.com без слеша в конце, имя пользователя livesync (не admin), пароль LIVESYNC_PASSWORD, имя базы obsidian, Use Internal API выключено, CORS на сервере уже настроен. Кнопка Check server requirements скажет "Проверка конфигурации не удалась", и это нормально: проверка читает /_node/_local/_config, а nginx его закрывает, в логе видно 403. Кнопку Fix жать не нужно, реальная проверка это следующая кнопка, Create or connect to database and continue.

Последний экран, "Final Confirmation: Overwrite Server Data with This Device's Files": три галочки, включая "I have created a backup of my Vault", и кнопка I Understand, Overwrite Server.

Ловушка 1: Overwrite Server требует прав администратора CouchDB

Симптом: мастер прошёл, внизу синхронизация стоит на нуле и значок перечёркнут красным, заметки на сервер не уходят. Сохранения не помогают.

Причина видна по логу nginx: "Overwrite Server" сначала удаляет базу (DELETE /obsidian/), а потом создаёт заново. У livesync прав на это нет, отсюда 401. Плагин остаётся в состоянии "первая загрузка не завершена" и ставит себя на паузу.

Лечение такое, что пароль админа на ПК не попадает, а окно риска измеряется минутами. Сначала бэкап и копия каталога couchdb-local.d/. Потом временно делаю livesync администратором сервера:

set -a; . ./.env; set +a
jq -n --arg p "$LIVESYNC_PASSWORD" '$p' | docker exec -i obsidian-couchdb sh -c 'cat > /tmp/p.json'
printf 'user = "%s:%s"\n' "$COUCHDB_USER" "$COUCHDB_PASSWORD" \
  | docker exec -i obsidian-couchdb curl -fsS -K - -X PUT --data-binary @/tmp/p.json \
    "http://127.0.0.1:5984/_node/_local/_config/admins/${LIVESYNC_USER}"
docker exec obsidian-couchdb rm -f /tmp/p.json

Выдать роль _admin через документ пользователя в _users нельзя, CouchDB отвечает 403. Изменение применяется через пару секунд, проверить можно запросом GET /_session, там должно появиться "roles":["_admin"].

Дальше на ПК: "Настройки", "Self-hosted LiveSync", "Перезапустить мастер настройки" и всё заново. Теперь в логе DELETE /obsidian/ 200, PUT /obsidian/ 201, _bulk_docs 201. Окно "All optional features are disabled" про выключенные Customisation Sync и Hidden File Sync закрываю кнопкой OK: для заметок они не нужны, наборы плагинов на ПК и телефоне всё равно разные.

И сразу снимаю права (префикс с printf и docker exec тот же, что выше):

... curl -K - -X DELETE "http://127.0.0.1:5984/_node/_local/_config/admins/${LIVESYNC_USER}"

Как сделать проще: выдать livesync права администратора до мастера и снять после. Это экономит час.

Ловушка 2: пересозданная база теряет права доступа

После удаления и создания база получает _security по умолчанию, где в members.roles стоит ["_admin"]. Как только livesync перестаёт быть админом, он получает 401 на свою же базу.

Лечение: вернуть _security из бэкапа, вот зачем скрипт сохраняет его отдельно.

docker exec -i obsidian-couchdb sh -c 'cat > /tmp/sec.json' < /var/backups/obsidian/security-YYYY-MM-DD.json
... curl -K - -X PUT -H 'Content-Type: application/json' --data-binary @/tmp/sec.json \
    "http://127.0.0.1:5984/obsidian/_security"

Проверка: у livesync своя база отвечает 200, _all_dbs даёт 401, в _session нет _admin.

Ловушка 3: MCP перестал расшифровывать заметки

Симптом: list_notes показывает заметки, read_note отвечает "Note not found", в логах MCP Decryption with HKDF failed.

Причина: у новой базы новая соль шифрования, она лежит в _local/obsidian_livesync_sync_parameters, поле pbkdf2salt. Запущенный MCP помнит старую.

Лечение: пересоздать контейнер MCP командой docker compose up -d --force-recreate mcp. Заодно я поменял VAULT_NAME на реальное имя хранилища. После старта в логах появляется Synchronisation parameters fetched successfully и число проиндексированных заметок.

Ловушка 4: Synchronisation paused for compatibility review

Окно появляется после пересоздания базы: плагин просит обновить плагин на всех устройствах и держит синхронизацию на паузе. На единственном устройстве безопасно нажать Resume synchronisation. Крестик и фиолетовая кнопка Keep synchronisation paused оставляют паузу. Вернуться к окну можно командой Review why synchronisation is paused, но она видна, только пока пауза активна: если в палитре "Команда не найдена", значит паузы уже нет.

Ловушка 5: "Диагностика настроек" ломает синхронизацию

Симптом: режим LiveSync выбран, пауза снята, но заметки не уходят. В логе nginx при каждом сохранении только GET/PUT _local/obsydian_livesync_milestone, без _bulk_docs и _changes. В журнале плагина сначала "Some mismatches have been detected in the configuration between devices. Running a manual replication will attempt to resolve this issue.", а затем "Не удалось подключиться к серверу". Это сообщение ложное, подключение в порядке.

Причина: в Hatch была нажата "Диагностика настроек", и она "исправила" customChunkSize с 0 на 60. В базе записано 0. Автосинхронизация при расхождении молча отказывается работать.

Лечение: палитра команд, Self-hosted LiveSync: Sync now, то есть ручная синхронизация. Плагин сам включает "Automatic alignment of compatible chunk settings", обновляет настройки в базе и запускает LiveSync. Окна с таблицей может и не быть. Не принимай предложения "Диагностики" менять customChunkSize на уже работающей базе.

Ловушка 6: после Fetch и Overwrite автосинхронизация выключена

Перед загрузкой плагин вызывает suspendAllSync() и выключает LiveSync, периодическую синхронизацию, sync on save и sync on start. После загрузки он их не включает обратно, в исходниках CLI-версии плагина так и написано: "suspendAllSync() clobbers them". Итог: синхронизация только по ручной команде.

Лечение: после мастера на каждом устройстве зайти в "Настройки синхронизации" и заново выбрать режим. Похожие жалобы есть в issue плагина.

Как диагностировать

Источника правды два, и это главный навык во всей истории.

Первый, лог nginx /var/log/nginx/obsidian.access.log. По нему видно, есть ли запросы от устройства вообще: User-Agent у ПК выглядит как obsidian/1.13.7 ... Electron, у телефона как iPhone ... obsidian. Дальше по запросам: _bulk_docs с кодом 201 означает, что данные ушли, _changes означает обмен, одни только milestone говорят, что плагин проверил базу и сам остановился, 401 это права, 403 на /_node это закрытая админка.

Второй, журнал самого плагина: палитра команд (Ctrl+P, на iPhone свайп вниз по заметке) и Self-hosted LiveSync: Show log. Названия команд плагина не переводятся, искать надо по-английски: Show log, Sync now.

В строке состояния внизу перечёркнутый красный значок и нули у счётчиков означают, что синхронизация стоит.

Второе устройство: iPhone

Если от неудачной первой попытки осталось хранилище, удали его в "Управлении хранилищами". Новое создаётся с тем же именем, что на ПК, тогда ссылки obsidian:// от ИИ открываются и на телефоне. Пункт "Хранить в iCloud" выключить: iCloud вместе с LiveSync дают дубликаты и конфликты. Плагин ставится так же, как на ПК.

Настройки передаются с ПК из раздела "Для настройки других устройств". Кнопка "Показать QR код" в русском интерфейсе показывает окно "Мы сгенерировали QR-код... Отсканируйте QR-код телефоном" без самого QR-кода, а OK просто закрывает окно. Причина в том, что в русском переводе строки Setup.QRCode потерян плейсхолдер ${qr_image}, в английском он есть. Обход: "Внешний вид", язык плагина English, показать QR, вернуть язык. Важно, что этот QR не зашифрован, в нём все настройки включая пароли, поэтому только со своего экрана, не фотографировать и не пересылать.

Альтернатива это "Копировать текущие настройки в Setup URI". Строка зашифрована паролем, который ты придумываешь сам, её можно переслать себе, например в "Избранное" мессенджера. Setup URI и пароль к нему стоит сохранить в менеджер паролей, пригодятся для следующих устройств.

В мастере на телефоне: "Я добавляю устройство к существующей настройке синхронизации", дальше QR или Setup URI и пароль. На экране "Mostly Complete: Decision Required" нужен вариант "My remote server is already set up. I want to join this device." Не первый, потому что "I am setting up a new server... / reset" перезапишет сервер пустым телефоном, и не третий, плагин сам называет его опасным.

Дальше "Data retrieval scheduled" и Overwrite all with remote files. Overwrite здесь про файлы на iPhone, сервер не трогается. Вариант "Compare time and take newer" не подходит: Obsidian кладёт в каждое новое хранилище заметку "Добро пожаловать", на iPhone она новее серверной и победила бы. Если появится окно про compatibility review, жми Resume.

После Fetch iPhone один раз синхронизировался и замолчал: правка с телефона на ПК не пришла. По логу nginx после Fetch от iPhone не было ни одного запроса. Ручной Sync now отправлял правку, а следующую уже нет. Причина та же, что и на ПК, шестая ловушка: Fetch выключил автосинхронизацию.

Правильные режимы синхронизации

Идти надо в "Настройки", "Self-hosted LiveSync", "Настройки синхронизации", "Режим синхронизации".

Устройство Режим Дополнительно
ПК LiveSync (непрерывно) Keep replication active in the background включить
iPhone LiveSync Sync on Startup, Sync on File Open, Sync on Save включить

Даже если в поле уже стоит LiveSync, после мастера выбери его заново, чтобы он применился.

Свёрнутый Obsidian на телефоне замораживается через несколько секунд, это ограничение iOS, а не плагина. Правка, сделанная прямо перед сворачиванием, уйдёт при следующем открытии, через Sync on Startup. В итоге пишешь заметку, и через секунду-две она на сервере и на другом устройстве, без нажатий.

Мелочи, которые стоит знать

Пустые папки не синхронизируются, LiveSync передаёт файлы. Новая папка появится на других устройствах и в MCP, когда в ней будет хоть одна заметка.

Переменная VAULT_NAME должна точно совпадать с именем хранилища в Obsidian, иначе ссылки obsidian://open?vault=... не открываются. Смена имени даёт новый подкаталог в томе MCP: поисковый индекс пересоберётся, а OAuth-клиентов придётся переподключить.

Команда docker compose restart не перечитывает .env, нужен docker compose up -d.

Удаление заметки через MCP уходит в базу, и LiveSync удаляет её на всех устройствах.

Лимиты: документ CouchDB 50 МБ, client_max_body_size 128M. Большие вложения раздувают базу.

Инструкции для ИИ можно держать на сервере (MCP_INSTRUCTIONS_FILE), а запись ограничить папкой (WRITE_FOLDERS), это пригодится при открытии MCP наружу.

Что даёт E2E-шифрование, а что нет

Защищено содержимое заметок: утечка логина с телефона даёт только шифротекст, дамп без passphrase бесполезен.

Не защищены пути и имена файлов, они лежат в базе открытым текстом, вида "path":"папка/заметка.md". Скрыть их можно через Path Obfuscation, но тогда не работает MCP, выбирать приходится. И root на сервере: passphrase лежит в .env для MCP, значит, это уже шифрование при хранении, а не строго end-to-end.

Итоговая проверка

Заметка, созданная на ПК, через 1-2 секунды читается через MCP с сервера, и раз она расшифровывается, то passphrase и Path Obfuscation в порядке. Правка на iPhone приходит на ПК без ручных команд. Пользователь livesync не админ, _all_dbs для него 401, админка снаружи 403. Бэкап по расписанию работает, восстановление проверено.

Что дальше

Открыть MCP наружу через nginx с OAuth (MCP_AUTH_TOKEN, BASE_URL), чтобы Claude в браузере, десктопе и на телефоне мог записывать мысли в Inbox-папку, а запись ограничить через WRITE_FOLDERS. Защиты от перебора пароля на форме входа MCP нет, понадобится limit_req в nginx, при этом fail2ban не должен забанить адреса Claude.

Копия бэкапа за пределы сервера через rsync или rclone. Fail2ban на 401 для CouchDB и ротация логов nginx для этого сайта.

Комментарии

Пока никто не написал. Будьте первым.