TelegramAuth + TelegramAuthBot + WatchTogether; README/AGENT
- mods/TelegramAuth, mods/TelegramAuthBot, mods/WatchTogether: копии из образа с enable: true (правило 1), секции в config/init.conf - TelegramAuth в API-режиме (enable: false -> accsdb/гейт не поднимается), TelegramAuthBot: бот @GatusMonBot, long polling - WatchTogether: customPlugins watchtogether.js, relay /wt/c/ - README: секция про SQLite/volume (первый запуск), таблица модулей, состояние Tg-notify и TelegramAuth, раздел WatchTogether - AGENT: правило 10 дополнено секретами init.conf, §12 переписан, добавлен §13 WatchTogether, список mods/ в §1 - в git bot_token и mutations_api_secret оставлены пустыми (правило 10), реальные значения только в рабочем файле на сервере
This commit is contained in:
@@ -16,6 +16,56 @@ docker compose restart # после правки config/init.conf или
|
||||
|
||||
По умолчанию сервер слушает порт **9118**; если порт занят — меняй `listen.port` в `config/init.conf` до первого запуска.
|
||||
|
||||
## Первая установка: SQLite не может создать базу в named volume
|
||||
|
||||
**Симптом.** Свежий `docker compose up -d` уходит в crash-loop (`Restarting (139)`, healthcheck `unhealthy`), в логах:
|
||||
|
||||
```
|
||||
Unhandled exception. Microsoft.Data.Sqlite.SqliteException (0x80004005):
|
||||
SQLite Error 14: 'unable to open database file'.
|
||||
at Microsoft.Data.Sqlite.SqliteConnection.Open()
|
||||
at Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal.SqliteDatabaseCreator.Create()
|
||||
at Microsoft.EntityFrameworkCore.RelationalDatabaseCreator.EnsureCreated()
|
||||
at Core.Program.Run(String[] args)
|
||||
```
|
||||
|
||||
**Причина.** Процесс в контейнере работает от uid `1000` (пользователь образа `lampac`), а Docker при первом создании named volume делает его владельцем `root:root`. Смонтированный каталог `/lampac/database` поэтому недоступен на запись для `lampac`, `sqlite3` получает `EACCES` и приложение падает сразу после `EnsureCreated()` — база не создаётся ни разу, поэтому изнутри контейнера это не лечится.
|
||||
|
||||
Та же первопричина у второй ошибки первого запуска:
|
||||
|
||||
```
|
||||
System.UnauthorizedAccessException: Access to the path '/lampac/passwd' is denied.
|
||||
```
|
||||
|
||||
`config/passwd` монтируется файлом и тоже должен принадлежать uid `1000`.
|
||||
|
||||
**Лечение** — на хосте, от root:
|
||||
|
||||
```bash
|
||||
# тома (первый запуск или миграция/копия томов)
|
||||
chown -R 1000:1000 /var/lib/docker/volumes/lampac_database/_data \
|
||||
/var/lib/docker/volumes/lampac_cache/_data
|
||||
|
||||
# файл пароля (владелец 1000, права 600 — читает только процесс контейнера)
|
||||
chown 1000:1000 config/passwd && chmod 600 config/passwd
|
||||
|
||||
docker compose up -d # или docker compose restart, если контейнер уже создан
|
||||
```
|
||||
|
||||
**Проверка:**
|
||||
|
||||
```bash
|
||||
docker compose ps # Up (healthy)
|
||||
docker logs --since 2m lampac | grep -ci unhandled # 0
|
||||
ls -ln /var/lib/docker/volumes/lampac_database/_data/Sisi.sql # uid/gid 1000
|
||||
```
|
||||
|
||||
> После лечения в `lampac_database` должны появиться `Sisi.sql`, `Sync.sql`, `TimeCode.sql`, `tgnotify/`, `tracks/`, `storage/` — это и есть признак, что базы созданы.
|
||||
|
||||
Проверить uid процесса в контейнере: `docker exec lampac id` → `uid=1000(lampac)`.
|
||||
|
||||
Правило: **любой bind-mount файл/каталог, в который пишет контейнер, должен принадлежать `1000:1000`** (см. `.gitignore` для `config/passwd`, `dlna/`).
|
||||
|
||||
## Структура проекта
|
||||
|
||||
| Путь | Назначение |
|
||||
@@ -24,7 +74,7 @@ docker compose restart # после правки config/init.conf или
|
||||
| `config/init.conf` | Конфигурация сервера (JSON, монтируется в `/lampac/init.conf`) |
|
||||
| `config/passwd` | Пароль root для `/adminpanel` и `/weblog` (не в git) |
|
||||
| volume `lampac_cache` | Кеш (`/lampac/cache`) — Docker named volume, не файловый том |
|
||||
| volume `lampac_database` | SQLite-базы Sync, TimeCode, Music, tg-notify (`/lampac/database`) — Docker named volume |
|
||||
| volume `lampac_database` | SQLite-базы Sync, TimeCode, tg-notify, tracks, storage (`/lampac/database`) — Docker named volume |
|
||||
| `dlna/` | Локальные медиа для DLNA (`/lampac/data/dlna`) |
|
||||
| `plugins/extensions.json` | Каталог плагинов для веб-клиента (раздел «Плагины»), отдаётся через `/extensions` |
|
||||
| `mods/<Имя>/` | Пользовательские копии встроенных модулей с `enable: true` |
|
||||
@@ -53,14 +103,18 @@ docker compose restart # после правки config/init.conf или
|
||||
|---|---|---|
|
||||
| `Tracks` | `/tracks.js`, `/ffprobe` — субтитры и дорожки | `"Tracks": { "enable": true }` |
|
||||
| `AdminPanel` | `/adminpanel` — редактор init.conf, current.conf, users.json | `"AdminPanel": { "enable": true }` |
|
||||
| `Music` | `/music.js`, `/music/*` — музыкальный каталог, плейлисты, стримы | секция `"Music"` (базовые дефолты) |
|
||||
| `Tg-notify.bot` | `/tg-notify.js`, `/api/tg/*` — уведомления о новых сериях в Telegram | секция `"TelegramBot"` |
|
||||
| `TelegramAuth` | `/tg/auth/*` — привязка UID устройства к учётке Telegram, HTTP API статуса | секция `"TelegramAuth"` (`enable: false` → без accsdb-гейта) |
|
||||
| `TelegramAuthBot` | `@GatusMonBot` — long-polling бот привязки и админ-команды | секция `"TelegramAuthBot"` |
|
||||
| `WatchTogether` | `/watchtogether.js`, `/watch_together/`, WS `/wt/c/` — комнаты синхронного просмотра | секция `"WatchTogether"` |
|
||||
|
||||
Клиентские плагины `music.js` и `tg-notify.js` зарегистрированы в `LampaWeb.customPlugins`; `{localhost}` в URL автоматически подставляется сервером.
|
||||
Клиентские плагины `tg-notify.js` и `watchtogether.js` зарегистрированы в `LampaWeb.customPlugins`; `{localhost}` в URL автоматически подставляется сервером.
|
||||
|
||||
> **Модуль `Music` удалён из `mods/`** (коммит `remove Music`): в образе у него `manifest.enable: false`, поэтому `/music.js` → 404, секция `"Music"` из `init.conf` убрана, плагин из `customPlugins` убран. Вернуть музыку — той же механикой: скопировать `lampac:/lampac/module/Music` в `mods/Music`, поставить `enable: true`, вернуть секцию и плагин.
|
||||
|
||||
### Ещё можно включить тем же способом
|
||||
|
||||
В образе выключены также: `DatabaseEditor`, `ExternalBind`, `LogUserRequest-Lite`, `Transcoding`, `WatchTogether`, `TelegramAuth`, `TelegramAuthBot`.
|
||||
В образе выключены также: `DatabaseEditor`, `ExternalBind`, `LogUserRequest-Lite`, `Transcoding`, `Music`.
|
||||
|
||||
## Конфигурация
|
||||
|
||||
@@ -187,8 +241,8 @@ docker exec lampac rm -rf /lampac/cache/static/59 # bucket /extensions; либ
|
||||
|
||||
### Состояние на нашем инстансе
|
||||
|
||||
- Модуль загружен, `/tg-notify.js` → 200, плагин уже в `LampaWeb.customPlugins`, вкладка «TG Подписки» видна.
|
||||
- `bot_token` **пуст** → long polling не работает (лог: `[TelegramBot] Установите bot_token…`); уведомления придут только после заполнения токена.
|
||||
- Модуль загружен, `/tg-notify.js` → 200, плагин уже в `LampaWeb.customPlugins`, вкладка «TG Подписки» видна; аккаунт привязан (`database/tgnotify/users.json`).
|
||||
- `bot_token` заполняется **только локально**: в git поле пустое (правило 10), токен вставлен в `config/init.conf` на сервере и при работе `@KlinkerZabbixBot` (`[TelegramBot] @KlinkerZabbixBot запущен!`). После любого `git pull`/правки конфига токен нужно вернуть на место — иначе polling не стартует.
|
||||
- Трекинг озвучек зависит от балансиров: на текущий момент `GET /lite/mirage` → тело `disable`, `GET /lite/collaps` → `503` — до тех пор, пока они не будут доступны (или не включится `lampac_token` при защите), бот будет уведомлять только о выходе серий (TMDB/Trakt).
|
||||
|
||||
## TelegramAuth + TelegramAuthBot: вход в Lampa через Telegram
|
||||
@@ -223,7 +277,29 @@ docker exec lampac rm -rf /lampac/cache/static/59 # bucket /extensions; либ
|
||||
|
||||
`mutations_api_secret` должен совпадать в обоих модулях и быть ненулевым — защищает `bind/complete` и бот-админку; вместе с `bot_token` не публиковать. Оба модуля выключены в `base.conf` (`SkipModules`) и в манифестах (`enable: false`).
|
||||
|
||||
**Состояние у нас:** выключены, `accsdb` в `init.conf` не включён → гейт неактивен, используем беззащитный доступ + root-пароль AdminPanel. Включать связку имеет смысл вместе с `accsdb` (защита сервера учётными записями).
|
||||
**Состояние у нас:** модули **включены** (копии в `mods/TelegramAuth/` и `mods/TelegramAuthBot/`, манифесты `enable: true`, `SkipModules` пуст), работают в **API-режиме**: `TelegramAuth.enable: false` → `accsdb` не поднимается, гейт неактивен, доступ не режется. Бот `@GatusMonBot` — `Telegram API OK`, long polling идёт; `owner_telegram_ids: [143672]` создаёт владельца ролью `admin` при старте, `auto_provision_users: true` + `auto_provision_activate_immediately: false` — новые привязки висят в pending до одобрения кнопкой у админа. Секрет `mutations_api_secret` (одинаков в обеих секциях) и `bot_token` лежат в `config/init.conf` **только на сервере**.
|
||||
|
||||
**Порядок включения гейта (когда решим):** поставить `TelegramAuth.enable: true` → в `LampaWeb` секцию `telegramAuthGate` (`enabled: true`, `botUsername: "GatusMonBot"`) → подключить клиентский оверлей (`deny.js` / `telegram_auth_gate.js`) → **сначала связать свои устройства через бота**, иначе текущие UID получат отказ.
|
||||
|
||||
## WatchTogether: комнаты синхронного просмотра
|
||||
|
||||
Модуль из группы «клиент и контент»: синхронизирует `play/pause/seek` между участниками комнаты. Подробный разбор — [официальная документация](https://docs.lampac.dev/modules/watch-together) и `mods/WatchTogether/README.md`.
|
||||
|
||||
**Как устроено.** Lampac не отдаёт медиа — он пассивный брокер: хранит состояние комнаты и рассылает команды. Сами видео каждый клиент тянет своим источником, поэтому подходит любой контент и совместим с экосистемой LParty (`lparty.js`, `lparty-web`, JustPlus Player).
|
||||
|
||||
| Клиент | Адрес |
|
||||
|---|---|
|
||||
| Плагин Lampa | `{localhost}/watchtogether.js` (в `LampaWeb.customPlugins`) |
|
||||
| Веб-гость без установки Lampa | `http://<адрес>/watch_together/?room=<base64(КОД:пароль)>` |
|
||||
| LParty relay (WebSocket) | `ws://<адрес>/wt/c/` |
|
||||
|
||||
Фирменная фича — **«тень» (`ShadowHost.cs`)**: сервер слушает канал и копирует url, позицию, скорость и список участников, виден в зрителях как `Lampac`, но ничего не рассылает. Как только хост рвётся, он мгновенно шлёт кадр `host` и продолжает timeline (лаг ≤ 2 с), попытки перехвата отклоняет повторным `host=сервер`; создатель вернулся — отдаёт роль обратно и снова уходит в тень. Пустые комнаты GC через `gc_empty_timeout_minutes`, любые — через `gc_max_lifetime_hours`.
|
||||
|
||||
**Конфиг** (секция `WatchTogether` в `init.conf`): `enable: true`, `allow_anonymous: true` (плагин и веб-гость без аккаунта), `relay_max_channels: 500`, `relay_max_clients_per_channel: 32`, `gc_empty_timeout_minutes: 30`, `gc_max_lifetime_hours: 12`.
|
||||
|
||||
**Требование к reverse proxy:** на `/wt/c/` нужен WebSocket upgrade, отключённый response buffering и таймаут **больше длительности просмотра**. Сейчас прокси нет — relay работает напрямую, ничего настраивать не нужно.
|
||||
|
||||
**Проверка:** `GET /watchtogether.js` → 200, `GET /watch_together/` → 200, `WS /wt/c/` → 400 на обычном GET (штатно: нужен upgrade; handshake даёт 101).
|
||||
|
||||
## Обновление Lampac
|
||||
|
||||
@@ -234,7 +310,7 @@ docker compose up -d
|
||||
|
||||
Перед обновлением проверить, что в `docker-compose.yaml` раскомментированы нужные тома. Данные сохраняются в примонтированных томах: `config/`, `cache/`, `database/`, `dlna/`, `mods/`.
|
||||
|
||||
**Образ закреплён точным digest** (`1.68.0@sha256:752dafd8…`): тег `1.68.0` на ghcr — mutable, его переиздавали, и в новой сборке `mods/Music` (копия из старой сборки) не компилируется (`MusicMetadataCacheService` не найден) — сервер уходит в crash-loop. Чтобы обновить образ: взять новый digest, пересобрать копии модулей в `mods/` из нового образа (иначе Roslyn-компиляция упадёт) и заменить digest в `docker-compose.yaml`.
|
||||
**Образ закреплён точным digest** (`1.68.0@sha256:752dafd8…`): тег `1.68.0` на ghcr — mutable, его переиздавали, и в новой сборке **копии модулей в `mods/`** (Roslyn компилирует их на каждом старте) перестают собираться — `CS0103` по символам из старого билда и crash-loop сервера. Чтобы обновить образ: взять новый digest, пересобрать копии модулей в `mods/` из нового образа (`docker cp lampac:/lampac/module/<Имя> mods/<Имя>` + вернуть `"enable": true`) и заменить digest в `docker-compose.yaml`. Не делать «просто» `docker compose pull` без фиксации digest.
|
||||
|
||||
## Безопасность
|
||||
|
||||
@@ -242,5 +318,6 @@ docker compose up -d
|
||||
|
||||
- Не публикуй в интернет без аутентификации, WAF и ограничения сети: `/adminpanel`, `/weblog`, `/database-editor`, `Tracks`, `Transcoding`, `Catalog`, `DLNA`, proxy-модули.
|
||||
- Нигде не раскрывай `config/passwd`, cookie `accspasswd`, заголовок `lcrqpasswd`.
|
||||
- **Секреты в `config/init.conf` не коммитятся**: `TelegramBot.bot_token`, `TelegramAuthBot.bot_token`, `mutations_api_secret`. В git они должны быть пустыми — реальные значения живут только в файле на сервере (`/root/init.conf.local` — резервная копия перед мержем). Перед `git add config/init.conf` проверять `git diff` на токены (`git diff config/init.conf | grep -E ":[0-9]{8,}:AA"` → пусто).
|
||||
- Для публикации за reverse proxy: [deployment/reverse-proxy](https://docs.lampac.dev/deployment/reverse-proxy) (HTTPS в ответах, реальный IP клиента, WebSocket, SSE, streaming).
|
||||
- `shm_size: 4096mb` — рекомендованный минимум для Playwright/Chromium.
|
||||
|
||||
Reference in New Issue
Block a user