> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bedolagam.ru/llms.txt
> Use this file to discover all available pages before exploring further.

# Remnawave

> Интеграция с VPN панелью Remnawave

## Обзор

Бот управляет VPN подписками через API панели [Remnawave](https://github.com/remnawave/backend). Все операции с пользователями, серверами и трафиком проходят через единый API клиент.

### Совместимость с Remnawave 2.7.0

Начиная с версии 2.7.0 панели поддерживаются:

* **MONTH\_ROLLING** — стратегия сброса трафика с помесячным скользящим окном
* **Per-inbound метрики** — разбивка трафика по отдельным inbound в реальном времени
* **Обновлённая модель данных нод** — вложенные объекты `versions` / `system` вместо плоских полей
* **Webhook `torrent_blocker.report`** — событие при обнаружении торрент-трафика
* **Webhook `subpage_config_changed`** — автоматическая инвалидация кэша конфигурации приложения при изменении подстраницы

## Настройка подключения

```env theme={null}
REMNAWAVE_API_URL=https://panel.example.com
REMNAWAVE_API_KEY=your_panel_api_key
```

<Warning>
  Если бот и панель на одном сервере в Docker, используйте внутренний адрес: `REMNAWAVE_API_URL=http://remnawave:3000`
</Warning>

## Защита панели

Для панелей, защищённых через [remnawave-reverse-proxy](https://github.com/eGamesAPI/remnawave-reverse-proxy):

```env theme={null}
# Для панелей установленных скриптом eGames
REMNAWAVE_SECRET_KEY=XXXXXXX:DDDDDDDD

# Или если ключ и значение одинаковые
REMNAWAVE_SECRET_KEY=secret_key_name
```

## Методы авторизации

| Конфигурация     | Authorization         | X-Api-Key             |
| ---------------- | --------------------- | --------------------- |
| Только API Key   | `Bearer <api_key>`    | `<api_key>`           |
| Basic Auth       | `Bearer <api_key>`    | `Basic <user:pass>`   |
| Caddy + API Key  | `Basic <caddy_token>` | `<api_key>`           |
| Cookies (eGames) | `Bearer <api_key>`    | `<api_key>` + cookies |

## Автосинхронизация

```env theme={null}
REMNAWAVE_AUTO_SYNC_ENABLED=true
REMNAWAVE_AUTO_SYNC_TIMES=03:00,15:00
```

Бот синхронизирует данные с панелью:

* **При старте бота** — полная синхронизация
* **По расписанию** — в указанное время
* **По команде** — через админ-панель

Синхронизируются:

* Серверы (сквады) и их статус
* Пользователи — сопоставление Telegram ID с аккаунтами панели
* Подписки — актуальные даты и параметры

### Двунаправленная синхронизация `end_date`

Панель является авторитетным источником для `end_date` на **активных** подписках. Как webhook-событие `user.modified`, так и пакетная синхронизация обновляют `end_date` в обоих направлениях — вперёд и назад.

Ранее принимались только обновления «вперёд» (дата в панели > локальная дата). Теперь изменения, сделанные администратором в панели (например, сокращение подписки), корректно передаются в бота.

<Info>
  60-секундная защита между webhook-событием и пакетной синхронизацией по-прежнему предотвращает конфликты.
</Info>

### Синхронизация в мультитарифном режиме

При `MULTI_TARIFF_ENABLED=true` каждая подписка получает собственного пользователя в панели (`user_{telegram_id}_{short_id}`). Синхронизация работает по `remnawave_uuid` на уровне подписки, а не пользователя.

* **Panel → Bot**: создание подписок для новых пользователей панели
* **Bot → Panel**: matching по суффиксу `_short_id` в username
* **Email/OAuth**: синхронизация всех пользователей панели для email
* **Автопривязка**: legacy user-level UUID автоматически привязывается к подписке при миграции

## Webhooks от панели (real-time события)

Для мгновенной реакции на события подписок вместо периодической синхронизации.

### Настройка

**1. Переменные окружения:**

```env theme={null}
REMNAWAVE_WEBHOOK_ENABLED=true
REMNAWAVE_WEBHOOK_PATH=/remnawave-webhook
REMNAWAVE_WEBHOOK_SECRET=your_secret_min_32_chars_here
```

Сгенерируйте секрет: `openssl rand -hex 32`

<Note>
  **Усиление безопасности webhook-верификации.** Все платёжные провайдеры переведены на fail-closed модель: CryptoBot, Heleket и Tribute отклоняют запросы при отсутствии API-ключа. Для сравнения подписей используется `hmac.compare_digest` (timing-safe). CloudPayments отклоняет запросы при отсутствии заголовка подписи.
</Note>

**2. В панели Remnawave:**

* URL: `https://hooks.domain.com/remnawave-webhook`
* Secret: тот же, что в `REMNAWAVE_WEBHOOK_SECRET`

**3. Проверка:**

```bash theme={null}
curl -s https://hooks.domain.com/remnawave-webhook | jq
# {"status": "ok", "service": "remnawave_webhook", "enabled": true}
```

### Поддерживаемые события

| Событие                                  | Описание                                                |
| ---------------------------------------- | ------------------------------------------------------- |
| `user.expired`                           | Подписка истекла                                        |
| `user.disabled`                          | Подписка деактивирована                                 |
| `user.enabled`                           | Подписка активирована                                   |
| `user.limited`                           | Превышен лимит трафика                                  |
| `user.traffic_reset`                     | Трафик сброшен                                          |
| `user.modified`                          | Данные подписки изменены                                |
| `user.deleted`                           | Пользователь удалён                                     |
| `user.revoked`                           | Ключи подписки отозваны                                 |
| `user.created`                           | Пользователь создан                                     |
| `user.expires_in_*`                      | Предупреждения об истечении (72/48/24ч)                 |
| `user.first_connected`                   | Первое подключение                                      |
| `user.bandwidth_usage_threshold_reached` | Порог трафика достигнут                                 |
| `user_hwid_devices.*`                    | Устройство добавлено/удалено                            |
| `torrent_blocker.report`                 | Торрент-блокировщик: обнаружено использование торрентов |
| `subpage_config_changed`                 | Конфигурация подстраницы изменена (автосброс кэша)      |
| `node.*`, `service.*`                    | Административные события                                |

<Info>
  При включённых webhooks бот защищает подписки от перезаписи данными из периодической синхронизации в течение 60 секунд после получения события.
</Info>

### Уведомления пользователям

При получении webhook-событий бот может отправлять уведомления пользователям в Telegram (или по email для email-only пользователей).

#### Главный переключатель

```env theme={null}
# Включить уведомления пользователям от вебхуков (по умолчанию true)
WEBHOOK_NOTIFY_USER_ENABLED=true
```

Если `false` — ни одно пользовательское уведомление не отправляется, даже если отдельные типы включены.

#### Настройка по типам

Каждый тип уведомления можно включить или выключить отдельно. Все по умолчанию **включены**.

| Переменная                           | По умолчанию | События                                     | Что получает пользователь                |
| ------------------------------------ | ------------ | ------------------------------------------- | ---------------------------------------- |
| `WEBHOOK_NOTIFY_SUB_STATUS`          | `true`       | `user.disabled`, `user.enabled`             | Подписка отключена / активирована        |
| `WEBHOOK_NOTIFY_SUB_EXPIRED`         | `true`       | `user.expired`, `user.expired_24_hours_ago` | Подписка истекла / истекла вчера         |
| `WEBHOOK_NOTIFY_SUB_EXPIRING`        | `true`       | `user.expires_in_72h/48h/24h`               | Подписка истекает через 3/2 дня / завтра |
| `WEBHOOK_NOTIFY_SUB_LIMITED`         | `true`       | `user.limited`                              | Лимит трафика исчерпан                   |
| `WEBHOOK_NOTIFY_TRAFFIC_RESET`       | `true`       | `user.traffic_reset`                        | Трафик сброшен, лимит доступен           |
| `WEBHOOK_NOTIFY_SUB_DELETED`         | `true`       | `user.deleted`                              | Подписка удалена из панели               |
| `WEBHOOK_NOTIFY_SUB_REVOKED`         | `true`       | `user.revoked`                              | Ключ подписки обновлён                   |
| `WEBHOOK_NOTIFY_FIRST_CONNECTED`     | `true`       | `user.first_connected`                      | Первое подключение к VPN                 |
| `WEBHOOK_NOTIFY_NOT_CONNECTED`       | `true`       | `user.not_connected`                        | Подписка активна, но нет подключения     |
| `WEBHOOK_NOTIFY_BANDWIDTH_THRESHOLD` | `true`       | `user.bandwidth_usage_threshold_reached`    | Использовано N% трафика                  |
| `WEBHOOK_NOTIFY_DEVICES`             | `true`       | `user_hwid_devices.added/deleted`           | Новое устройство / устройство удалено    |

#### Примеры сообщений

**Подписка истекает завтра:**

```
🔴 Подписка истекает завтра!

Осталось менее 24 часов. Продлите подписку прямо сейчас.

[Продлить подписку] [Закрыть]
```

**Лимит трафика исчерпан:**

```
⚠️ Достигнут лимит трафика

Вы исчерпали весь доступный трафик.
Докупите трафик или дождитесь сброса.

[Докупить трафик] [Моя подписка] [Закрыть]
```

**Первое подключение:**

```
🎉 Первое подключение!

Вы впервые подключились к VPN. Добро пожаловать!

[Моя подписка] [Закрыть]
```

#### Тихие события

Некоторые webhook-события обрабатываются **без уведомления** пользователю:

| Событие         | Что происходит                                                                                                                  |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `user.modified` | Синхронизация данных подписки — панель авторитетна. Обновляет трафик, статус и `end_date` в обоих направлениях (вперёд и назад) |
| `user.created`  | Логирование создания пользователя в панели                                                                                      |

<Note>
  Все переменные `WEBHOOK_NOTIFY_*` можно менять **без перезапуска бота** через админ-панель (Настройки).
</Note>

## Мониторинг серверов

| Переменная                   | Описание                                                     |
| ---------------------------- | ------------------------------------------------------------ |
| `SERVER_STATUS_MODE`         | `disabled`, `external_link`, `external_link_miniapp`, `xray` |
| `SERVER_STATUS_EXTERNAL_URL` | Ссылка на внешний мониторинг                                 |
| `SERVER_STATUS_METRICS_URL`  | URL метрик XrayChecker                                       |
| `MONITORING_INTERVAL`        | Интервал проверки (секунды, по умолчанию 60)                 |

Бот отправляет уведомления администраторам при:

* Падении сервера (недоступен)
* Высокой нагрузке CPU/RAM
* Аномальном трафике
* Восстановлении после падения
