feat: add backups feature
This commit is contained in:
@@ -49,6 +49,8 @@
|
||||
|
||||
Обычно эти значения не требуют правки.
|
||||
|
||||
Настройки `BACKUP_*` управляют автоматическими бэкапами и восстановлением. Практический сценарий, mount compose-папки и проверки архивов описаны в [разделе про бэкапы](../features/backups.md).
|
||||
|
||||
| Переменная | Назначение |
|
||||
| --- | --- |
|
||||
| `WEBAPP_ME_CACHE_TTL_SECONDS` | TTL кеша `/api/me`. |
|
||||
@@ -71,6 +73,25 @@
|
||||
| `TARIFF_WORKER_LOCK_TTL_SECONDS` | TTL Redis lock для tariff worker. |
|
||||
| `TARIFF_WORKER_TICK_SECONDS` | Интервал tariff worker. |
|
||||
| `TARIFF_WORKER_BULK_PANEL_FETCH_THRESHOLD` | Порог активных подписок для bulk fetch пользователей панели. |
|
||||
| `BACKUP_ENABLED` | Включает периодические бэкапы в worker-контейнере. По умолчанию `False`. |
|
||||
| `BACKUP_INTERVAL_SECONDS` | Интервал между бэкапами. По умолчанию `3600`; запуск выравнивается на границу часа: 12:00, 13:00 и т.д. |
|
||||
| `BACKUP_CHAT_ID` | Telegram chat ID для архивов. Если пусто, используется `LOG_CHAT_ID`. |
|
||||
| `BACKUP_THREAD_ID` | Topic/thread ID для архивов. Если пусто, используется `LOG_THREAD_ID`. |
|
||||
| `BACKUP_DIR` | Локальная папка архивов внутри контейнера. По умолчанию `data/backups` в volume `shop-data`. |
|
||||
| `BACKUP_LOCAL_RETENTION` | Сколько локальных ZIP-архивов хранить после отправки. По умолчанию `100`. |
|
||||
| `BACKUP_POSTGRES_DUMP_ENABLED` | Добавлять в архив `pg_dump` базы PostgreSQL. |
|
||||
| `BACKUP_PG_DUMP_PATH` | Путь к `pg_dump` внутри worker-контейнера. |
|
||||
| `BACKUP_PG_DUMP_TIMEOUT_SECONDS` | Таймаут выполнения `pg_dump`. |
|
||||
| `BACKUP_PG_RESTORE_PATH` | Путь к `pg_restore` внутри backend-контейнера для восстановления из админки. |
|
||||
| `BACKUP_PG_RESTORE_TIMEOUT_SECONDS` | Таймаут выполнения `pg_restore`. |
|
||||
| `BACKUP_ARCHIVE_SIGNATURE_REQUIRED` | Требовать валидную HMAC-подпись `manifest.json` при upload/restore. По умолчанию `True`. |
|
||||
| `BACKUP_ARCHIVE_SIGNATURE_SECRET` | Отдельный секрет подписи backup-архивов. Если пусто, используется `BOT_TOKEN`. |
|
||||
| `BACKUP_COMPOSE_ENABLED` | Добавлять snapshot compose-каталога в архив. Если mount отсутствует, бэкап БД не падает. |
|
||||
| `BACKUP_COMPOSE_SOURCE_DIR` | Путь внутри контейнера к compose-каталогу. В стандартном compose это `/app/compose-source`. |
|
||||
| `BACKUP_COMPOSE_RESTORE_DIR` | Куда восстанавливать compose-файлы. Если пусто, используется `BACKUP_COMPOSE_SOURCE_DIR`. |
|
||||
| `BACKUP_COMPOSE_EXCLUDE_DIRS` | Имена директорий, которые не попадают в compose snapshot. |
|
||||
| `COMPOSE_BACKUP_SOURCE` | Host-путь, который Docker Compose монтирует как `/app/compose-source`. По умолчанию текущая папка compose-файла. |
|
||||
| `COMPOSE_RESTORE_MODE` | Режим mount для backend: `rw` позволяет восстанавливать compose-папку из админки, `ro` оставляет только чтение. |
|
||||
|
||||
## Общие настройки
|
||||
|
||||
@@ -109,6 +130,8 @@
|
||||
|
||||
Часть внешнего вида (`WEBAPP_PRIMARY_COLOR`, `WEBAPP_LOGO_*`, `WEBAPP_FAVICON_*`) сохранена для совместимости, но env-значения этих полей игнорируются при загрузке. Настраивайте их в **Админка -> Внешний вид**.
|
||||
|
||||
Практическая настройка Mini App вынесена в [веб-приложение](../features/web-app.md), а вход через Telegram - в [Telegram-авторизацию](../features/telegram-auth.md).
|
||||
|
||||
| Переменная | Где менять | Назначение |
|
||||
| --- | --- | --- |
|
||||
| `WEBAPP_ENABLED` | `.env` / админка | Включает Web App. Если `False`, пользовательский Web App и админка недоступны до включения через `.env` и рестарта. |
|
||||
@@ -143,6 +166,8 @@
|
||||
|
||||
Вход по email появляется только если заполнены `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD` и `SMTP_FROM_EMAIL`.
|
||||
|
||||
Практический сценарий настройки SMTP, magic link и парольного входа описан в [разделе входа по email](../features/email-login.md).
|
||||
|
||||
| Переменная | Назначение |
|
||||
| --- | --- |
|
||||
| `SMTP_HOST` | SMTP host. |
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
- редактор разрешенных настроек приложения из manifest-файла;
|
||||
- раздел **Внешний вид** для логотипа, emoji-логотипа, выбора темы, accent-цвета, масштаба логотипа и предпросмотра тем;
|
||||
- раздел **Инструкции подключения** для встроенной страницы установки, поведения кнопок бота и Remnawave Subscription Page config;
|
||||
- раздел **Бэкапы** для просмотра локальных ZIP-архивов, загрузки архива и восстановления БД/compose-папки;
|
||||
- редактор JSON-каталога тарифов;
|
||||
- загрузка Internal Squads из Remnawave для выбора в тарифах.
|
||||
|
||||
@@ -58,6 +59,10 @@
|
||||
|
||||
Для каждого платежного метода в разделе провайдера доступны настройки отображения `PAYMENT_<METHOD>_WEBAPP_LABEL_RU`, `PAYMENT_<METHOD>_WEBAPP_LABEL_EN`, `PAYMENT_<METHOD>_WEBAPP_ICON`, `PAYMENT_<METHOD>_TELEGRAM_LABEL_RU`, `PAYMENT_<METHOD>_TELEGRAM_LABEL_EN` и `PAYMENT_<METHOD>_TELEGRAM_EMOJI`. Пустое значение возвращает мультиязычное значение по умолчанию из модуля платежного провайдера. Иконка Web App выбирается из уже подключенных lucide-иконок (`frontend/src/lib/components/ui/icons.js`) через модалку в админке.
|
||||
|
||||
## Бэкапы
|
||||
|
||||
Раздел **Система -> Бэкапы** показывает архивы из `data/backups`, принимает upload ZIP-файла и запускает восстановление БД/compose-папки с предварительной проверкой архива. Подробная эксплуатационная инструкция: [бэкапы и восстановление](backups.md).
|
||||
|
||||
## Переводы
|
||||
|
||||
Раздел **Система -> Переводы** позволяет переопределять отдельные строки из `locales/ru.json` и `locales/en.json` без монтирования полного файла локализации. Строки сгруппированы по месту применения: админка, Mini App, Telegram-бот, платежи, подписки, поддержка и другие группы.
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# Бэкапы и восстановление
|
||||
|
||||
Minishop умеет автоматически собирать ZIP-бэкапы в worker-контейнере, хранить последние архивы на сервере, отправлять их в Telegram и восстанавливать БД/compose-папку из админки.
|
||||
|
||||
## Что попадает в архив
|
||||
|
||||
Архив создается в `BACKUP_DIR`, по умолчанию `data/backups` внутри volume `shop-data`.
|
||||
|
||||
Типовой файл называется так:
|
||||
|
||||
```text
|
||||
remnawave-minishop-backup-20260527-120000+0300.zip
|
||||
```
|
||||
|
||||
Внутри:
|
||||
|
||||
- `database/<POSTGRES_DB>.dump` - `pg_dump` в custom format для `pg_restore`;
|
||||
- `compose/` - snapshot папки с `docker-compose.yml`, `.env` и соседними конфигами;
|
||||
- `manifest.json` - дата создания, сведения о БД, compose snapshot и предупреждения.
|
||||
|
||||
Если compose-папка не смонтирована или недоступна, worker не роняет весь бэкап: архив будет создан с дампом БД и предупреждением в `manifest.json`.
|
||||
|
||||
## Настройка
|
||||
|
||||
Основные параметры доступны в админке: **Система -> Настройки -> Бэкапы**.
|
||||
|
||||
Минимальный `.env`:
|
||||
|
||||
```env
|
||||
BACKUP_ENABLED=True
|
||||
BACKUP_CHAT_ID=-1001234567890
|
||||
BACKUP_INTERVAL_SECONDS=3600
|
||||
BACKUP_LOCAL_RETENTION=100
|
||||
BACKUP_COMPOSE_ENABLED=True
|
||||
COMPOSE_BACKUP_SOURCE=.
|
||||
COMPOSE_RESTORE_MODE=rw
|
||||
```
|
||||
|
||||
`BACKUP_INTERVAL_SECONDS=3600` запускает бэкапы ровно на границе часа: 12:00, 13:00 и т.д. Значение по умолчанию для локального хранения - 100 последних ZIP-архивов.
|
||||
|
||||
`BACKUP_CHAT_ID` задает чат Telegram для отправки архивов. Если он пустой, используется `LOG_CHAT_ID`. Для topic/thread можно указать `BACKUP_THREAD_ID`; если он пустой, используется `LOG_THREAD_ID`.
|
||||
|
||||
Каждый архив подписывается HMAC-подписью в `manifest.json` и содержит SHA-256 каждого файла. По умолчанию restore принимает только архивы с валидной подписью этого инстанса. Если нужен отдельный стабильный ключ подписи, задайте `BACKUP_ARCHIVE_SIGNATURE_SECRET`; если ключ пустой, используется `BOT_TOKEN`.
|
||||
|
||||
## Mount compose-папки
|
||||
|
||||
В стандартных compose-файлах есть два mount:
|
||||
|
||||
- `worker`: `${COMPOSE_BACKUP_SOURCE:-.}:/app/compose-source:ro` - только читает папку для создания snapshot;
|
||||
- `backend`: `${COMPOSE_BACKUP_SOURCE:-.}:/app/compose-source:${COMPOSE_RESTORE_MODE:-rw}` - читает список архивов и может восстановить compose-папку из админки.
|
||||
|
||||
`COMPOSE_BACKUP_SOURCE=.` означает папку рядом с текущим `docker-compose.yml`. Если compose лежит в другом месте, укажите абсолютный host-путь.
|
||||
|
||||
Если нужно запретить восстановление compose-файлов из контейнера, задайте:
|
||||
|
||||
```env
|
||||
COMPOSE_RESTORE_MODE=ro
|
||||
```
|
||||
|
||||
В этом режиме восстановление БД останется доступным, а восстановление compose-папки вернет понятную ошибку о недоступной записи.
|
||||
|
||||
## Восстановление из админки
|
||||
|
||||
Откройте **Система -> Бэкапы**. В разделе можно:
|
||||
|
||||
- выбрать архив, уже лежащий в `data/backups`;
|
||||
- загрузить ZIP-архив вручную;
|
||||
- отметить, что восстанавливать: `БД`, `compose-папка` или оба варианта;
|
||||
- запустить восстановление после подтверждения.
|
||||
|
||||
БД восстанавливается через `pg_restore --clean --if-exists --no-owner --no-privileges`. На время восстановления лучше не запускать платежи, рассылки, массовую синхронизацию и ручные изменения подписок.
|
||||
|
||||
Compose-файлы восстанавливаются поверх текущей папки. Перед заменой backend создает pre-restore snapshot текущего compose-каталога рядом с остальными архивами:
|
||||
|
||||
```text
|
||||
remnawave-minishop-compose-pre-restore-YYYYMMDD-HHMMSS+ZZZZ.zip
|
||||
```
|
||||
|
||||
После восстановления compose-папки перезапустите нужные сервисы, чтобы изменения `docker-compose.yml`, `.env`, Caddyfile/Nginx-конфигов и других файлов реально применились:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build backend worker
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
Если менялись proxy-конфиги, перезапустите соответствующий сервис (`caddy`, `nginx`, `newt`).
|
||||
|
||||
## Проверка архива перед восстановлением
|
||||
|
||||
Backend валидирует архив до восстановления:
|
||||
|
||||
- файл должен быть валидным ZIP;
|
||||
- `manifest.json` должен принадлежать `remnawave-minishop` и иметь поддерживаемую версию формата;
|
||||
- HMAC-подпись manifest должна быть валидной, если `BACKUP_ARCHIVE_SIGNATURE_REQUIRED=True`;
|
||||
- SHA-256 и размер каждого файла должны совпадать с manifest;
|
||||
- выбранный server-side файл должен лежать внутри `BACKUP_DIR`, путь вида `../backup.zip` отклоняется;
|
||||
- пути внутри ZIP не могут быть абсолютными, содержать `..`, `\`, пустые сегменты или дубли;
|
||||
- архивы с подозрительно большим числом файлов, размером или zip-bomb compression ratio отклоняются;
|
||||
- для восстановления БД нужен `database/*.dump` или `database/*.backup`;
|
||||
- для восстановления compose нужны файлы внутри `compose/`;
|
||||
- compose restore стартует только если целевая папка существует и доступна на запись;
|
||||
- backup/restore защищены одним Redis lock, чтобы две операции не выполнялись одновременно.
|
||||
|
||||
Это защищает от случайной загрузки мусорного файла, zip-slip-архивов, поврежденных ZIP и структурно похожих архивов, которые не были созданы этим инстансом. Если вы сознательно восстанавливаете старый неподписанный архив, временно выставьте `BACKUP_ARCHIVE_SIGNATURE_REQUIRED=False`, восстановите архив и верните проверку обратно.
|
||||
|
||||
## Ручное восстановление БД
|
||||
|
||||
Если админка недоступна, можно восстановить дамп вручную:
|
||||
|
||||
```bash
|
||||
unzip remnawave-minishop-backup-YYYYMMDD-HHMMSS+ZZZZ.zip -d restore
|
||||
docker compose cp restore/database/remnawave_minishop.dump postgres:/tmp/remnawave_minishop.dump
|
||||
docker compose stop backend worker
|
||||
docker compose exec postgres sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists --no-owner --no-privileges /tmp/remnawave_minishop.dump'
|
||||
docker compose up -d backend worker
|
||||
```
|
||||
|
||||
После ручного восстановления проверьте миграции и healthcheck:
|
||||
|
||||
```bash
|
||||
docker compose run --rm migrate
|
||||
docker compose ps
|
||||
docker compose logs -f backend worker
|
||||
```
|
||||
|
||||
## Переменные
|
||||
|
||||
Полный справочник лежит в [переменных окружения](../configuration/env-vars.md#кеши-rate-limits-и-worker). Основные ключи:
|
||||
|
||||
| Переменная | Назначение |
|
||||
| --- | --- |
|
||||
| `BACKUP_ENABLED` | Включает периодические бэкапы. |
|
||||
| `BACKUP_CHAT_ID` / `BACKUP_THREAD_ID` | Куда отправлять архивы в Telegram. |
|
||||
| `BACKUP_INTERVAL_SECONDS` | Периодичность, по умолчанию `3600`. |
|
||||
| `BACKUP_LOCAL_RETENTION` | Сколько последних архивов хранить на сервере. |
|
||||
| `BACKUP_DIR` | Каталог ZIP-архивов. |
|
||||
| `BACKUP_ARCHIVE_SIGNATURE_REQUIRED` | Требовать валидную HMAC-подпись manifest при upload/restore. |
|
||||
| `BACKUP_ARCHIVE_SIGNATURE_SECRET` | Отдельный секрет подписи архивов; если пустой, используется `BOT_TOKEN`. |
|
||||
| `BACKUP_COMPOSE_ENABLED` | Добавлять compose snapshot. |
|
||||
| `COMPOSE_BACKUP_SOURCE` | Host-путь compose-папки для mount в контейнеры. |
|
||||
| `COMPOSE_RESTORE_MODE` | `rw` для восстановления compose из админки, `ro` для запрета записи. |
|
||||
| `BACKUP_PG_DUMP_PATH` / `BACKUP_PG_RESTORE_PATH` | Пути к `pg_dump` и `pg_restore` внутри контейнеров. |
|
||||
@@ -4,7 +4,7 @@ Minishop закрывает путь от регистрации пользов
|
||||
|
||||
## Для пользователей
|
||||
|
||||
- Регистрация через Telegram Mini App или email-код.
|
||||
- Регистрация через [Telegram Mini App](telegram-auth.md) или [email-код](email-login.md).
|
||||
- Просмотр подписки, срока действия, трафика и ссылки подключения.
|
||||
- Покупка подписки, пакетов трафика и дополнительных устройств.
|
||||
- Пробный период, промокоды и реферальные сценарии.
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# Вход по email
|
||||
|
||||
Email-вход позволяет пользователю зарегистрироваться или войти в Mini App без Telegram. Пользователь вводит email, получает одноразовый код и может подтвердить вход кодом или magic link из письма. После входа email можно связать с Telegram-аккаунтом в настройках профиля.
|
||||
|
||||
Аккаунты только с email не получают права администратора: админка проверяет Telegram ID из `ADMIN_IDS`.
|
||||
|
||||
## Когда форма появляется
|
||||
|
||||
Кнопка входа по email показывается только если заполнены все обязательные SMTP-настройки:
|
||||
|
||||
```ini
|
||||
SMTP_HOST=smtp-relay.brevo.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=<smtp-login>
|
||||
SMTP_PASSWORD=<smtp-password-or-api-key>
|
||||
SMTP_FROM_EMAIL=no-reply@domain.com
|
||||
```
|
||||
|
||||
Если хотя бы одно из этих полей пустое, backend вернет `email_auth_enabled=false` в bootstrap, а frontend скроет email-login.
|
||||
|
||||
Для magic link также нужен корректный `SUBSCRIPTION_MINI_APP_URL`, потому что ссылка в письме строится на его основе.
|
||||
|
||||
## SMTP-настройка
|
||||
|
||||
Типовой пример:
|
||||
|
||||
```ini
|
||||
SMTP_HOST=smtp-relay.brevo.com
|
||||
SMTP_PORT=587
|
||||
SMTP_FALLBACK_PORTS=2525,465
|
||||
SMTP_TIMEOUT_SECONDS=30
|
||||
SMTP_STARTTLS=True
|
||||
SMTP_USE_SSL=False
|
||||
SMTP_USERNAME=<smtp-login>
|
||||
SMTP_PASSWORD=<smtp-password-or-api-key>
|
||||
SMTP_FROM_EMAIL=no-reply@domain.com
|
||||
SMTP_FROM_NAME=Remnawave Minishop
|
||||
|
||||
EMAIL_CODE_TTL_SECONDS=600
|
||||
EMAIL_CODE_RESEND_SECONDS=60
|
||||
EMAIL_CODE_MAX_ATTEMPTS=5
|
||||
BRUTE_FORCE_MAX_FAILURES=5
|
||||
BRUTE_FORCE_WINDOW_SECONDS=900
|
||||
BRUTE_FORCE_LOCK_SECONDS=900
|
||||
```
|
||||
|
||||
Для Brevo обычно подходит порт `587` с STARTTLS. Если основной порт недоступен, приложение пробует порты из `SMTP_FALLBACK_PORTS`; порт `465` используется через SSL wrapper автоматически.
|
||||
|
||||
`SMTP_FROM_EMAIL` должен быть подтвержден у SMTP-провайдера, иначе письмо часто отклоняется или попадает в спам. `SMTP_FROM_NAME` можно оставить пустым, тогда используется название Web App.
|
||||
|
||||
Полный справочник переменных: [SMTP и вход по email](../configuration/env-vars.md#smtp-и-вход-по-email).
|
||||
|
||||
## Как работает вход
|
||||
|
||||
1. Пользователь вводит email в форме входа.
|
||||
2. Backend проверяет rate limit и создает одноразовый код.
|
||||
3. Письмо отправляется через SMTP. Если `SUBSCRIPTION_MINI_APP_URL` валиден, в письме также есть magic link.
|
||||
4. Пользователь вводит код в Mini App или открывает magic link.
|
||||
5. Backend создает нового email-пользователя или находит существующего по email.
|
||||
6. Если в URL был referral-параметр, он применяется к новой или существующей записи.
|
||||
7. Пользователь получает Web App-сессию.
|
||||
|
||||
Коды хранятся в базе в хешированном виде, устаревают по `EMAIL_CODE_TTL_SECONDS`, повторная отправка ограничена `EMAIL_CODE_RESEND_SECONDS`, а количество попыток ввода ограничено `EMAIL_CODE_MAX_ATTEMPTS` и общими brute-force настройками.
|
||||
|
||||
## Парольный вход
|
||||
|
||||
После подтверждения email пользователь может задать пароль в настройках профиля. Пароль хранится как PBKDF2-SHA256 hash с солью.
|
||||
|
||||
После установки пароля доступен путь:
|
||||
|
||||
```text
|
||||
https://app.domain.com/login/password
|
||||
```
|
||||
|
||||
Если парольный вход не удался, frontend предлагает fallback на обычный email-код. Установка или изменение пароля тоже подтверждается email-кодом.
|
||||
|
||||
## Привязка аккаунтов
|
||||
|
||||
В настройках профиля пользователь может:
|
||||
|
||||
- привязать email к Telegram-аккаунту через код;
|
||||
- привязать Telegram к email-аккаунту через Telegram Mini Apps `initData` или Telegram OAuth;
|
||||
- задать или сменить пароль для email-входа.
|
||||
|
||||
Если email уже принадлежит другой записи, backend выполняет безопасное объединение по существующим правилам аккаунтов и инвалидирует старые Web App-кеши.
|
||||
|
||||
## Проверка после настройки
|
||||
|
||||
1. Перезапустите backend/frontend после изменения `.env`.
|
||||
2. Откройте `https://app.domain.com/` вне Telegram.
|
||||
3. Убедитесь, что форма email-входа видна.
|
||||
4. Запросите код на тестовый адрес.
|
||||
5. Проверьте письмо, magic link и ручной ввод 6-значного кода.
|
||||
6. Проверьте логи backend, если письмо не пришло:
|
||||
|
||||
```bash
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
## Частые ошибки
|
||||
|
||||
- Форма email не видна: не заполнены `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD` или `SMTP_FROM_EMAIL`.
|
||||
- Письмо не отправляется: проверьте порт, STARTTLS/SSL режим, SMTP login/API key и подтверждение отправителя.
|
||||
- Magic link ведет не туда: исправьте `SUBSCRIPTION_MINI_APP_URL`, он должен быть публичным HTTPS URL Mini App без `/api` и `/auth`.
|
||||
- Код сразу устаревает: проверьте `EMAIL_CODE_TTL_SECONDS` и время на сервере.
|
||||
- Пользователь получает `rate_limited`: подождите `EMAIL_CODE_RESEND_SECONDS` или проверьте brute-force настройки.
|
||||
|
||||
Email-уведомления поддержки и платежей используют тот же SMTP-контур. Сценарий поддержки описан в [разделе тикетов](support.md).
|
||||
@@ -45,7 +45,7 @@
|
||||
- `SUPPORT_ADMIN_NOTIFICATION_COOLDOWN_SECONDS` - пауза для Telegram/log уведомлений;
|
||||
- `SUPPORT_ADMIN_EMAIL_COOLDOWN_SECONDS` - пауза для email-уведомлений.
|
||||
|
||||
Email-уведомления администраторам включаются через `SUPPORT_ADMIN_EMAIL_NOTIFICATIONS_ENABLED=True`. Письма отправляются только администраторам из `ADMIN_IDS`, у которых в базе есть email. Для отправки нужен рабочий SMTP-конфиг, как и для входа по email.
|
||||
Email-уведомления администраторам включаются через `SUPPORT_ADMIN_EMAIL_NOTIFICATIONS_ENABLED=True`. Письма отправляются только администраторам из `ADMIN_IDS`, у которых в базе есть email. Для отправки нужен рабочий SMTP-конфиг, как и для [входа по email](email-login.md).
|
||||
|
||||
Ответ администратора и закрытие тикета дополнительно отправляются пользователю в Telegram, если у него есть Telegram-аккаунт, и на email, если он привязан.
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# Telegram-авторизация
|
||||
|
||||
Telegram-вход в Mini App работает двумя способами:
|
||||
|
||||
- внутри Telegram Mini App backend проверяет Telegram Mini Apps `initData`;
|
||||
- при открытии сайта в обычном браузере используется Telegram OAuth / OpenID Connect Authorization Code Flow с PKCE, `nonce`, callback `/auth/telegram/callback` и серверной проверкой `id_token` по JWKS Telegram.
|
||||
|
||||
`initData` не требует отдельного OAuth-секрета, но требует корректного `BOT_TOKEN`, публичного HTTPS Mini App URL и настройки Mini Apps в BotFather. OAuth нужен для входа через кнопку Telegram вне клиента Telegram и для привязки Telegram к email-аккаунту из настроек профиля.
|
||||
|
||||
## Что нужно заранее
|
||||
|
||||
Минимальные переменные:
|
||||
|
||||
```ini
|
||||
WEBAPP_ENABLED=True
|
||||
SUBSCRIPTION_MINI_APP_URL=https://app.domain.com/
|
||||
WEBAPP_SESSION_SECRET=<stable-random-secret>
|
||||
WEBAPP_AUTH_MAX_AGE_SECONDS=86400
|
||||
WEBAPP_LOGIN_TOKEN_TTL_SECONDS=600
|
||||
|
||||
TELEGRAM_OAUTH_CLIENT_ID=<client-id-from-botfather>
|
||||
TELEGRAM_OAUTH_CLIENT_SECRET=<client-secret-from-botfather>
|
||||
TELEGRAM_OAUTH_REQUEST_ACCESS=write
|
||||
```
|
||||
|
||||
`SUBSCRIPTION_MINI_APP_URL` должен быть публичным HTTPS URL именно frontend/Mini App-домена. Не добавляйте сюда `/api`, `/auth`, webhook-путь или конкретную страницу.
|
||||
|
||||
`WEBAPP_SESSION_SECRET` должен быть стабильным между рестартами, иначе Web App-сессии и OAuth state-cookie станут невалидными.
|
||||
|
||||
`WEBAPP_AUTH_MAX_AGE_SECONDS` ограничивает возраст Telegram Mini Apps `initData` и OAuth `id_token`. По умолчанию это 24 часа. Слишком маленькое значение может ломать вход на устройствах с неточными часами.
|
||||
|
||||
`WEBAPP_LOGIN_TOKEN_TTL_SECONDS` управляет TTL OAuth state, nonce и login-token. По умолчанию 10 минут.
|
||||
|
||||
`TELEGRAM_OAUTH_CLIENT_ID` можно не задавать, если client id совпадает с bot id: приложение возьмет его из префикса `BOT_TOKEN`. `TELEGRAM_OAUTH_CLIENT_SECRET` для браузерного OAuth обязателен.
|
||||
|
||||
`TELEGRAM_OAUTH_REQUEST_ACCESS=write` добавляет scope `telegram:bot_access`, чтобы бот мог написать пользователю после логина. Если это не нужно, оставьте переменную пустой. Также поддерживается `phone`, если вы осознанно запрашиваете телефон.
|
||||
|
||||
Полный справочник переменных: [Веб-приложение, внешний вид и Telegram Login](../configuration/env-vars.md#веб-приложение-внешний-вид-и-telegram-login).
|
||||
|
||||
## Настройка в BotFather
|
||||
|
||||
1. Откройте `@BotFather` -> `/mybots` -> выберите бота.
|
||||
2. В `Bot Settings` -> `Domain` укажите домен Web App без протокола и пути, например `app.domain.com`.
|
||||
3. В `Bot Settings` -> `Mini Apps` укажите URL, например `https://app.domain.com/`.
|
||||
4. В `Bot Settings` -> `Web Login` включите OpenID Connect Login, если BotFather предлагает переключение.
|
||||
5. Скопируйте client id и client secret в `TELEGRAM_OAUTH_CLIENT_ID` и `TELEGRAM_OAUTH_CLIENT_SECRET`.
|
||||
6. В `Web Login` -> `Allowed URLs` добавьте:
|
||||
|
||||
```text
|
||||
https://app.domain.com/
|
||||
https://app.domain.com/auth/telegram/callback
|
||||
```
|
||||
|
||||
После изменения `.env` перезапустите backend и frontend:
|
||||
|
||||
```bash
|
||||
docker compose up -d --force-recreate backend frontend
|
||||
```
|
||||
|
||||
## Проксирование
|
||||
|
||||
Публичный домен `SUBSCRIPTION_MINI_APP_URL` должен идти в контейнер `frontend:80`. Frontend nginx сам проксирует `/api/*` и `/auth/*` во внутренний WebApp-сервер backend на `backend:8081`.
|
||||
|
||||
Если используете собственный reverse proxy, не отправляйте `/auth/telegram/start` и `/auth/telegram/callback` напрямую в webhook-сервер `backend:8080`: эти маршруты принадлежат Web App API на `backend:8081` и штатно проходят через frontend.
|
||||
|
||||
Готовые схемы Caddy, Nginx, Newt и прямой публикации описаны в [развертывании](../getting-started/deployment.md#готовые-папки-запуска).
|
||||
|
||||
## Как проверить
|
||||
|
||||
Внутри Telegram:
|
||||
|
||||
1. Откройте Mini App кнопкой бота или через URL, настроенный в BotFather.
|
||||
2. Проверьте, что пользователь входит без OAuth-redirect и видит личный кабинет.
|
||||
3. Если вход не проходит, проверьте `SUBSCRIPTION_MINI_APP_URL`, домен BotFather и возраст `initData`.
|
||||
|
||||
В обычном браузере:
|
||||
|
||||
1. Откройте `https://app.domain.com/`.
|
||||
2. Нажмите вход через Telegram.
|
||||
3. Проверьте redirect на Telegram OAuth и возврат на `https://app.domain.com/auth/telegram/callback`.
|
||||
4. После успешного callback пользователь должен вернуться на `/` со статусом `telegram_auth=success`, который frontend очистит из URL.
|
||||
|
||||
Для диагностики полезны:
|
||||
|
||||
```bash
|
||||
curl -i https://app.domain.com/auth/telegram/start
|
||||
docker compose logs -f backend frontend
|
||||
```
|
||||
|
||||
## Частые ошибки
|
||||
|
||||
- `telegram_oauth_not_configured` или `telegram_auth=not_configured`: не задан `TELEGRAM_OAUTH_CLIENT_SECRET` или client id не удалось получить из `TELEGRAM_OAUTH_CLIENT_ID`/`BOT_TOKEN`.
|
||||
- `Telegram OAuth nonce mismatch`: сессия/state устарели, поменялся `WEBAPP_SESSION_SECRET`, пользователь открыл старую вкладку или callback пришел с другого домена.
|
||||
- `Telegram OAuth ID token is stale`: `WEBAPP_AUTH_MAX_AGE_SECONDS` слишком маленький или на сервере/клиенте сбито время.
|
||||
- `Telegram OAuth callback failed`: проверьте allowed URL в BotFather и что `/auth/*` доходит до frontend/WebApp API.
|
||||
- Mini App не открывается внутри Telegram: домен в BotFather должен совпадать с `SUBSCRIPTION_MINI_APP_URL`, а URL должен быть HTTPS.
|
||||
|
||||
Общие логи по авторизации собраны в [разделе диагностики логов](../troubleshooting/logs.md#авторизация-mini-app-и-telegram-oauth).
|
||||
@@ -38,20 +38,6 @@ WEBAPP_SESSION_TTL_SECONDS=86400
|
||||
WEBAPP_AUTH_MAX_AGE_SECONDS=86400
|
||||
WEBAPP_LOGIN_TOKEN_TTL_SECONDS=600
|
||||
|
||||
TELEGRAM_OAUTH_CLIENT_ID=<client-id-from-botfather>
|
||||
TELEGRAM_OAUTH_CLIENT_SECRET=<client-secret-from-botfather>
|
||||
TELEGRAM_OAUTH_REQUEST_ACCESS=write
|
||||
|
||||
SMTP_HOST=smtp-relay.brevo.com
|
||||
SMTP_PORT=587
|
||||
SMTP_FALLBACK_PORTS=2525,465
|
||||
SMTP_STARTTLS=True
|
||||
SMTP_USE_SSL=False
|
||||
SMTP_USERNAME=<smtp-login>
|
||||
SMTP_PASSWORD=<smtp-password-or-key>
|
||||
SMTP_FROM_EMAIL=no-reply@domain.com
|
||||
SMTP_FROM_NAME=Remnawave Minishop
|
||||
|
||||
SUPPORT_LINK=https://t.me/your_support_link
|
||||
SUPPORT_TICKETS_ENABLED=True
|
||||
SUPPORT_TICKET_RATE_LIMIT_PER_HOUR=5
|
||||
@@ -83,43 +69,17 @@ SUPPORT_TICKET_RATE_LIMIT_PER_HOUR=5
|
||||
|
||||
Внешний вид настраивается в админке: раздел **Внешний вид** управляет логотипом, emoji-логотипом, accent-цветом, выбранной темой и масштабом логотипа. Кастомные темы читаются из `WEBAPP_THEMES_DIR`, а `WEBAPP_DEFAULT_THEME` может принудительно выбрать тему по ключу. Подробный контракт `theme.json`, CSS/asset-роуты и пайплайн создания темы описаны в [webapp-themes.md](webapp-themes.md).
|
||||
|
||||
Если SMTP-настройки не заполнены, вход по email скрывается.
|
||||
## Авторизация
|
||||
|
||||
Mini App поддерживает вход через Telegram Mini Apps `initData`, Telegram OAuth / OpenID Connect вне Telegram и email-код. Подробная настройка вынесена в отдельные разделы:
|
||||
|
||||
- [Telegram-авторизация](telegram-auth.md) - BotFather, Mini Apps, Web Login, callback `/auth/telegram/callback`, OAuth-переменные и типичные ошибки.
|
||||
- [Вход по email](email-login.md) - SMTP, одноразовые коды, magic link, парольный вход и проверки доставки писем.
|
||||
|
||||
Если SMTP-настройки не заполнены, вход по email скрывается. Если Telegram OAuth не настроен, вход через Telegram продолжает работать внутри Telegram Mini App через `initData`, но внешняя браузерная авторизация не сможет стартовать.
|
||||
|
||||
Тикеты поддержки включаются через `SUPPORT_TICKETS_ENABLED`; внешний резервный контакт задается `SUPPORT_LINK`. Полный сценарий пользователя, админа и уведомлений описан в разделе [поддержка пользователей / тикеты](support.md).
|
||||
|
||||
## Telegram-авторизация
|
||||
|
||||
Внутри Telegram Mini App пользователь авторизуется через Telegram Mini Apps `initData`. При открытии страницы вне Telegram используется Telegram OAuth / OpenID Connect Authorization Code Flow с PKCE, callback `/auth/telegram/callback`, `nonce` и серверной проверкой `id_token` по JWKS Telegram.
|
||||
|
||||
Настройка в BotFather:
|
||||
|
||||
1. Откройте `@BotFather` -> `/mybots` -> выберите бота.
|
||||
2. В `Bot Settings` -> `Domain` укажите домен Web App без протокола и пути, например `app.domain.com`.
|
||||
3. В `Bot Settings` -> `Mini Apps` укажите URL, например `https://app.domain.com/`.
|
||||
4. В `Bot Settings` -> `Web Login` включите OpenID Connect Login, если BotFather предлагает переключение.
|
||||
5. Скопируйте идентификатор клиента и секрет клиента в `TELEGRAM_OAUTH_CLIENT_ID` и `TELEGRAM_OAUTH_CLIENT_SECRET`.
|
||||
6. В `Web Login` -> `Allowed URLs` добавьте:
|
||||
|
||||
```text
|
||||
https://app.domain.com/
|
||||
https://app.domain.com/auth/telegram/callback
|
||||
```
|
||||
|
||||
`TELEGRAM_OAUTH_REQUEST_ACCESS=write` разрешает боту написать пользователю после логина. Если дополнительные разрешения не нужны, оставьте переменную пустой.
|
||||
|
||||
## Вход по email
|
||||
|
||||
Вход по email работает через одноразовый код:
|
||||
|
||||
1. Пользователь вводит email.
|
||||
2. Бот отправляет код через SMTP.
|
||||
3. Код вводится в модальном окне Web App.
|
||||
4. После подтверждения создается или находится пользователь, а email можно связать с Telegram-аккаунтом.
|
||||
|
||||
Для Brevo обычно подходит порт `587` с STARTTLS. Если основной порт недоступен, приложение пробует порты из `SMTP_FALLBACK_PORTS`; порт `465` используется через SSL.
|
||||
|
||||
Полный список переменных, обязательные поля для включения входа по email и типичные ошибки подключения описаны в разделе **SMTP и вход по email** в [configuration.md](../getting-started/configuration.md).
|
||||
|
||||
## Проксирование
|
||||
|
||||
Рекомендуемая продакшен-схема - два публичных домена:
|
||||
|
||||
@@ -105,6 +105,8 @@ docker compose exec backend sh -lc 'id; touch /app/data/themes/test && rm /app/d
|
||||
- [configuration/env-vars.md](../configuration/env-vars.md) - полный справочник переменных `.env`.
|
||||
- [features/admin-panel.md](../features/admin-panel.md) - как устроены overrides и allowlist настроек.
|
||||
- [features/tariffs.md](../features/tariffs.md) - JSON-каталог тарифов и редактор тарифов.
|
||||
- [Веб-приложение / Mini App](../features/web-app.md) - домен Mini App, Telegram OAuth и вход по email.
|
||||
- [Веб-приложение / Mini App](../features/web-app.md) - домен Mini App, инструкции установки и проксирование.
|
||||
- [Telegram-авторизация](../features/telegram-auth.md) - BotFather, Mini Apps и OAuth.
|
||||
- [Вход по email](../features/email-login.md) - SMTP, коды, magic link и парольный вход.
|
||||
- [Поддержка пользователей / тикеты](../features/support.md) - тикеты поддержки и уведомления.
|
||||
- [Развертывание](deployment.md) - Docker Compose, обратный прокси, Caddy/Nginx и обновления.
|
||||
|
||||
@@ -356,6 +356,8 @@ docker compose exec backend sh -lc 'id; touch /app/data/themes/test && rm /app/d
|
||||
|
||||
## Резервная копия PostgreSQL
|
||||
|
||||
Для штатных автоматических ZIP-бэкапов, отправки в Telegram и восстановления через админку используйте раздел [бэкапы и восстановление](../features/backups.md). Команды ниже - минимальный ручной fallback для PostgreSQL.
|
||||
|
||||
```bash
|
||||
docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB"' > backup.sql
|
||||
```
|
||||
|
||||
@@ -14,5 +14,5 @@ Remnawave Minishop состоит из Telegram-бота, backend API, worker-п
|
||||
|
||||
- [Установка](setup.md) - базовый запуск через Compose.
|
||||
- [Развертывание](../deployment.md) - Docker Compose, Caddy, Nginx, Pangolin/Newt и запуск без обратного прокси.
|
||||
- [Настройка Telegram бота](../features/web-app.md#telegram-авторизация) - Telegram OAuth и Telegram Mini App.
|
||||
- [Настройка SMTP](../features/web-app.md#вход-по-email) - Вход и регистрация по email.
|
||||
- [Настройка Telegram бота](../features/telegram-auth.md) - Telegram OAuth и Telegram Mini App.
|
||||
- [Настройка SMTP](../features/email-login.md) - Вход и регистрация по email.
|
||||
|
||||
@@ -39,8 +39,8 @@ docker compose up -d
|
||||
|
||||
## Настройки для веб апп
|
||||
|
||||
- [Настройка Telegram бота](../features/web-app.md#telegram-авторизация) - Telegram OAuth и Telegram Mini App.
|
||||
- [Настройка SMTP](../features/web-app.md#вход-по-email) - Вход и регистрация по email.
|
||||
- [Настройка Telegram бота](../features/telegram-auth.md) - Telegram OAuth и Telegram Mini App.
|
||||
- [Настройка SMTP](../features/email-login.md) - Вход и регистрация по email.
|
||||
|
||||
## После первого входа
|
||||
|
||||
|
||||
+2
-2
@@ -8,5 +8,5 @@ Remnawave Minishop - Telegram-бот и Mini App для продажи и упр
|
||||
|
||||
- **Продажа подписок** - тарифы на срок и по трафику, докупки трафика, HWID-устройства, [premium-сквады](features/tariffs.md#premium-сквады-и-отдельный-лимит)
|
||||
- **Жизненный цикл пользователей** - регистрация, пробный период, продление, синхронизация с панелью и предупреждения по трафику.
|
||||
- **Mini App** - личный кабинет, инструкции установки, Telegram OAuth, вход по email и публичные реферальные ссылки.
|
||||
- **Операционные инструменты** - админка, тикеты поддержки, промокоды, рассылки, логи и настройки поверх `.env`.
|
||||
- **Mini App** - личный кабинет, инструкции установки, [Telegram OAuth](features/telegram-auth.md), [вход по email](features/email-login.md) и публичные реферальные ссылки.
|
||||
- **Операционные инструменты** - админка, тикеты поддержки, промокоды, рассылки, логи, [бэкапы и восстановление](features/backups.md), настройки поверх `.env`.
|
||||
|
||||
@@ -92,7 +92,7 @@ docker compose logs -f backend
|
||||
- `/auth/telegram/start` и `/auth/telegram/callback` проходят через frontend nginx в `backend:8081`;
|
||||
- в браузере после callback нет статуса `telegram_auth=invalid_state`, `invalid_token`, `not_configured`, `unauthorized` или `failed`.
|
||||
|
||||
Подробности по маршрутам и настройке OAuth: [веб-приложение / Mini App](../features/web-app.md).
|
||||
Подробности по маршрутам и настройке OAuth: [Telegram-авторизация](../features/telegram-auth.md).
|
||||
|
||||
## После изменения конфигурации
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Обслуживание
|
||||
|
||||
Плановое обслуживание обычно сводится к обновлению образов, проверке миграций, логов и резервных копий PostgreSQL.
|
||||
Плановое обслуживание обычно сводится к обновлению образов, проверке миграций, логов и резервных копий. Подробная инструкция по автоматическим ZIP-бэкапам и восстановлению вынесена в [бэкапы и восстановление](../features/backups.md).
|
||||
|
||||
## Обновление
|
||||
|
||||
@@ -16,6 +16,19 @@ docker compose logs -f migrate backend worker
|
||||
docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB"' > backup.sql
|
||||
```
|
||||
|
||||
## Автоматические бэкапы
|
||||
|
||||
Worker может собирать ZIP-архивы с дампом PostgreSQL и snapshot compose-папки, отправлять их в Telegram и хранить последние архивы в `data/backups`. Настройка и восстановление описаны в [отдельном разделе](../features/backups.md).
|
||||
|
||||
После изменения backup-настроек в `.env` перезапустите backend и worker:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build backend worker
|
||||
docker compose logs -f backend worker
|
||||
```
|
||||
|
||||
Восстановление из архива доступно в админке **Система -> Бэкапы**. Там же можно загрузить ZIP вручную, выбрать `БД` и/или `compose-папка`, а backend проверит архив перед запуском. Подробности: [бэкапы и восстановление](../features/backups.md#восстановление-из-админки).
|
||||
|
||||
## Проверки после работ
|
||||
|
||||
- `docker compose ps`
|
||||
|
||||
Reference in New Issue
Block a user