# Runbook: Joplin — синк Mac ↔ телефон (WebDAV / Android-хотспот) Симптом: **синхронизация перестала работать** между Joplin на Mac и на телефоне. Стек: **rclone serve webdav** на Mac → `~/JoplinSync` → Joplin (Mac + Android) по HTTP. Облако Joplin не используется. **Рабочая схема (2026-06–07):** Mac на **хотспоте**, primary IP **`*.100`** через `networksetup -setmanual`, телефон → `http://<подсеть>.100:8080`. Подробно: [STABLE_SETUP.md](./STABLE_SETUP.md). **Последняя проверка: 2026-07-04** — синк работает на подсети `10.121.169.x` (см. ниже). --- ## Проверенный рабочий сетап (зафиксировано 2026-07-04) ### Условия (все обязательны) | # | Условие | Как проверить | |---|---------|---------------| | 1 | Mac — **клиент Wi‑Fi хотспота Android** (не домашний Wi‑Fi) | `joplin-hotspot-alias.sh status` → `network: похоже на Android-хотспот` | | 2 | **rclone** слушает `:8080` | `joplin-webdav-status.sh` → процесс / порт | | 3 | Mac primary IP = **`<подсеть>.100`** (setmanual) | `static IP: OK`, `ipconfig getifaddr en0` → `*.100` | | 4 | Шлюз Wi‑Fi = **телефон** (Android) | gateway `10.x.x.x` / `192.168.43.x` — не `192.168.1.1` роутера | | 5 | **Mac Joplin** → `http://127.0.0.1:8080` | `settings.json` → `sync.6.path` | | 6 | **Телефон Joplin** → `http://<подсеть>.100:8080` | URL из `status`, **без** `/` и пробелов в конце | | 7 | Учётка WebDAV: логин `joplin`, пароль из env | после смены пароля — `joplin-webdav-reload.sh` | | 8 | В rclone.log — запросы **не только** с `127.0.0.1` | `GET`/`PUT from 10.x.x.x` (часто IP **шлюза**, не Mac) | ### Пример сессии, когда синк **работал** (2026-07-04) ``` Подсеть: 10.121.169.x Gateway: 10.121.169.246 ← телефон (виден в rclone.log) Mac primary: 10.121.169.100 ← networksetup -setmanual URL Mac: http://127.0.0.1:8080 URL телефон: http://10.121.169.100:8080 rclone.log: GET from 10.121.169.246:59442 … alias.log: networksetup -setmanual 10.121.169.100 gw 10.121.169.246 ``` ### Одна команда перед синком ```bash ./docs/apps/joplin/scripts/joplin-ensure-sync.sh ``` Один раз (LaunchAgent без пароля): ```bash ./docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh ./docs/apps/joplin/scripts/joplin-hotspot-alias-install.sh ``` Перед возвратом на домашний Wi‑Fi: ```bash ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh dhcp ``` --- ## Что НЕ работает (не пробовать) | Подход | Почему не работает | Что делать вместо | |--------|-------------------|-------------------| | **Tailscale / VPN mesh** | На Mac нет App Store; brew tailscale без GUI/daemon — не подняли стабильно; пользователь отказался | Хотспот + LAN WebDAV (эта схема) | | **`ifconfig alias *.100`** | Mac видит alias (`curl` с Mac OK), **Android не маршрутизирует** к alias — в rclone.log **нет** `from 10.x` | **`networksetup -setmanual`** → primary `*.100` | | **`http://*.local:8080`** (mDNS) | Android-хотспот **не резолвит** `.local` клиентов Wi‑Fi | IP: `http://<подсеть>.100:8080` | | **URL = DHCP primary Mac** (`10.x.x.84`) | IP **меняется** при каждом reconnect хотспота | Фиксированный хвост **`.100`** | | **Старый URL после смены подсети** (`10.74.21.100` при Mac в `10.121.169.x`) | ETIMEDOUT; телефон стучится не туда | `./joplin-hotspot-alias.sh status` → **один раз** новый URL | | **Stale Manual Wi‑Fi** (старый шлюз в prefs) | `No Router MAC`, нет интернета, ping gateway fail | `macos-hotspot-network-recover.sh recover` → DHCP → `repair` | | **Mac дома (`192.168.1.x`), телефон на LTE** | Разные сети — маршрута нет | Mac к **хотспоту** телефона **или** телефон в ту же Wi‑Fi | | **Смотреть только UI Joplin на Mac** | Mac синкается на `127.0.0.1` — **OK даже когда телефон молчит** | `tail -f ~/Library/Logs/joplin-webdav/rclone.log \| grep -v 127.0.0.1` | | **WebDAV URL в разделе «Прокси»** | Прокси — для HTTP/SOCKS, не адрес синка | **Синхронизация → Self-hosting → WebDAV** | | **Пробел / `/` в конце URL** | `Not a valid URL: …8080 /info.json` | Переписать URL без пробела и без trailing `/` | | **Joplin Cloud / Docker Server** | Не выбрано: нужен **локальный** WebDAV без облака | rclone на Mac (`~/JoplinSync`) | | **Обновлять URL на Mac при смене хотспота** | Mac всегда на localhost | Mac: **только** `127.0.0.1:8080`; менять URL **на телефоне** | ### Быстрая отличительная диагностика | Симптом | Вероятная причина из таблицы выше | |---------|-----------------------------------| | rclone только `from 127.0.0.1` | alias вместо setmanual, разные сети, или неверный URL на телефоне | | `curl` с Mac на `*.100` OK, телефон — timeout | **alias** (типичный кейс 2026-07-04) → `repair` | | Mac «Completed», заметок нет | Mac не на WebDAV / пробел в URL | | `401 Unauthorized` | пароль env ≠ Joplin или старый rclone → `reload` | | Интернет на Mac мёртв после reconnect | stale Manual → `recover` | --- ## Архитектура ``` Телефон (Joplin) ──HTTP──► Mac en0 primary *.100:8080 ──► rclone ──► ~/JoplinSync/ Mac (Joplin) ──HTTP──► 127.0.0.1:8080 (тот же rclone) ``` | Компонент | Путь / имя | |-----------|------------| | Данные | `~/JoplinSync` | | Учётка | `~/.config/joplin-webdav/env` (`600`, не в git) | | WebDAV | LaunchAgent `com.eternal.joplin-webdav` | | Static `*.100` | LaunchAgent `com.eternal.joplin-hotspot-alias` (setmanual; опционально + sudoers) | | Лог rclone | `~/Library/Logs/joplin-webdav/rclone.log` | | Лог static IP | `~/Library/Logs/joplin-webdav/alias.log` | | Лог Joplin Mac | `~/.config/joplin-desktop/log.txt` | | Настройки Mac | `~/.config/joplin-desktop/settings.json` → `sync.6.path` | Скрипты: `docs/apps/joplin/scripts/`. --- ## Шаг 0: диагностика ```bash ./docs/apps/joplin/scripts/joplin-webdav-status.sh ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status ``` | Что смотреть | OK | Проблема | |--------------|-----|----------| | rclone / `:8080` | процесс слушает | `joplin-webdav-serve.sh` или `joplin-webdav-install.sh` | | `static IP: OK` | primary `*.100` | `joplin-hotspot-alias.sh repair` (sudo) | | rclone.log | `from 10.` или `from 192.` | только `127.0.0.1` — телефон не достучался | | Mac URL | `127.0.0.1:8080` | настроить WebDAV на Mac | --- ## Правильные URL ### Android раздаёт хотспот, Mac — клиент Wi‑Fi (основной сценарий) | Устройство | WebDAV URL | |------------|------------| | **Mac** | `http://127.0.0.1:8080` | | **Телефон** | `http://<подсеть>.100:8080` — актуально: `http://10.121.169.100:8080` (2026-07-04) | Узнать актуальный URL: ```bash ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status # или grep JOPLIN_PHONE_URL ~/.config/joplin-webdav/env ``` **Не использовать на телефоне** (подробнее — раздел «Что НЕ работает» выше): | URL / подход | Почему | |-----|--------| | `http://eternals.local:8080` | Android-хотспот **не резолвит** `.local` | | `http://10.219.227.100:8080` | старая подсеть (пример) | | `http://10.74.21.100:8080` | старая подсеть (пример) | | `http://10.x.x.84:8080` (DHCP primary Mac) | IP меняется при reconnect | | alias `*.100` без setmanual | телефон не достучится (2026-07-04) | ### Общее для Joplin - Логин: `joplin` - Пароль: `JOPLIN_WEBDAV_PASS` из env - **Без** `/` в конце URL - **Без пробела** в конце - `http://`, не `https://` - **Настройки → Синхронизация → Self-hosting → WebDAV** (не «Прокси») После смены URL на Mac: **Quit Joplin** → открыть снова → **Синхронизировать**. --- ## Симптом → причина → действие ### 1. «Синк OK, заметок нет на Mac» Mac Joplin не на WebDAV — в `~/JoplinSync` только данные с телефона. → URL `http://127.0.0.1:8080`, проверить конфигурацию, синк. --- ### 2. `ETIMEDOUT` / `connect ETIMEDOUT 10.x.x.x:8080` **Причина:** на телефоне **устаревший IP** (другая подсеть или primary `.100` не выставлен). **Признаки:** Joplin `ETIMEDOUT`; rclone — нет свежих `GET`/`PUT` с `10.`. **Действие:** ```bash ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh ensure # sudo ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status # новый URL ``` → Обновить URL на телефоне **только если сменилась подсеть** (`10.219` → `10.74`). --- ### 3. `401 Unauthorized` Пароль в Joplin ≠ env, или rclone не перезапущен. ```bash grep JOPLIN_WEBDAV_PASS ~/.config/joplin-webdav/env ./docs/apps/joplin/scripts/joplin-webdav-reload.sh ``` --- ### 4. `Not a valid URL: …/info.json` Пробел в конце URL в настройках Joplin → переписать URL. --- ### 5. Порт 8080 не слушает ```bash ./docs/apps/joplin/scripts/joplin-webdav-status.sh ./docs/apps/joplin/scripts/joplin-webdav-serve.sh ``` Лог: `~/Library/Logs/joplin-webdav/launchd.err.log`. --- ### 6. Mac «синкается», телефон — нет (2026-07-04) **Самый частый кейс.** Mac → `127.0.0.1:8080` OK. Телефон молчит. **Три причины (часто вместе):** 1. **Подсеть сменилась** — на телефоне старый URL (`10.74.21.100`), Mac уже в `10.121.169.x` 2. **Primary `.100` не выставлен** — LaunchAgent не смог `sudo networksetup` (sudoers + `repair`) 3. **Разные сети** — Mac на домашнем Wi‑Fi (`192.168.1.x`), телефон на мобильном **Диагностика:** ```bash ./docs/apps/joplin/scripts/joplin-webdav-status.sh grep JOPLIN_PHONE_URL ~/.config/joplin-webdav/env tail -5 ~/Library/Logs/joplin-webdav/rclone.log | grep -v 127.0.0.1 ``` | Признак | Значение | |---------|----------| | rclone только `from 127.0.0.1` | телефон **не достучался** | | `static IP: MISSING` | `./joplin-hotspot-alias.sh repair` | | `stale ifconfig: …` | старый alias → `repair` (скрипт снимет alias, выставит setmanual) | | `JOPLIN_PHONE_URL` ≠ URL из status | обновить URL **на телефоне** | | gateway `192.168.1.1` | домашний Wi‑Fi — телефон должен быть **в той же сети** | **Фикс:** ```bash ./docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh # если sudo просит пароль ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh repair ./docs/apps/joplin/scripts/joplin-webdav-status.sh # URL для телефона ``` → Обновить URL в Joplin на телефоне → **Синхронизировать** --- ### 7. `ECONNREFUSED` / телефон «не достаёт», Mac — да **Причина:** primary **`*.100` отсутствует** на `en0` (слетел после reconnect или DHCP вместо setmanual). ```bash ifconfig en0 | grep inet ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status curl -s -o /dev/null -w '%{http_code}\n' http://10.74.21.100:8080/ # подставьте *.100 из status ``` → `joplin-hotspot-alias.sh ensure` → В браузере **на телефоне**: `http://.100:8080` — запрос логина → Нет интернета на Mac: [HOTSPOT_NETWORK_EMERGENCY.md](../../HOTSPOT_NETWORK_EMERGENCY.md) --- ### 8. `eternals.local` / `*.local` не работает с телефона **Ожидаемо.** mDNS на Mac резолвится, Android-хотспот — нет. Использовать **`http://.100:8080`**, не `.local`. --- ## Процедура: переподключили хотспот / сменили Wi‑Fi ### 1. Интернет на Mac Если `curl` / браузер мёртвы: ```bash bash /Users/eternal/code/local_machine/docs/connectivity/scripts/macos-hotspot-network-recover.sh recover ``` Wi‑Fi на хотспоте: **Manual `*.100`** через `joplin-hotspot-alias` (шлюз = текущий gateway). Перед домашним Wi‑Fi: `joplin-hotspot-alias.sh dhcp`. См. [HOTSPOT_NETWORK_EMERGENCY.md](../../HOTSPOT_NETWORK_EMERGENCY.md). ### 2. Joplin ```bash ./docs/apps/joplin/scripts/joplin-webdav-status.sh ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh ensure # если static IP MISSING ``` Чеклист: - [ ] rclone слушает `:8080` - [ ] `static IP: OK` (или `repair` выполнен) - [ ] **Mac:** `http://127.0.0.1:8080` — без изменений - [ ] **Телефон:** URL из `status` — **не менять**, если подсеть та же (`10.74.21.x`) - [ ] Подсеть **сменилась** → один раз новый `http://.100:8080` - [ ] В rclone.log появились `from 10.` после синка на телефоне ### 3. Авто `*.100` (рекомендуется один раз) ```bash bash ./docs/apps/joplin/scripts/joplin-android-hotspot-setup.sh install bash ./docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh ``` LaunchAgent выставляет primary `*.100` каждые 60 с после reconnect. --- ## Скрипты | Скрипт | Когда | |--------|--------| | `joplin-webdav-status.sh` | Первая диагностика | | `joplin-hotspot-alias.sh status\|ensure\|repair\|dhcp` | URL телефона, primary `*.100`, вернуть DHCP | | `joplin-android-hotspot-setup.sh install` | Полная настройка хотспота | | `joplin-hotspot-alias-install-sudo.sh` | setmanual/dhcp без пароля (LaunchAgent) | | `joplin-webdav-install.sh` | Первая установка rclone + launchd | | `joplin-webdav-reload.sh` | После смены пароля в env | | `joplin-mdns-setup.sh` | Справочно; **не для URL на телефоне-хотспоте** | Путь: `docs/apps/joplin/scripts/`. --- ## Логи **rclone.log** — успех: `PROPFIND`, `GET`, `PUT from `. Телефон часто виден как IP **шлюза** (`10.74.21.61`), не IP Mac — нормально для Android. **log.txt Mac:** ```bash grep -E 'Synchronizer: \[error\]|ETIMEDOUT|ECONNREFUSED|Unauthorized|Not a valid URL' \ ~/.config/joplin-desktop/log.txt | tail -20 ``` --- ## Безопасность - WebDAV только в LAN (`0.0.0.0:8080` пока rclone работает); не пробрасывать в интернет. - env и пароль — не в git. --- ## Связанные документы | Документ | Зачем | |----------|--------| | [STABLE_SETUP.md](./STABLE_SETUP.md) | Primary `*.100`, установка | | [README.md](./README.md) | Оглавление | | [docs/apps/joplin/README.md](../../../apps/joplin/README.md) | Установка с нуля | | [HOTSPOT_NETWORK_EMERGENCY.md](../../HOTSPOT_NETWORK_EMERGENCY.md) | Сеть macOS после reconnect | --- ## История инцидентов | Дата | Симптом | Корень | Фикс | |------|---------|--------|------| | 2026-06-02 | 401 | Пароль env ≠ Joplin | `joplin-webdav-reload.sh` | | 2026-06-08 | ETIMEDOUT | Старый IP на телефоне | Обновить URL | | 2026-06-09 | Телефон не достаёт `.100` | Mac без primary `.100` | `setmanual` / `joplin-hotspot-alias repair` | | 2026-06-15 | Нет интернета после reconnect | Stale Manual + битые маршруты | `macos-hotspot-network-recover.sh recover` | | 2026-06-19 | `eternals.local` не работает | Android-хотспот не резолвит mDNS | URL `http://10.74.21.100:8080` + setmanual | | 2026-06-19 | Синк OK | primary `.100` + LaunchAgent | [STABLE_SETUP.md](./STABLE_SETUP.md) | | 2026-07-04 | Mac OK, телефон нет | alias `.100`; подсеть `10.74`→`10.121` | setmanual + URL `10.121.169.100` | | 2026-07-04 | **Синк OK** | setmanual `10.121.169.100`, gateway `.246` | [рабочий сетап](#проверенный-рабочий-сетап-зафиксировано-2026-07-04) | --- *Актуальный URL телефона: `./docs/apps/joplin/scripts/joplin-hotspot-alias.sh status`.*