Files
lampac/README.md
T
prodik d03a0282f1 lampa-main в git: клиент переживает пересоздание контейнера
- каталог lampa-main/ (yumata/lampa) смонтирован bind-mountом в /lampac/wwwroot/lampa-main (override)
- в образе 1.72.0 клиента нет, LampaCron из GitHub не докачивает (нет доступа к GitHub) -> / отдавал 500
- README/AGENT: механика обновления клиента через git
- compose: 1.72.0, cache/database как bind-mountы, секреты в init.conf
2026-10-06 17:35:35 +03:00

346 lines
32 KiB
Markdown
Raw 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.
Lampac NextGen — локальный Docker-развёртывание
> Сервер: Proxmox VM 130 «lampac», Debian 13, 192.168.88.243, логин prodik. Детали — AGENT.md (раздел Размещение на сервере).
Локальное развёртывание [Lampac NextGen](https://github.com/lampac-nextgen/lampac) — самохостируемого бекенда для Lampa — в Docker. Официальная документация: [docs.lampac.dev](https://docs.lampac.dev).
## Быстрый старт
```bash
docker compose up -d # первый запуск
docker compose logs -f # логи (строки compilation / configure module / loaded module)
docker compose restart # после правки config/init.conf или манифестов в mods/
```
- Веб-клиент Lampa: **http://localhost:9118**
- Админ-панель: **http://localhost:9118/adminpanel** (root-пароль из `config/passwd`)
- TorrServer-прокси: `http://localhost:9118/ts/*` (порт TorrServer — 9085)
По умолчанию сервер слушает порт **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/`, `lampa-main/`).
## Секреты (вынесены из git)
Модули `TelegramBot`, `TelegramAuthBot`, `TelegramAuth` читают `bot_token` и `mutations_api_secret` из конфига. В репозитории эти поля **всегда пустые** — реальные значения живут в файле, который не коммитится.
| Файл | В git? | Назначение |
|---|---|---|
| `config/init.conf` | ✅ | Шаблон конфига, секреты **пустые**. Именно его редактируете для обычных настроек (`listen`, `SkipModules`, `initPlugins`, модули). |
| `config/secrets.env` | ❌ .gitignore | Токены ботов и `mutations_api_secret`. `TELEGRAM_NOTIFY_BOT_TOKEN`, `TELEGRAM_AUTH_BOT_TOKEN`, `TELEGRAM_AUTH_MUTATIONS_SECRET`. |
| `config/init.custom.conf` | ❌ .gitignore | Боевой конфиг, который монтируется в контейнер. Собирается из шаблона + `secrets.env` скриптом. |
| `scripts/config-secrets.py` | ✅ | Собирает/разбирает боевой конфиг: `apply`, `export`, `check`, `status`. |
| `scripts/install-git-hooks.sh` | ✅ | Устанавливает хуки: `post-merge`/`post-checkout` → `apply`, `pre-commit` → `check`. |
| `docker-compose.yaml` | ✅ | Монтирует `./config/init.custom.conf:/lampac/init.conf` (не `init.conf`). |
**Рабочий процесс:**
```bash
# первый раз / после git pull:
python3 scripts/config-secrets.py apply # init.custom.conf = шаблон + secrets.env
docker compose up -d # рекреация из-за нового mount
# правки в init.conf:
# 1) правите config/init.conf (шаблон)
# 2) python3 scripts/config-secrets.py apply -> обновляет init.custom.conf
# 3) docker compose restart lampac
# перед коммитом:
python3 scripts/config-secrets.py export # секреты -> пустые в шаблоне
git add config/init.conf
git commit -m "..."
```
**Git-хуки (рекомендуется):** `bash scripts/install-git-hooks.sh` — после `git pull`/смены ветки `apply` запустится сам, а `pre-commit` не даст случайно закоммитить секреты.
> `docker-compose.override.yml` (в .gitignore) — серверный override для Proxmox (том DLNA -> `/mnt/torrents`), живёт только на сервере.
## Структура проекта
| Путь | Назначение |
|---|---|
| `docker-compose.yaml` | Основной сервис (образ `ghcr.io/lampac-nextgen/lampac:1.68.1`) |
| `docker-compose.override.yml` | Серверный override (Proxmox: том DLNA -> `/mnt/torrents`), в .gitignore |
| `config/init.conf` | Шаблон конфига (JSON, в git, секреты **пустые**) |
| `config/init.custom.conf` | Боевой конфиг (в .gitignore, монтируется в `/lampac/init.conf`) |
| `config/secrets.env` | Токены ботов и `mutations_api_secret` (в .gitignore) |
| `config/passwd` | Пароль root для `/adminpanel` и `/weblog` (в .gitignore) |
| `lampa-main/` | Веб-клиент Lampa (в git, bind-mount в `/lampac/wwwroot/lampa-main`) |
| volume `lampac_cache` | Кеш (`/lampac/cache`) — 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` |
> Веб-клиент `lampa-main` **хранится в git** (каталог `lampa-main/`) и смонтирован bind-mountом в `/lampac/wwwroot/lampa-main` (в `docker-compose.override.yml` на сервере), поэтому переживает пересоздание контейнера. В образе клиента нет, а `LampaCron` автообновление из GitHub не докачивает (на сервере нет доступа к GitHub) — поэтому клиент держим в репозитории. Обновить клиент: скачать архив с https://github.com/yumata/lampa/archive/refs/heads/main.zip, распаковать в `lampa-main/` (топ-каталог `lampa-main-main` переименовать в `lampa-main`), `chown -R 1000:1000 lampa-main`, закоммитить; на сервере `git pull` — перезапуск не нужен (статика). См. также `scripts/restore-lampa-main.sh`.
## Включённые модули из `mods/`
Встроенные модули с `"enable": false` в `manifest.json` внутри образа **нельзя включать правкой файла в контейнере** — файлы пропадут при обновлении. Механика по официальной документации ([модули Lampac](https://docs.lampac.dev/modules/overview), [пользовательские модули](https://docs.lampac.dev/maintenance/custom-modules)):
1. Скопировать модуль из образа в `mods/<Имя>/` на хосте:
```bash
docker cp lampac:/lampac/module/<Имя> "mods/<Имя>"
```
2. В `mods/<Имя>/manifest.json` поставить `"enable": true`.
3. Добавить том в `docker-compose.yaml`:
```yaml
- ./mods/<Имя>:/lampac/mods/<Имя>
```
4. При необходимости добавить секцию модуля в `config/init.conf` (runtime-флаг).
5. `docker compose up -d` (при добавлении тома) или `restart` (при правке манифеста с `dynamic: true`).
### Сейчас подключены
| Модуль | Что даёт | Секция в init.conf |
|---|---|---|
| `Tracks` | `/tracks.js`, `/ffprobe` — субтитры и дорожки | `"Tracks": { "enable": true }` |
| `AdminPanel` | `/adminpanel` — редактор init.conf, current.conf, users.json | `"AdminPanel": { "enable": true }` |
| `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"` |
Клиентский плагин `tg-notify.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`, `Music`, `WatchTogether`.
## Конфигурация
- `config/init.conf` — JSON. После правки: `docker compose restart`. Следи за валидностью JSON (лишняя запятая ломает парсинг).
- `BaseModule.SkipModules` / `BaseModule.LoadModules` — фильтры загрузки модулей (имя, группа, regex). `SkipModules` имеет приоритет над `LoadModules`.
- `LampaWeb.initPlugins` — флаги встроенных плагинов веб-клиента; `LampaWeb.customPlugins` — дополнительные плагины (`status: 1`).
- `LampaWeb.autoupdate: true` — Lampa Web-клиент автообновляется из `yumata/lampa` (раз в 90 минут).
## Установка плагинов по ссылке через веб (AdminPanel)
Список плагинов, который сервер раздаёт всем клиентам через `/lampainit.js` и `/on.js`, собирается по `LampaWeb.initPlugins` + `LampaWeb.customPlugins`. Watcher перечитывает `init.conf` без перезапуска (интервал ~1 с, runtime-параметры применяются на лету).
1. Открой **http://localhost:9118/adminpanel**, введи root-пароль (содержимое `config/passwd`) — пароль сохраняется в cookie `accspasswd` (штатный механизм root-авторизации).
2. В редакторе `init.conf` открой секцию **`LampaWeb`** → **`customPlugins`** и добавь запись:
```json
{ "url": "https://example.com/plugin.js", "status": 1, "name": "ИмяПлагина" }
```
Поддерживается плейсхолдер `{localhost}` — сервер подставит свой адрес.
3. Сохрани — перезапуск не нужен. Проверка: `curl -s http://localhost:9118/lampainit.js | grep <имя>`.
Нюансы:
- `status: 1` — активная запись.
- Family-dedup: `name.js` и `name/js/{token}` считаются одним плагином; если в registry клиента уже есть один вариант, второй из серверного списка не добавляется.
- Внешние URL должны быть доступны из браузеров клиентов и отдавать CORS-заголовки.
- Альтернатива без сервера: вставить ссылку напрямую в веб-клиенте Lampa (настройки → «Плагины») — тогда плагин живёт только в localStorage этого браузера и грузится браузером напрямую.
API (для скриптов): `GET/POST /adminpanel/api/init`, `POST /adminpanel/api/init/section/{key}` с cookie `accspasswd=<root-пароль>`.
## Каталог плагинов (раздел «Плагины» в веб-клиенте)
В веб-клиенте Lampa раздел «Плагины» грузит каталог (store) с маршрута **`/extensions`** (включается при `LampaWeb.initPlugins.pirate_store: true`). Содержимое берётся из файла `LampaWeb/plugins/extensions.json` модуля — у нас он переопределён файловым mount из `./plugins/extensions.json` (см. `docker-compose.yaml`). Плейсхолдер `{localhost}` в ссылках сервер заменяет своим адресом.
**Все плагины каталога размещены локально** (mirror): `.js`-файлы лежат в `./plugins/`, каталог целиком смонтирован в `/lampac/wwwroot/plugins/` (одна строка в compose) и ссылки в каталоге ведут на `{localhost}/plugins/<имя>.js`. (Целиком в корень `wwwroot` монтировать нельзя — перекроется веб-клиент `lampa-main`.) Сами файлы плагинов всегда локальные; исключение — плагин-лоадеры, подгружающие основной код с внешнего хоста: «Клубничка 18+» (rc.bwa.ad) и Showy (showy.online/online.js — файл локально патчен под абсолютный URL, иначе он бы подгружал `/online.js` с нашего сервера). Остальные скачаны целиком (для pubtorr / torrentmanager / td скачано тело, а не лоадер).
- `plugins/sources.json` — карта «локальный файл → исходный URL». Для обновления плагина: скачать файл по исходному URL, перезаписать локальный, перезапуск не нужен.
- `plugins/modss.js` — локальная patched-копия MODS's (заменён вызов `Lampa.Utils.isPWA()`), раздаётся как `/plugins/modss.js`, но из каталога исключена (upstream мёртв: загрузчик отвечает stub-ошибкой «Используйте: lampa.mx»). Вернуть карточку можно, добавив запись с `link: "{localhost}/plugins/modss.js"`.
Удалены из каталога (мёртвы upstream, проверено по факту выдачи):
- «MODS's» (`lampa.stream/modss`) — загрузчик отвечает stub-ошибкой;
- «Отзывы и рецензии» (`lampaplugins.github.io/store/o.js`) — файл заменён автором на пустой stub;
- «Вторая кнопка Торренты», «Поиск локального TorrServer», «Горячие кнопки», «Золотая Тема», «Тип управления», «Старый стиль», «Мультфильмы» — публичных копий нет;
- «Телевидение by Skaz» / «ТВ by skaz» / «ТВ by skaz 2.0» — файлы заменены placeholder-заглушками;
- «Импорт/Экспорт закладок, истории» (`skaz.tv/export.js`) — 404.
Важный нюанс — **диск-кеш ответа**: маршруты LampaWeb кешируют ответы в `/lampac/cache/static/<bucket>/<id>.json` (named volume `lampac_cache`), кеш переживает рестарт контейнера. После правки `extensions.json` для мгновенного применения удалить закешированную запись:
```bash
docker exec lampac rm -rf /lampac/cache/static/59 # bucket /extensions; либо весь /lampac/cache/static
```
Перезапуск контейнера при этом **не требуется** (маршрут читает файл при каждом запросе, если нет кеш-записи).
## Tg-notify.bot: Telegram-бот уведомлений о новых сериях
Фоновый Telegram-бот (long polling): пользователь подписывается на сериал прямо из карточки Lampa, бот отслеживает выход новых эпизодов и появление выбранной озвучки и шлёт в Telegram уведомление с обложкой, номером серии и описанием из TMDB.
Модуль объединяет три подсистемы:
1. **Трекер новых серий** — Trakt API (если задан `trakt_client_id`), иначе TMDB.
2. **Трекер озвучек** — параллельный опрос встроенных балансиров **Mirage**, **Collaps** и **VideoHub** через `lampac_host` (`/lite/mirage`, `/lite/collaps`, `/lite/cdnvideohub`); берётся максимальный эпизод из всех источников.
3. **Клиентский плагин** `tg-notify.js` — вкладка «TG Подписки», перехват кнопки 🔔 в карточке, меню выбора озвучки.
### Как это работает (поток)
1. **Привязка аккаунта** — во вкладке «TG Подписки» в Lampa выдаётся deep-link `/start link_{uid}` (для UID вида email — `/start link64_{base64url(uid)}`). После `/start` бот сохраняет связку `chat_id ↔ lampac_uid` в `database/tgnotify/users.json`; подписки становятся общими для всех устройств этого аккаунта.
2. **Подписка** — в карточке сериала кнопка 🔔 перехватывается плагином, показывается меню озвучек (`GET /api/tg/voices`), выбор уходит на `POST /api/tg/subscribe` и сохраняется в `subscriptions.json`.
3. **Фоновый цикл `CheckAll`** — раз в `check_interval_minutes` (первый прогон — через 2 минуты после старта, вручную — `/check`): новые серии через Trakt→TMDB; если выбрана конкретная озвучка — параллельно Mirage + Collaps + VideoHub.
4. **Уведомление** — сообщение вида:
```
🎬 Название
🎙 Озвучка
📺 S05E08 — Название эпизода
Описание (до 300 символов)
```
с обложкой кадра из TMDB (`still_path`), если есть.
### Конфигурация (секция `TelegramBot` в `config/init.conf`)
| Поле | Назначение |
|---|---|
| `bot_token` | Токен от [@BotFather](https://t.me/BotFather). **Обязателен** — без него long polling не стартует (в логе предупреждение, сервер работает) |
| `tmdb_api_key` | Ключ TMDB v3: обложки, описания эпизодов, определение актуального сезона |
| `trakt_client_id` | Client ID Trakt; основной источник новых серий (если пуст — только TMDB) |
| `lampac_host` | Базовый URL Lampac для запросов к балансерам; в Docker — `http://127.0.0.1:9118` |
| `lampac_token` | Токен `accsdb`; обязателен, если включена защита (иначе балансеры вернут ошибку входа) |
| `kp_api_key` | Ключ kinopoiskapiunofficial.tech — резолвинг `tmdb_id → kinopoisk_id` по названию для VideoHub (опционально; без него покрытие ~40% через мост `/externalids`) |
| `check_interval_minutes` | Период фоновой проверки (дефолт 60) |
| `tmdb_lang` | Язык метаданных TMDB (дефолт `ru-RU`, фоллбэк `en-US`) |
| `data_dir` | Каталог `users.json`/`subscriptions.json` (дефолт `database/tgnotify` — у нас это том `./database/`, переживает рестарты) |
### Быстрый старт
1. [@BotFather](https://t.me/BotFather) → `/newbot` → получить токен.
2. `config/init.conf` → `TelegramBot.bot_token` = токен.
3. `docker compose restart lampac` (по желанию — заполнить `tmdb_api_key` и `trakt_client_id`).
4. В Lampa (http://localhost:9118) вкладка «TG Подписки» → deep-link → `/start` у бота.
5. В карточке сериала — 🔔, выбрать озвучку (или «без озвучки» — уведомление о самом факте выхода серии).
### Команды бота
| Команда | Действие |
|---|---|
| `/start` | Приветствие; `/start link_{uid}` — привязка аккаунта |
| `/list` | Список активных подписок |
| `/check` | Принудительная проверка в фоне |
| `/help` | Справка |
| `/unlink` | Отвязать аккаунт |
### HTTP API
| Метод | Маршрут | Назначение |
|---|---|---|
| `GET` | `/tg-notify.js` | Раздача клиентского плагина (AllowAnonymous) |
| `POST` | `/api/tg/subscribe` | Подписка на сериал/озвучку |
| `POST` | `/api/tg/unsubscribe` | Отписка |
| `GET` | `/api/tg/status?tmdb_id=` | Статус подписки текущего пользователя |
| `GET` | `/api/tg/voices?title=&year=&season=&tmdb_id=` | Доступные озвучки (Mirage + Collaps + VideoHub) |
| `GET` | `/api/tg/link` | Deep-link для привязки бота |
| `GET` | `/api/tg/subscriptions` | Все подписки пользователя с метаданными |
Все маршруты, кроме `/tg-notify.js` и `/api/tg/voices`, требуют `requestInfo.user_uid` (вход в аккаунт).
### Состояние на нашем инстансе
- Модуль загружен, `/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
Пара модулей из группы **Community** — замена пароля аккаунта подтверждением в Telegram (сценарий: ТВ, где вводить пароль неудобно). Не путать с Tg-notify.bot — тот только уведомляет о сериях.
- **`TelegramAuth`** — серверная часть: хранение пользователей/устройств, HTTP API `/tg/auth/*`, синхронизация UID в `accsdb`; **Telegram Auth Gate** — вместо экрана `deny.js` (модалка пароля) показывает fullscreen-оверлей с UID, кнопкой «Открыть Telegram» и QR-кодом на крупных экранах.
- **`TelegramAuthBot`** — long-polling бот: пользователь открывает бота (`/start link_{uid}` или отправляет UID), бот сам вызывает `POST /tg/auth/bind/complete`; есть админ-команды. HTTP UI нет.
Активация гейта — только при трёх условиях сразу: `accsdb.enable: true` + `LampaWeb.telegramAuthGate.enabled: true` + непустой `botUsername`. Иначе тихий откат на `deny.js`.
Конфиг (по образцу `init.merge.example.json` модулей):
```json
"TelegramAuth": {
"enable": true,
"mutations_api_secret": "SECRET"
},
"TelegramAuthBot": {
"enable": true,
"bot_token": "ТОКЕН_ОТ_BOTFATHER",
"mutations_api_secret": "SECRET"
},
"LampaWeb": {
"telegramAuthGate": {
"enabled": true,
"botUsername": "имя_бота_без_@",
"serviceName": "lampa"
}
}
```
`mutations_api_secret` должен совпадать в обоих модулях и быть ненулевым — защищает `bind/complete` и бот-админку; вместе с `bot_token` не публиковать. Оба модуля выключены в `base.conf` (`SkipModules`) и в манифестах (`enable: false`).
**Состояние у нас:** модули **включены** (копии в `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 получат отказ.
## Обновление Lampac
```bash
docker compose pull
docker compose up -d
```
Перед обновлением проверить, что в `docker-compose.yaml` раскомментированы нужные тома. Данные сохраняются в примонтированных томах: `config/`, `cache/`, `database/`, `dlna/`, `mods/`, `lampa-main/`.
`wwwroot/lampa-main` смонтирован как bind-mount из `./lampa-main/` (см. раздел «Структура проекта»), поэтому переживает рекреацию контейнера. Если директория на хосте пуста — `bash scripts/restore-lampa-main.sh scripts/lampa-main.zip` (архив берётся с https://github.com/yumata/lampa/archive/refs/heads/main.zip).
**Образ закреплён точным 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.
## Безопасность
По предупреждению официальной документации:
- Не публикуй в интернет без аутентификации, WAF и ограничения сети: `/adminpanel`, `/weblog`, `/database-editor`, `Tracks`, `Transcoding`, `Catalog`, `DLNA`, proxy-модули.
- Нигде не раскрывай `config/passwd`, cookie `accspasswd`, заголовок `lcrqpasswd`.
- **Секреты в git не попадают**: `TelegramBot.bot_token`, `TelegramAuthBot.bot_token`, `mutations_api_secret` хранятся в `config/secrets.env` (в .gitignore). В git `config/init.conf` эти поля всегда пустые. Реальный боевой конфиг — `config/init.custom.conf` (тоже gitignored), собирается скриптом `scripts/config-secrets.py apply` из шаблона + секретов. Перед `git add config/init.conf`: `python3 scripts/config-secrets.py check` → должно быть `check: секретов в config/init.conf нет — ок`.
- Для публикации за reverse proxy: [deployment/reverse-proxy](https://docs.lampac.dev/deployment/reverse-proxy) (HTTPS в ответах, реальный IP клиента, WebSocket, SSE, streaming).
- `shm_size: 4096mb` — рекомендованный минимум для Playwright/Chromium.