Hub stage 0: own users with roles, login limit, audit log, permission table
Users in HUB_DATA/users.json with scrypt hashes and roles (viewer, operator, apps-admin, admin), managed by hub/users-cli.ts; HUB_USER/HUB_PASSWORD remain a bootstrap admin while the file does not exist. Five failed logins in 15 minutes lock the address or the name for 15 minutes. Logins, logouts and every refused request go to a JSON Lines audit log that admins read through hub/audit/list. Endpoints are listed in routes.ts with their kind and capability; writes stay refused for now. Optional <ID>_ADMIN_TOKEN is read for the coming write stages. The management plan is in docs/hub-management-plan.md. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
042cb116ea
commit
0ef2d53a65
17 files changed
+1497
-79
No files matched your search
@@ -12,7 +12,7 @@ version: "3.8"
|
||||
# MDNS_TOKEN=...
|
||||
# NDNS_TOKEN=...
|
||||
# HUB_USER=... # логин в сам хаб
|
||||
# HUB_PASSWORD=... # длинный пароль: у хаба нет ограничения числа попыток входа
|
||||
# HUB_PASSWORD=... # первый вход; затем пользователи в /data/users.json (docs/hub-deploy.md, шаг 4a)
|
||||
#
|
||||
# Обновление: docker compose pull technitium-hub && docker compose up -d technitium-hub
|
||||
|
||||
@@ -23,13 +23,19 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dns-net
|
||||
volumes:
|
||||
- technitium-hub-data:/data
|
||||
environment:
|
||||
# id=адрес, по порядку; токен каждого берётся из <ID>_TOKEN
|
||||
- HUB_SERVERS=mdns=https://mdns.shnt.top,ndns=https://ndns.shnt.top
|
||||
- MDNS_TOKEN=${MDNS_TOKEN}
|
||||
- NDNS_TOKEN=${NDNS_TOKEN}
|
||||
# Только пока нет /data/users.json; потом пользователи создаются через users-cli (docs/hub-deploy.md)
|
||||
- HUB_USER=${HUB_USER}
|
||||
- HUB_PASSWORD=${HUB_PASSWORD}
|
||||
- HUB_DATA=/data
|
||||
# За Traefik: брать адрес клиента из X-Forwarded-For (для ограничения попыток входа и журнала)
|
||||
- HUB_TRUST_PROXY=1
|
||||
- HUB_DOMAIN=dnss.shnt.top
|
||||
- TZ=Asia/Novosibirsk
|
||||
labels:
|
||||
@@ -42,6 +48,9 @@ services:
|
||||
- "traefik.http.routers.hub.service=hub-svc"
|
||||
- "traefik.http.services.hub-svc.loadbalancer.server.port=8080"
|
||||
|
||||
volumes:
|
||||
technitium-hub-data:
|
||||
|
||||
networks:
|
||||
dns-net:
|
||||
external: true
|
||||
|
||||
@@ -181,14 +181,20 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dns-net
|
||||
volumes:
|
||||
- technitium-hub-data:/data
|
||||
environment:
|
||||
# id=адрес по порядку; токен каждого из <ID>_TOKEN. Сервер на ЭТОМ же хосте можно
|
||||
# указать изнутри сети, мимо Traefik: ndns=http://technitium-smart:5380
|
||||
- HUB_SERVERS=mdns=https://mdns.shnt.top,ndns=https://ndns.shnt.top
|
||||
- MDNS_TOKEN=${MDNS_TOKEN}
|
||||
- NDNS_TOKEN=${NDNS_TOKEN}
|
||||
# Только пока нет /data/users.json; потом пользователи создаются через users-cli (docs/hub-deploy.md)
|
||||
- HUB_USER=${HUB_USER}
|
||||
- HUB_PASSWORD=${HUB_PASSWORD}
|
||||
- HUB_DATA=/data
|
||||
# За Traefik: брать адрес клиента из X-Forwarded-For (для ограничения попыток входа и журнала)
|
||||
- HUB_TRUST_PROXY=1
|
||||
- HUB_DOMAIN=dnss.shnt.top
|
||||
- TZ=Asia/Novosibirsk
|
||||
labels:
|
||||
@@ -209,3 +215,4 @@ networks:
|
||||
volumes:
|
||||
technitium-data:
|
||||
technitium-console:
|
||||
technitium-hub-data:
|
||||
+50
-7
@@ -4,7 +4,7 @@
|
||||
|
||||
- запрос «All servers» хаб отправляет на оба сервера и складывает ответы;
|
||||
- запрос к одному серверу хаб пересылает только ему;
|
||||
- запись хаб не выполняет никогда.
|
||||
- запись хаб пока не выполняет: любой запрос на изменение получает отказ и попадает в журнал.
|
||||
|
||||
Серверы Technitium не меняются, кластер не нужен. В инструкции хаб ставится на хост, где уже работают Traefik и `technitium-smart` (`docs/compose.shnt.example.yaml`). Адрес хаба: `https://dnss.shnt.top`.
|
||||
|
||||
@@ -91,12 +91,12 @@ git tag hub-v1.0.0 && git push origin hub-v1.0.0
|
||||
MDNS_TOKEN=вставьте_токен_mdns
|
||||
NDNS_TOKEN=вставьте_токен_ndns
|
||||
|
||||
# Вход в сам хаб (это НЕ логин Technitium)
|
||||
# Первый вход в хаб (это НЕ логин Technitium). Нужен, пока не создан файл пользователей (шаг 4a)
|
||||
HUB_USER=admin
|
||||
HUB_PASSWORD=длинный_случайный_пароль
|
||||
```
|
||||
|
||||
Пароль хаба нужен длинный: у хаба нет ограничения числа попыток входа. Сгенерировать можно так:
|
||||
Пароль лучше длинный. После 5 неудачных попыток за 15 минут вход блокируется на 15 минут, но это не замена хорошему паролю. Сгенерировать можно так:
|
||||
```bash
|
||||
openssl rand -base64 24
|
||||
```
|
||||
@@ -126,8 +126,12 @@ chmod 600 .env
|
||||
- NDNS_TOKEN=${NDNS_TOKEN}
|
||||
- HUB_USER=${HUB_USER}
|
||||
- HUB_PASSWORD=${HUB_PASSWORD}
|
||||
- HUB_DATA=/data
|
||||
- HUB_TRUST_PROXY=1
|
||||
- HUB_DOMAIN=dnss.shnt.top
|
||||
- TZ=Asia/Novosibirsk
|
||||
volumes:
|
||||
- technitium-hub-data:/data
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=dns-net"
|
||||
@@ -138,6 +142,13 @@ chmod 600 .env
|
||||
- "traefik.http.services.hub-svc.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
Том `technitium-hub-data` нужно объявить в разделе `volumes:` того же файла:
|
||||
```yaml
|
||||
volumes:
|
||||
technitium-hub-data:
|
||||
```
|
||||
В нём лежат файл пользователей `users.json` и журнал `audit.log`. `HUB_TRUST_PROXY=1` нужен за Traefik: хаб берёт адрес клиента из заголовка `X-Forwarded-For` для ограничения попыток входа и журнала. Если до хаба можно достучаться в обход Traefik, включать эту переменную нельзя: заголовок можно подделать.
|
||||
|
||||
Если хаб стоит в том же файле, что Traefik, отдельный блок `networks:` с `external: true` из примера не нужен: сеть `dns-net` в этом файле уже объявлена.
|
||||
|
||||
Про имена в `HUB_SERVERS`:
|
||||
@@ -149,6 +160,32 @@ chmod 600 .env
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4a. Пользователи хаба
|
||||
|
||||
У хаба свои пользователи с ролями. Они лежат в `/data/users.json`, пароли в виде хешей.
|
||||
|
||||
| Роль | Что может |
|
||||
|---|---|
|
||||
| `viewer` | смотреть |
|
||||
| `operator` | смотреть, блокировка и кеш (после появления записи) |
|
||||
| `apps-admin` | смотреть, управлять приложениями (после появления записи) |
|
||||
| `admin` | всё, включая журнал действий |
|
||||
|
||||
Пока файла нет, в хаб входит один `admin` из `HUB_USER` / `HUB_PASSWORD`. Когда файл появился, эти две переменные игнорируются (в логе будет строка об этом). Если нет ни файла, ни переменных, хаб не запустится.
|
||||
|
||||
После запуска (шаг 5) создайте пользователей. Пароль команда спросит дважды, при вводе он не показывается:
|
||||
```bash
|
||||
docker exec -it technitium-hub node --experimental-strip-types /app/hub/users-cli.ts add denis admin
|
||||
docker exec -it technitium-hub node --experimental-strip-types /app/hub/users-cli.ts add alice viewer
|
||||
```
|
||||
Остальные команды: `passwd <имя>`, `role <имя> <роль>`, `disable <имя>`, `enable <имя>`, `list`. Хаб замечает изменение файла на следующем запросе и завершает сессии затронутых пользователей. Перезапуск не нужен.
|
||||
|
||||
После создания своего `admin` уберите `HUB_USER` и `HUB_PASSWORD` из `.env` и compose, затем `docker compose up -d technitium-hub`.
|
||||
|
||||
Журнал: войдите админом и откройте `/api/hub/audit/list?limit=200` (JSON, новые записи первыми) или смотрите файл `docker exec technitium-hub tail -n 50 /data/audit.log`. Пароли и токены в журнал не пишутся.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 5. Запуск
|
||||
|
||||
Если реестр закрытый, один раз войдите в него. Нужен токен Gitea с правом `read:package`:
|
||||
@@ -218,7 +255,10 @@ docker compose rm -f technitium-hub # удалить контейнер
|
||||
|---|---|---|
|
||||
| `HUB_SERVERS` | обязательна | Серверы по порядку: `id=https://адрес,...` |
|
||||
| `<ID>_TOKEN` | обязательна для каждого | API-токен сервера (`MDNS_TOKEN`, `NDNS_TOKEN`, ...) |
|
||||
| `HUB_USER`, `HUB_PASSWORD` | обязательны | Вход в хаб |
|
||||
| `HUB_USER`, `HUB_PASSWORD` | нужны, пока нет `users.json` | Первый `admin`; при наличии файла игнорируются |
|
||||
| `HUB_DATA` | `/data` | Папка `users.json` и `audit.log` (на ней том) |
|
||||
| `HUB_TRUST_PROXY` | выключено | `1`: адрес клиента из `X-Forwarded-For` (только за Traefik) |
|
||||
| `<ID>_ADMIN_TOKEN` | нет | Токен записи сервера (`MDNS_ADMIN_TOKEN`). Пока не используется, в логи не пишется |
|
||||
| `HUB_DOMAIN` | `hub` | Имя, которое консоль показывает как имя сервера |
|
||||
| `HUB_CACHE_SECONDS` | `15` | Сколько секунд хранить ответы серверов (0 выключает кеш) |
|
||||
| `HUB_TIMEOUT_MS` | `8000` | Сколько ждать ответа сервера, мс |
|
||||
@@ -239,7 +279,10 @@ docker compose rm -f technitium-hub # удалить контейнер
|
||||
| Контейнер сразу завершается | В `docker compose logs technitium-hub` будет названа недостающая переменная. Проверьте `.env` и что compose его видит (`docker compose config \| grep TOKEN`). |
|
||||
| `https://dnss.shnt.top` не открывается, ошибка сертификата | Нет DNS-записи `dnss` (шаг 2) или Traefik ещё получает сертификат: смотрите `docker logs traefik`. |
|
||||
| 404 от Traefik | Контейнер не в сети `dns-net` или опечатка в `Host(\`dnss.shnt.top\`)`. |
|
||||
| Вход в хаб: «Invalid username or password» | Неверные `HUB_USER`/`HUB_PASSWORD` в `.env`. После правки `.env` нужен `docker compose up -d technitium-hub`. |
|
||||
| Вход в хаб: «Invalid username or password» | Неверный логин или пароль. Если есть `users.json`, работают только его пользователи (`users-cli.ts list`), а `HUB_USER` игнорируется. После правки `.env` нужен `docker compose up -d technitium-hub`. |
|
||||
| «Too many failed logins. Try again in N minutes.» | 5 неудач за 15 минут с одного адреса или на одно имя. Подождите; блокировка хранится в памяти, её снимает перезапуск контейнера. |
|
||||
| Все пользователи блокируются разом | Не включён `HUB_TRUST_PROXY=1`: хаб видит только адрес Traefik. |
|
||||
| Контейнер пишет `audit log is not writable` | Нет тома на `/data` или папка не принадлежит `node`. Журнал живёт в памяти (последние 1000 записей) до исправления. |
|
||||
| В шапке «1 server not answering», в подсказке `ndns: its API token was refused` | Токен `NDNS_TOKEN` отозван или скопирован с ошибкой. Создайте новый (шаг 1.4) и перезапустите хаб. |
|
||||
| В подсказке `... did not answer: ...` или `ECONNREFUSED` / `timeout` | Хаб не достучался до сервера. Проверьте с хоста хаба: `docker exec technitium-hub node -e "fetch('https://ndns.shnt.top/api/status').then(r=>console.log(r.status))"`. |
|
||||
| В подсказке `ndns: ...` с сообщением об отказе в доступе | У группы `hub-readers` на этом сервере не хватает View в каком-то разделе (шаг 1.2). |
|
||||
@@ -249,6 +292,6 @@ docker compose rm -f technitium-hub # удалить контейнер
|
||||
|
||||
## Безопасность
|
||||
|
||||
- Хаб только читает: любая запись получает отказ ещё в хабе, а токены выданы пользователю с одними правами View.
|
||||
- Хаб только читает: любая запись получает отказ ещё в хабе (и запись в журнале), а токены выданы пользователю с одними правами View.
|
||||
- Токены лежат только в `.env` на хосте и в памяти контейнера. В браузер они не попадают, в ответы и логи хаба не пишутся.
|
||||
- У хаба один общий логин и нет ограничения попыток входа. Нужен длинный пароль, а если хаб не должен быть виден из интернета, добавьте к роутеру `hub` в Traefik `ipallowlist` или `basicAuth`.
|
||||
- У каждого человека свой логин и роль. Вход защищён блокировкой после 5 неудач. Нужны длинные пароли, а если хаб не должен быть виден из интернета, добавьте к роутеру `hub` в Traefik `ipallowlist` или `basicAuth`.
|
||||
@@ -0,0 +1,181 @@
|
||||
# Хаб: централизованное управление серверами Technitium без кластера
|
||||
|
||||
Общий план. Внутри два пласта:
|
||||
- **общее управление**: каждый сервер из одной консоли, действия «на все серверы», сравнение и выравнивание;
|
||||
- **упор на Apps**: приложения на всех серверах и синхронизация их конфигов.
|
||||
|
||||
Статус: план, ничего из этого ещё не сделано. Сейчас хаб только читает (`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. **Какие приложения стоят на серверах** и какие поля в их конфигах заведомо локальные. Это станет начальными списками локальных полей.
|
||||
Reference in new issue
Block a user