Hub: step-by-step deployment guide; Dockerfile comment the language check flagged
docs/hub-deploy.md walks through the image, a read-only hub-reader user and token on each server, the DNS record, .env, the compose service, checks, updates and troubleshooting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3f917c6bd2
commit
a86d1a088a
2 files changed
+255
-1
No files matched your search
@@ -0,0 +1,254 @@
|
||||
# Хаб: запуск по шагам
|
||||
|
||||
Хаб показывает статистику двух серверов Technitium DNS (`dns.shnt.top` и `ndns.shnt.top`) в одной консоли. Это один маленький контейнер. Он отдаёт ту же консоль и сам ходит в API обоих серверов по их токенам:
|
||||
|
||||
- запрос «All servers» хаб отправляет на оба сервера и складывает ответы;
|
||||
- запрос к одному серверу хаб пересылает только ему;
|
||||
- запись хаб не выполняет никогда.
|
||||
|
||||
Серверы Technitium не меняются, кластер не нужен. В инструкции хаб ставится на хост, где уже работают Traefik и `technitium-smart` (`docs/compose.shnt.example.yaml`). Адрес хаба: `https://hub.shnt.top`.
|
||||
|
||||
```
|
||||
браузер ─► Traefik (hub.shnt.top, TLS) ─► technitium-hub:8080
|
||||
├─► https://dns.shnt.top/api/... (DNS_TOKEN)
|
||||
└─► https://ndns.shnt.top/api/... (NDNS_TOKEN)
|
||||
```
|
||||
|
||||
Что хаб показывает: Dashboard (сумма или один сервер), Logs (View Logs и Query Logs, объединённые с колонкой Server) и About. Остальные разделы скрыты, ими управляют в консоли каждого сервера.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 0. Образ хаба в реестре
|
||||
|
||||
Образ `git.shx.one/denozord/technitium-hub` собирает отдельный workflow `.gitea/workflows/hub.yaml`.
|
||||
|
||||
1. Отправьте коммиты хаба на `git.shx.one`:
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
2. В репозитории на `git.shx.one` откройте **Actions** и дождитесь зелёного прогона **Hub**:
|
||||
- job `check` проверяет типы и тесты хаба;
|
||||
- job `image` собирает образ и кладёт его в реестр.
|
||||
3. Убедитесь, что образ появился: в репозитории или профиле откройте **Packages**, там должен быть `technitium-hub` с тегом `latest`.
|
||||
|
||||
Если job `image` упал на входе в реестр, проверьте секрет `ACTION_PAT` (или `ACTIONS_PAT`) в настройках репозитория: это токен Gitea с правом `write:package`. Он тот же, что использует образ консоли.
|
||||
|
||||
Выпуск версии с номером (необязательно):
|
||||
```bash
|
||||
git tag hub-v1.0.0 && git push origin hub-v1.0.0
|
||||
```
|
||||
Тег даёт образы `1.0.0` и `1.0` в дополнение к `latest`.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 1. Пользователь только для чтения на каждом сервере
|
||||
|
||||
Сделайте это **на обоих серверах**: `https://dns.shnt.top` и `https://ndns.shnt.top`. Войдите в консоль сервера как администратор.
|
||||
|
||||
1. **Группа.** Administration › Groups › **Add Group**: имя `hub-readers`, описание любое.
|
||||
2. **Права группы.** Administration › Permissions: у группы `hub-readers` отметьте только **View** в четырёх разделах:
|
||||
|
||||
| Раздел | Зачем хабу |
|
||||
|---|---|
|
||||
| Dashboard | статистика, топы, график по часам, живые метрики |
|
||||
| Logs | список файлов логов и Query Logs |
|
||||
| Apps | список приложений логирования, из которых Query Logs читает записи |
|
||||
| Settings | состояние блокировки на Dashboard |
|
||||
|
||||
Modify и Delete не отмечайте нигде. Остальные разделы оставьте без прав.
|
||||
3. **Пользователь.** Administration › Users › **Add User**: имя `hub-reader`, длинный случайный пароль. Затем в карточке пользователя добавьте его в группу `hub-readers`. Из группы `Everyone` можно убрать, если у неё есть лишние права.
|
||||
4. **API-токен.** Нужен токен именно для `hub-reader`, а не для администратора:
|
||||
- выйдите из консоли и войдите под `hub-reader`;
|
||||
- в меню пользователя внизу слева выберите **Create API Token**, имя токена `hub`;
|
||||
- скопируйте токен сразу: его показывают один раз.
|
||||
|
||||
Можно и под администратором: Administration › Sessions › **Create Token**, пользователь `hub-reader`.
|
||||
5. Проверьте токен с любой машины. В ответе должно быть `"status":"ok"`:
|
||||
```bash
|
||||
curl -s "https://dns.shnt.top/api/dashboard/stats/get?type=LastHour&token=ТОКЕН" | head -c 200
|
||||
```
|
||||
- `"status":"invalid-token"` значит, что скопирован не тот токен;
|
||||
- `"status":"error"` с сообщением об отказе в доступе значит, что у группы не хватает права View.
|
||||
|
||||
Результат шага: два токена, `DNS_TOKEN` (с `dns.shnt.top`) и `NDNS_TOKEN` (с `ndns.shnt.top`).
|
||||
|
||||
---
|
||||
|
||||
## Шаг 2. DNS-запись для hub.shnt.top
|
||||
|
||||
В Cloudflare (зона `shnt.top`) создайте запись `hub` той же формы, что `dns`: `A` на IP хоста или `CNAME` на `dns.shnt.top`.
|
||||
|
||||
Сертификат Traefik получит сам. В compose уже настроен `certresolver=myresolver` с DNS-challenge через Cloudflare (`CF_DNS_API_TOKEN`), отдельно открывать порт 80 для проверки не нужно.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 3. Файл .env
|
||||
|
||||
На хосте в каталоге с `docker-compose.yml` откройте `.env` (там уже лежат `CF_DNS_API_TOKEN` и `DNS_SERVER_ADMIN_PASSWORD`) и добавьте:
|
||||
|
||||
```dotenv
|
||||
# Хаб: токены пользователей hub-reader с шага 1
|
||||
DNS_TOKEN=вставьте_токен_dns
|
||||
NDNS_TOKEN=вставьте_токен_ndns
|
||||
|
||||
# Вход в сам хаб (это НЕ логин Technitium)
|
||||
HUB_USER=admin
|
||||
HUB_PASSWORD=длинный_случайный_пароль
|
||||
```
|
||||
|
||||
Пароль хаба нужен длинный: у хаба нет ограничения числа попыток входа. Сгенерировать можно так:
|
||||
```bash
|
||||
openssl rand -base64 24
|
||||
```
|
||||
|
||||
Закройте `.env` от посторонних:
|
||||
```bash
|
||||
chmod 600 .env
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4. Сервис в compose
|
||||
|
||||
Добавьте в `docker-compose.yml` в раздел `services:` блок из `docs/compose.hub.example.yaml`:
|
||||
|
||||
```yaml
|
||||
technitium-hub:
|
||||
image: git.shx.one/denozord/technitium-hub:latest
|
||||
container_name: technitium-hub
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dns-net
|
||||
environment:
|
||||
# id=адрес, по порядку; токен каждого берётся из <ID>_TOKEN
|
||||
- HUB_SERVERS=dns=https://dns.shnt.top,ndns=https://ndns.shnt.top
|
||||
- DNS_TOKEN=${DNS_TOKEN}
|
||||
- NDNS_TOKEN=${NDNS_TOKEN}
|
||||
- HUB_USER=${HUB_USER}
|
||||
- HUB_PASSWORD=${HUB_PASSWORD}
|
||||
- HUB_DOMAIN=hub.shnt.top
|
||||
- TZ=Asia/Novosibirsk
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=dns-net"
|
||||
- "traefik.http.routers.hub.rule=Host(`hub.shnt.top`)"
|
||||
- "traefik.http.routers.hub.entrypoints=websecure"
|
||||
- "traefik.http.routers.hub.tls.certresolver=myresolver"
|
||||
- "traefik.http.routers.hub.service=hub-svc"
|
||||
- "traefik.http.services.hub-svc.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
Если хаб стоит в том же файле, что Traefik, отдельный блок `networks:` с `external: true` из примера не нужен: сеть `dns-net` в этом файле уже объявлена.
|
||||
|
||||
Про имена в `HUB_SERVERS`:
|
||||
- имя слева от `=` видно в консоли в селекторе «Server»;
|
||||
- из имени получается переменная токена: `dns` даёт `DNS_TOKEN`, `ndns` даёт `NDNS_TOKEN`, `my-dns` дал бы `MY_DNS_TOKEN`;
|
||||
- первый в списке сервер считается основным.
|
||||
|
||||
Адреса серверов указываются публичные (`https://dns.shnt.top`). API Technitium доступно по тому же адресу, что и консоль (роутер `panel-old` в Traefik), отдельный порт не нужен.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 5. Запуск
|
||||
|
||||
Если реестр закрытый, один раз войдите в него. Нужен токен Gitea с правом `read:package`:
|
||||
```bash
|
||||
docker login git.shx.one
|
||||
```
|
||||
|
||||
Скачайте образ и запустите хаб:
|
||||
```bash
|
||||
docker compose pull technitium-hub
|
||||
docker compose up -d technitium-hub
|
||||
```
|
||||
|
||||
Проверьте контейнер:
|
||||
```bash
|
||||
docker compose ps technitium-hub # STATUS: Up ... (healthy)
|
||||
docker compose logs -f technitium-hub
|
||||
```
|
||||
|
||||
В логе при старте не должно быть ошибок конфигурации. Если чего-то не хватает, хаб не запустится и назовёт переменную, например `NDNS_TOKEN is required for the server "ndns".`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 6. Проверка
|
||||
|
||||
1. Откройте `https://hub.shnt.top` и войдите с `HUB_USER` / `HUB_PASSWORD` из `.env`.
|
||||
2. На Dashboard над заголовком должен быть селектор **Server: All servers**.
|
||||
3. Сверьте цифры. Total Queries в «All servers» должна равняться сумме значений в консолях `dns.shnt.top` и `ndns.shnt.top` за тот же период. Расхождение в пределах минуты нормально: хаб кеширует ответы на 15 секунд, а Last Hour обновляется на ходу.
|
||||
4. Выберите в селекторе `dns`, затем `ndns`: цифры каждого сервера должны совпасть с его собственной консолью.
|
||||
5. Откройте Logs › Query Logs, нажмите **Query**. Записи обоих серверов идут вместе, в колонке **Server** видно, чья запись.
|
||||
6. Кнопка статуса справа в шапке показывает `hub.shnt.top`. Если какой-то сервер не ответил, там будет «1 server not answering», а по нажатию появится причина.
|
||||
|
||||
Проверка без браузера (подставьте пароль хаба):
|
||||
```bash
|
||||
T=$(curl -s -X POST https://hub.shnt.top/api/user/login \
|
||||
--data-urlencode "user=admin" --data-urlencode "pass=ПАРОЛЬ_ХАБА" | sed -E 's/.*"token":"([^"]+)".*/\1/')
|
||||
curl -s -H "Authorization: Bearer $T" "https://hub.shnt.top/api/dashboard/stats/get?type=LastHour" | head -c 300
|
||||
curl -s -H "Authorization: Bearer $T" "https://hub.shnt.top/api/dashboard/stats/get?type=LastHour&node=ndns" | head -c 300
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Обновление
|
||||
|
||||
После нового прогона **Hub** в Actions:
|
||||
```bash
|
||||
docker compose pull technitium-hub && docker compose up -d technitium-hub
|
||||
```
|
||||
Сессии хаба хранятся в памяти: после перезапуска контейнера нужно войти заново.
|
||||
|
||||
Чтобы закрепить версию, укажите в compose тег вместо `latest`, например `technitium-hub:1.0.0`.
|
||||
|
||||
## Остановка и удаление
|
||||
|
||||
```bash
|
||||
docker compose stop technitium-hub # остановить
|
||||
docker compose rm -f technitium-hub # удалить контейнер
|
||||
```
|
||||
|
||||
Чтобы отозвать доступ хаба к серверам, на каждом сервере удалите токен в Administration › Sessions или отключите пользователя `hub-reader`.
|
||||
|
||||
---
|
||||
|
||||
## Настройки хаба
|
||||
|
||||
| Переменная | По умолчанию | Что задаёт |
|
||||
|---|---|---|
|
||||
| `HUB_SERVERS` | обязательна | Серверы по порядку: `id=https://адрес,...` |
|
||||
| `<ID>_TOKEN` | обязательна для каждого | API-токен сервера (`DNS_TOKEN`, `NDNS_TOKEN`, ...) |
|
||||
| `HUB_USER`, `HUB_PASSWORD` | обязательны | Вход в хаб |
|
||||
| `HUB_DOMAIN` | `hub` | Имя, которое консоль показывает как имя сервера |
|
||||
| `HUB_CACHE_SECONDS` | `15` | Сколько секунд хранить ответы серверов (0 выключает кеш) |
|
||||
| `HUB_TIMEOUT_MS` | `8000` | Сколько ждать ответа сервера, мс |
|
||||
| `HUB_PORT` | `8080` | Порт внутри контейнера |
|
||||
|
||||
Третий сервер добавляется строкой в `HUB_SERVERS` и его токеном:
|
||||
```yaml
|
||||
- HUB_SERVERS=dns=https://dns.shnt.top,ndns=https://ndns.shnt.top,lab=https://lab.shnt.top
|
||||
- LAB_TOKEN=${LAB_TOKEN}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Если что-то не так
|
||||
|
||||
| Признак | Причина и что делать |
|
||||
|---|---|
|
||||
| Контейнер сразу завершается | В `docker compose logs technitium-hub` будет названа недостающая переменная. Проверьте `.env` и что compose его видит (`docker compose config \| grep TOKEN`). |
|
||||
| `https://hub.shnt.top` не открывается, ошибка сертификата | Нет DNS-записи `hub` (шаг 2) или Traefik ещё получает сертификат: смотрите `docker logs traefik`. |
|
||||
| 404 от Traefik | Контейнер не в сети `dns-net` или опечатка в `Host(\`hub.shnt.top\`)`. |
|
||||
| Вход в хаб: «Invalid username or password» | Неверные `HUB_USER`/`HUB_PASSWORD` в `.env`. После правки `.env` нужен `docker compose up -d technitium-hub`. |
|
||||
| В шапке «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). |
|
||||
| Query Logs пустой или «нет приложения» | На сервере не установлено приложение логирования (Query Logs (Sqlite) и подобные) или нет права View на Apps. |
|
||||
| Цифры «All servers» больше суммы на 1-2 клиента | Clients считается по каждому серверу отдельно: клиент, который ходит на оба сервера, учтён дважды. Это ожидаемо. |
|
||||
| Нажатие на что-то пишет «The hub is read-only.» | Хаб только читает. Изменения делаются в консоли нужного сервера. |
|
||||
|
||||
## Безопасность
|
||||
|
||||
- Хаб только читает: любая запись получает отказ ещё в хабе, а токены выданы пользователю с одними правами View.
|
||||
- Токены лежат только в `.env` на хосте и в памяти контейнера. В браузер они не попадают, в ответы и логи хаба не пишутся.
|
||||
- У хаба один общий логин и нет ограничения попыток входа. Нужен длинный пароль, а если хаб не должен быть виден из интернета, добавьте к роутеру `hub` в Traefik `ipallowlist` или `basicAuth`.
|
||||
Reference in new issue
Block a user