Files
technitium-console/docs/hub-management-plan.md
DenozordecandClaude Opus 5.5 9742f0fe69
CI / check (push) Successful in 4m27s
Hub / check (push) Successful in 1m17s
CI / image (push) Successful in 1m54s
Hub / image (push) Successful in 1m56s
Hub stage 8: settings drift, webhook notices, profiles
The drift check now also covers the settings baseline and the Blocked
and Allowed lists baseline; the drift dialog offers Open compare,
Accept as baseline and Revert to baseline for them. Old drift.json
files still load.

HUB_WEBHOOK_URL (and an optional HUB_WEBHOOK_SECRET for an HMAC
signature) receives drift.found, drift.cleared and write.failed
notices, only on change, without values, never blocking a request and
never logging the address beyond its host. Admins see the webhook
status and can send a test from About and from the drift dialog.

Profiles bundle the hub's app, settings and lists baselines. Applying
one to a server runs install, app configs, settings and lists in order
after a preview; a failed step stops that server's later steps and
Retry failed resumes from it. Profiles export and import as a file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 02:11:19 +07:00

182 lines
17 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.
# Хаб: централизованное управление серверами Technitium без кластера
Общий план. Внутри два пласта:
- **общее управление**: каждый сервер из одной консоли, действия «на все серверы», сравнение и выравнивание;
- **упор на Apps**: приложения на всех серверах и синхронизация их конфигов.
Статус: этапы 0 и 1 (безопасность, Apps по серверам), 2 (установка и обновление), 3 (сравнение и синхронизация конфигов), 4 (история, откат, расхождения), 5 (управление каждым сервером), 6 (действия на все серверы вне Apps), 7 (зоны, настройки и блокировка: сравнение и выравнивание) и 8 (профили, webhook, расхождения настроек и списков) сделаны. Этапы после 8 пока планы (`docs/hub-deploy.md`).
---
## 1. Контекст и цель
- Есть два независимых сервера Technitium DNS: `mdns.shnt.top` и `ndns.shnt.top`. Кластера нет и не будет: серверы должны оставаться самостоятельными.
- Хаб на `dnss.shnt.top` уже показывает статистику обоих: Dashboard, Logs, About, переключатель «All servers / mdns / ndns», предупреждение об отказе сервера.
- **Цель:** управлять обоими серверами из хаба. Прежде всего приложениями (Apps): ставить, обновлять и держать их конфиги одинаковыми там, где нужно, не трогая того, что у каждого сервера своё.
---
## 2. Принципы
1. **Два режима записи.**
- **На один сервер:** действие пересылается выбранному серверу (`node=mdns` или `node=ndns`). Так уже работает чтение.
- **На все серверы:** хаб выполняет действие на каждом выбранном сервере и показывает итог по каждому отдельно. Тихого «ок» при частичном успехе не бывает.
2. **Чтение и запись разделены.**
- Токены `hub-reader` (только View) остаются для чтения.
- Для записи на каждом сервере заводится отдельный `hub-admin` только с теми правами, которые нужны этапу.
3. **Хаб защищается до того, как получает запись.** Роли, ограничение попыток входа, журнал действий (этап 0).
4. **Конфиги синхронизируются, данные нет.**
- Синхронизируются тексты конфигов приложений и настройки.
- Базы логов, кеш и статистика у каждого сервера свои.
5. **Общая часть плюс локальные поля.**
- В конфигах приложений есть поля, свои для каждого сервера: сети Split Horizon, путь к базе Query Logs, локальные группы клиентов Advanced Blocking.
- Синхронизируется только общая часть. Локальные поля задаются по каждому серверу.
6. **Источник правды для конфигов: эталон в хабе.**
- Хаб хранит желаемый конфиг в своём томе (`/data`), серверы приводятся к нему.
- Первый эталон берётся импортом с любого сервера.
- Альтернатива: ведущий сервер (mdns) как эталон. Она проще, но хуже: зависит от живучести одного сервера и не даёт истории.
7. **Зоны DNS лучше синхронизировать средствами Technitium.** Primary-зона на одном сервере и secondary с передачей зоны (AXFR) на другом надёжнее рассылки каждой правки из хаба. Хаб помогает это настроить и показывает расхождения, но не дублирует записи сам.
8. **Перед изменением предпросмотр, после него итог и откат.** Каждое применение конфига сохраняет прежнюю версию.
---
## 3. Этапы
Сначала безопасность, потом Apps (главный упор), потом общее управление.
### Этап 0. Безопасность записи (обязателен первым)
- **Пользователи хаба с ролями**, в файле `/data/users.json`, пароли в виде хешей:
- `viewer`: только смотрит;
- `apps-admin`: управляет приложениями;
- `operator`: блокировка и кеш;
- `admin`: всё.
- **Защита входа:**
- ограничение попыток входа и временная блокировка после серии неудач;
- по желанию: вход через ваш auth-портал (Traefik `forwardAuth`).
- **Журнал действий** (`/data/audit.log`, раздел Audit в консоли хаба): кто, когда, на каком сервере, что сделал, итог.
- **Токены записи** `MDNS_ADMIN_TOKEN` и `NDNS_ADMIN_TOKEN`. На старте права только Modify и Delete на Apps, другие разделы добавляются по этапам.
- **Права в хабе:** вместо списка «только чтение»: таблица «эндпоинт → чтение / запись на один сервер / запись на все / нужная роль».
- **Доступ к хабу по сети:** закрыть по IP (`ipallowlist` в Traefik) или через auth-портал.
### Этап 1. Apps: обзор по серверам (только чтение)
Матрица «приложение × сервер» в разделе Apps при «All servers»:
- установлено или нет, версия, есть ли обновление;
- конфиг: «совпадает», «отличается (N полей)» или «отличается только в локальных полях»;
- фильтры: «отличаются версии», «отличаются конфиги», «есть обновление».
Отвечает на вопрос «что где стоит и где расхождения» без единой записи.
### Этап 2. Apps: установка, обновление, удаление на нескольких серверах
- Выбор цели у действий: mdns, ndns или все серверы.
- **Из магазина:** `apps/downloadAndInstall` и `apps/downloadAndUpdate` на каждом выбранном сервере.
- **Свой zip:** загружается в хаб один раз, хаб отправляет его через `apps/install` или `apps/update` на каждый сервер.
- Окно итога по серверам и кнопка «Повторить на неудавшихся».
- **«Выровнять версии»:** обновить приложение везде до самой новой версии.
- **Удаление на всех:** отдельное подтверждение. Хаб перед удалением сохраняет конфиг в историю.
### Этап 3. Apps: сравнение и синхронизация конфигов
- **Сравнение рядом:** конфиг на mdns и на ndns. Для JSON: по полям (добавлено, удалено, изменено), для не-JSON: построчно.
- **Эталон в хабе:**
- импорт эталона с выбранного сервера;
- правка эталона в редакторе хаба;
- хранение в `/data/apps/<приложение>/baseline.json`.
- **Локальные поля:**
- список путей полей, которые не синхронизируются (например, `networks`, `dbPath`), плюс их значения по каждому серверу;
- хранение в `/data/apps/<приложение>/overrides.json`;
- итоговый конфиг сервера = эталон + его локальные значения.
- **Предпросмотр:** что изменится на каждом сервере, затем применение через `apps/config/set` на выбранных серверах с итогом по каждому.
- **Проверка до записи:** JSON разбирается в хабе. Если сервер отверг конфиг, показывается его ошибка, а сервер остаётся со старым конфигом.
### Этап 4. Apps: история, откат, контроль расхождений
- **История:** каждое применение сохраняет прежний конфиг каждого сервера (`/data/apps/<приложение>/history/`). Можно посмотреть любую версию и откатить один сервер или все.
- **Проверка расхождений по расписанию** (по умолчанию раз в 15 минут). Если конфиг поменяли прямо в консоли сервера, в шапке появляется предупреждение с действиями «Принять как эталон» и «Вернуть к эталону».
- **Экспорт и импорт всех эталонов одним файлом:** резервная копия и подготовка нового сервера.
### Этап 5. Управление каждым сервером из одной консоли
- Запись на выбранный сервер открывается для разделов Zones, Cache, Blocking, DNS Client, Settings, DHCP, Logs (кроме удаления логов). Права токена `hub-admin` расширяются под эти разделы.
- В «All servers» запись по-прежнему закрыта: кнопки неактивны с подсказкой «выберите сервер».
- Администрирование пользователей, SSO и LDAP серверов остаётся в их собственных консолях.
### Этап 6. Действия «на все серверы» вне Apps
- **Блокировка:** добавить или удалить домен в Blocked и Allowed, временно отключить блокировку, обновить списки, изменить URL списков.
- **Кеш:** сбросить весь кеш или удалить домен.
- **Итог по каждому серверу** и повтор на неудавшихся.
### Этап 7. Сравнение и выравнивание остального
- **Zones в «All servers»:**
- объединённый список с отметкой, где зона есть, и признаком расхождения (разный SOA serial);
- действия «Скопировать зону на другой сервер» (экспорт и импорт) и «Сделать secondary на другом сервере» (передача зоны).
- **Blocking и Settings:** отчёт о различиях и «Принять как эталон» с предпросмотром, по той же схеме «общая часть плюс локальные поля», что и для Apps.
### Этап 8. Удобство (по желанию)
- Профили: набор приложений с конфигами и правил, который применяется к новому серверу.
- Уведомления о расхождениях наружу (webhook).
---
## 4. Что меняется в коде
**Хаб (`hub/`):**
- `server.ts`:
- таблица прав по эндпоинтам;
- пересылка POST и multipart (zip приложений, импорт зон);
- рассылка «на все» с итогами по серверам.
- Новые модули:
- `users.ts`: роли, хеши паролей, ограничение попыток входа;
- `audit.ts`: журнал действий;
- `store.ts`: файлы в `/data` (эталоны, локальные поля, история), запись атомарно через временный файл;
- `apps-sync.ts`: сравнение конфигов, слияние эталона с локальными полями, предпросмотр, применение;
- `drift.ts`: проверка расхождений по расписанию.
- `config.ts`: `<ID>_ADMIN_TOKEN`, `HUB_DATA` (по умолчанию `/data`), `HUB_DRIFT_MINUTES`.
**Консоль (`src/`), только в режиме хаба:**
- права разделов приходят от хаба по роли пользователя;
- Apps: матрица по серверам, выбор цели у действий, окно итогов;
- экран «Конфиг приложения»: сравнение рядом, эталон, локальные поля, предпросмотр, история и откат;
- предупреждение о расхождениях в шапке;
- раздел Audit.
**Развёртывание:**
- в compose: том `technitium-hub-data:/data` и токены `MDNS_ADMIN_TOKEN`, `NDNS_ADMIN_TOKEN` в `.env`;
- на каждом сервере пользователь `hub-admin` в отдельной группе с правами записи только на нужные разделы.
---
## 5. Риски и как их закрыть
| Риск | Что делаем |
|---|---|
| Хаб получает ключи на запись к обоим серверам | Этап 0 первым; токены только на нужные разделы; хаб закрыт по IP или через auth-портал |
| Частичный успех при рассылке | Итог по каждому серверу, повтор на неудавшихся, откат из истории |
| Разные версии приложения ждут разный формат конфига | Хаб показывает версии и предлагает сначала выровнять их |
| Неверно заданные локальные поля перенесут настройки одного сервера на другой | Предпросмотр перед каждым применением, история и откат |
| Конфиг поменяли мимо хаба | Проверка расхождений по расписанию и предупреждение |
| Разные версии Technitium понимают API по-разному | Версия каждого сервера в хабе, предупреждение при расхождении |
---
## 6. Как проверяется каждый этап
- **Модульные тесты хаба** (vitest): права по эндпоинтам, роли и защита входа, слияние эталона с локальными полями, сравнение JSON, история и откат.
- **Тест с двумя фейковыми серверами:** рассылка, частичный отказ, итоги.
- **Мок** (`dev/mock-api.mjs`) получает приложения и конфиги, разные на двух портах. В браузере проверяются матрица, сравнение, применение и откат.
- **Порядок работы:** код по этапам пишет Sonnet, Opus проверяет дифф, тесты и браузер, коммит после каждого принятого этапа.
- **На серверах:** сначала на одном приложении с безобидным конфигом, потом шире.
---
## 7. Решения перед стартом
1. **Источник правды для конфигов:** эталон в хабе (рекомендация) или ведущий сервер mdns.
2. **Вход в хаб:** свои пользователи хаба с ролями или ваш auth-портал через Traefik `forwardAuth`.
3. **Какие приложения стоят на серверах** и какие поля в их конфигах заведомо локальные. Это станет начальными списками локальных полей.