Telegram-бот управления VPN на базе Remnawave. Пользователи регистрируются по инвайт-кодам, управляют подключениями и отслеживают трафик. Поддерживает роли: пользователь, модератор, администратор.
git clone https://github.com/<user>/vpn_bot.git
cd vpn_bot
cp .env.example .env
# Заполни .env своими ключами
make upЛоги:
make logs| Переменная | Обязательная | Описание |
|---|---|---|
BOT_TOKEN |
✅ | Токен от @BotFather |
ADMIN_ID |
✅ | Telegram ID администратора (получи у @userinfobot) |
REMNAWAVE_URL |
✅ | URL панели Remnawave |
REMNAWAVE_API_TOKEN |
✅ | JWT-токен из панели Remnawave |
DB_PATH |
— | Путь к SQLite-базе (дефолт: /app/data/bot.db) |
REMNAWAVE_DEFAULT_SQUAD_UUIDS |
— | Список UUID internal squads через запятую; новые пользователи добавляются во все перечисленные сквады |
SD_CONFIGS_PATH |
— | Путь к папке service discovery для мониторинга (дефолт: /app/sd_configs) |
VICTORIA_METRICS_URL |
— | URL VictoriaMetrics (дефолт: http://victoriametrics:8428) |
CALLBACK_PORT |
— | Порт встроенного callback-сервера Platega (дефолт: 8080) |
MIN_SUBSCRIPTION_PRICE |
— | Минимальная цена подписки для модераторов (дефолт: 400) |
TRIAL_TRAFFIC_LIMIT_GB |
— | Лимит трафика для триала в ГБ (дефолт: 1) |
PLATEGA_MERCHANT_ID |
— | Merchant ID Platega для пользовательской оплаты |
PLATEGA_SECRET |
— | Секретный ключ Platega |
PLATEGA_CALLBACK_URL |
— | Публичный HTTPS callback URL вида https://domain/platega/callback |
PLATEGA_FEE_SBP |
— | Комиссия Platega для СБП в процентах |
PLATEGA_FEE_CARD |
— | Комиссия Platega для оплаты картой |
PLATEGA_FEE_CRYPTO |
— | Комиссия Platega для крипты |
PLATEGA_FEE_WITHDRAWAL |
— | Комиссия вывода средств для расчёта доли модератора |
RENDER_URL |
— | URL render-сервиса субтитров |
RENDER_API_KEY |
— | API-ключ render-сервиса |
Пример:
REMNAWAVE_DEFAULT_SQUAD_UUIDS=uuid-1,uuid-2,uuid-3Для обратной совместимости бот также понимает legacy-переменную REMNAWAVE_DEFAULT_SQUAD_UUID, если новый список не задан.
Если PLATEGA_MERCHANT_ID и PLATEGA_SECRET не заданы, бот запускается как раньше: callback-сервер не поднимается, кнопки оплаты не показываются.
Подробности по интеграции Platega и настройке callback-сервера: docs/platega/README.md и docs/plans/2026-03-22-deployment-checklist.md.
| Кнопка | Действие |
|---|---|
/start |
Регистрация по инвайт-коду или вход для зарегистрированных |
/start <code> |
Автоматическая активация кода из ссылки-приглашения |
👤 Мой статус |
Статус подписки по типу (триал / оплаченная / grace / бессрочная), трафик, устройства и ссылка |
💳 Оплатить подписку / 💳 Продлить подписку |
Запуск flow оплаты: выбор способа, ссылка, ручная проверка; кнопка скрыта без Platega или при subscription_price = NULL |
📡 Серверы |
Live-дашборд мониторинга нод (обновляется каждые 5 сек) |
📚 Инструкции |
Инструкции по настройке клиентов: iOS, Android, ПК |
ℹ️ Информация |
Помощь, контакт для вопросов и ссылки на документы сервиса |
Назначается администратором. В главном меню появляется дополнительная кнопка 🎟 Приглашения:
| Кнопка | Действие |
|---|---|
📨 Создать приглашение |
Генерирует инвайт-код на 30 дней и ссылку для отправки |
📋 Мои приглашения |
Список своих кодов (статус, кто активировал, дата, Telegram ID) |
👥 Мои подписчики |
Карточки подписчиков: статус, цена, подписка до, трафик, устройства |
💰 Мой заработок |
Доход модератора за месяц и накопительный итог |
✏️ Изменить цену |
Смена цены подписки для своего подписчика |
🗑 Удалить приглашение |
Удаление своего неиспользованного кода |
Главное меню администратора:
| Кнопка | Действие |
|---|---|
📋 Управление |
Инвайты и действия с пользователями (см. ниже) |
👥 Модераторы |
Управление ролями: назначить / список / статистика / снять модератора |
📢 Рассылка |
Отправка сообщения всем активным пользователям (текст, фото, видео, документы) |
📊 Общая статистика |
Финансовая сводка за месяц, конверсия trial → оплата и текущее состояние базы |
🔧 Режим обслуживания / ▶️ Штатный режим |
Временно скрывает оплату у пользователей и останавливает scheduler-кики/disable |
👤 Режим пользователя |
Просмотр бота глазами пользователя |
Кнопка 📋 Управление открывает панель инвайтов и действий с пользователями:
| Кнопка | Действие |
|---|---|
🎟 Создать инвайт |
Генерирует инвайт-код и ссылку для отправки |
📋 Коды |
Список всех кодов: статус, кто активировал, дата, кто создал (модератор или админ) |
🗑 Удалить код |
Удаление неиспользованного кода (использованные защищены) |
🚫 Забанить |
Перманентный бан: запись в ban-лист + удаление из БД бота и Remnawave |
♾️ Сменить тариф |
Перевод пользователя с месячной подписки на бессрочную без смены куратора |
🔍 Инфо о пользователе |
Карточка пользователя: куратор, цена, срок, трафик, устройства, тип подписки и статус |
✏️ Изменить цену |
Смена цены месячной подписки; для legacy-пользователя без цены бот отдельно спросит, считать ли текущий период уже оплаченным |
При активации нового инвайта админ получает уведомление с Telegram ID, username и именем.
Инвайт от модератора vs от администратора:
- модераторский инвайт: триал на 72 часа с лимитом трафика и ценой подписки из инвайта;
- админский инвайт: бессрочно (
2099-01-01), без ограничения трафика.
Срок подписки и продление:
- продление через Platega добавляет 30 дней к текущему сроку (или от текущей даты, если уже истекло);
- раннее продление через Platega запрещено, если до истечения больше 90 дней;
- при сбое активации платёж остаётся подтверждённым, получает статус
confirmed_not_activatedи повторно обрабатывается scheduler без перезаписи исходногоconfirmed_at; - администратор может перевести месячную подписку в бессрочную; при этом
invites.created_byсохраняется, аexpire_daysстановитсяNULL.
Scheduler подписок:
- стартует с полным проходом при запуске бота и далее работает каждые 30 минут;
- триал предупреждает менее чем за 24 часа и кикает сразу в точный
expireAt; - оплаченную подписку предупреждает за 3 дня и менее чем за 24 часа;
- в точный
expireAtоплаченная подписка переводится вDISABLED, затем даётся 72 часа grace period; - после grace period пользователь удаляется, если свежая оплата не подтверждена;
- в
maintenance modedisable и автокики блокируются. - legacy-пользователи без инвайта и без
subscription_priceпропускаются новым payment-scheduler и продолжают жить по старой модели. - legacy-пользователь модератора с уже оплаченным вручную текущим периодом может быть переведён на новую модель через
✏️ Изменить цену: бот спросит, считать ли текущий период уже оплаченным; при ответеДапользователь сразу пойдёт по paid-ветке с💳 Продлить подписку, напоминаниями за 3/1 день и grace period.
Flow оплаты:
- пользователь выбирает
💳 Оплатить подпискуили💳 Продлить подписку; - бот показывает методы оплаты:
🏦 СБП,💳 Карта,🪙 Крипта; - после создания платежа бот отправляет ссылку и кнопку
🔄 Проверить оплату; - callback и ручная проверка синхронизируют локальный статус платежа (
confirmed,canceled,chargebacked); - при успешной оплате подписка активируется автоматически, лимит трафика снимается;
- если подтверждение получено, но Remnawave временно недоступен, пользователю не показывается ложное сообщение об активации: платёж остаётся в
confirmed_not_activated, а scheduler повторяет активацию позже.
Миграция старых пользователей модераторов:
- если у старого пользователя модератора ещё нет
subscription_price, админ задаёт цену через✏️ Изменить цену; - для legacy-case бот дополнительно спрашивает, был ли текущий период уже оплачен вручную;
- ответ
✅ Да, считать оплаченнойпомечает пользователя как migrated-paid без поддельного платежа вpayments; - ответ
❌ Нет, оставить trialпросто сохраняет цену и оставляет пользователя в trial до первой оплаты через Platega; - вопрос показывается только для legacy-case с модераторским инвайтом, пустой ценой, активной finite-подпиской и отсутствием confirmed-платежей; новые пользователи после деплоя этот шаг не видят.
Бан пользователя — перманентная операция:
- Telegram ID заносится в
banned_users - Пользователь удаляется из Remnawave
- Пользователь удаляется из БД бота
- Если пользователь был модератором — все его неиспользованные инвайты удаляются
После бана пользователь блокируется на уровне /start и не может зарегистрироваться повторно.
Автокик по истечению подписки — это не бан. Пользователь может вернуться с новым инвайтом.
Снятие модератора — все неиспользованные инвайты модератора удаляются автоматически. Сам пользователь остаётся зарегистрированным.
Рассылка — отправляется только пользователям со статусом ACTIVE в Remnawave. Пользователи с истёкшей подпиской или заблокированные не получают.
Бот мониторит VPS-ноды через Prometheus Node Exporter и отображает их состояние в live-дашборде (кнопка 📡 Серверы). При уходе ноды в офлайн или перегрузке приходит алерт в Telegram.
На каждой ноде выполни:
bash <(wget -qO- https://raw.githubusercontent.com/fUS1ONd/vpn_bot/main/scripts/install-node-exporter.sh) <IP_СЕРВЕРА_С_БОТОМ>Скрипт устанавливает Node Exporter, открывает порт 9100 только для IP сервера с ботом и добавляет сервис в автозапуск.
В Remnawave добавь тег bw:<Mbps> к ноде для указания bandwidth (например bw:1000 = 1 Gbit). По умолчанию 1000 Mbps.
- Нода OFFLINE — Node Exporter не отвечает
- Load Index > 80% — нода перегружена (
Load Average × 100 / bandwidth)
go mod download # Установить зависимости
make down # Остановить бота
make up # Пересобрать и запустить
make tests # Запустить тесты
make fmt # Проверить форматирование
make logs # Показать логиСтруктура:
vpn_bot/
├── cmd/
│ ├── bot/ → Точка входа бота
│ └── migrator/ → Утилита миграции пользователей из старой БД
├── internal/
│ ├── bot/ → Обработчики, клавиатуры, дашборд, состояния, scheduler
│ ├── callback/ → HTTP callback-сервер Platega
│ ├── database/ → SQLite (users, invites, payments, moderator_earnings, moderators, bans, notifications)
│ ├── platega/ → HTTP-клиент Platega
│ ├── remnawave/ → HTTP-клиент Remnawave API
│ ├── monitoring/ → Метрики, алерты, service discovery
│ └── config/ → Загрузка конфигурации
├── scripts/
│ └── install-node-exporter.sh → Установка Node Exporter на ноды
├── monitoring/
│ └── prometheus.yml → Конфиг vmagent
├── docs/ → API документация, планы, прогресс
├── Makefile
└── docker-compose.yml → bot + VictoriaMetrics + vmagent
- Remnawave
- Документация Platega
- Чеклист деплоя платежей
- CLAUDE.md / AGENTS.md — инструкции для работы с репозиторием