Сеть
Последние действия
Последние подписки
| Пользователь | Сервер | Тариф | Истекает | Статус |
|---|
| Пользователь | Подписки | Активна до | Устройств | Зарегистрирован |
|---|
| Сервер | Срок | Создан | Статус | Ссылка |
|---|
| Локация | Адрес | Тип | Статус | Пинг | Live |
|---|
Добавить ноду
Заполни данные новой локации — панель сгенерирует ключи и команду, включит TCP+Reality, gRPC+Reality и XHTTP+Reality разом. Выполни команду на чистом Ubuntu-сервере (по SSH) — Xray установится и настроится сам, ничего дополнительно передавать не нужно.
Маршрут
Мои цепочки
| Время | Админ | Действие | Детали | IP |
|---|
По подпискам
| Пользователь | Сервер | Входящий | Исходящий | Всего |
|---|
Настройка приёма платежей
Заполни один раз — панель сама соберёт из этого публичную оферту и политику конфиденциальности (обязательны для подключения ЮKassa) на своих страницах, готовых к показу клиентам.
Как это работает
1. Заполни реквизиты ниже (кто ты для закона — самозанятый/ИП/ООО, ИНН, контакты). Это те же данные, что ЮKassa попросит при регистрации магазина.
2. Подключи ЮKassa: заведи магазин на yookassa.ru, в личном кабинете возьми shop_id и секретный ключ (Настройки → Ключи API), вставь сюда. Панель сразу проверит их и сохранит.
3. Ссылки на готовые оферту и политику (https://{домен}/offer, /privacy) — дай их ЮKassa при регистрации магазина, она их обязательно спросит.
Самозанятым для приёма платежей от физлиц регистрация магазина в ЮKassa доступна напрямую по паспорту и ИНН, без онлайн-кассы — она уже встроена в сервис ЮKassa. ИП/ООО — обычная регистрация магазина.
Реквизиты для документов
Страницы всегда доступны по ссылкам: /offer · /privacy — незаполненные поля показываются пометкой, что их надо указать, страница не ломается.
ЮKassa — ключи API
Панель сама постучится в ЮKassa (/v3/me) и сохранит ключи только если они рабочие. После сохранения сразу включаются приём оплаты и приём вебхуков — без рестарта; бот на всякий случай перезапускается сам, чтобы кнопки оплаты в Telegram тоже обновились немедленно.
Platega — ключи API
У Platega нет публичного эндпоинта для проверки ключей без реального платежа, так что сохраняется без предварительной проверки — если ключи неверные, это будет видно по первой неудачной оплате. Применяется сразу, без рестарта.
Тарифы
Цены по срокам подписки и общий приём оплаты — меняются здесь, применяются сразу, рестарт не нужен.
История
| Пользователь | Сервер | Тариф | Провайдер | Сумма | Создан | Статус |
|---|
Архитектура
Панель — три процесса: bot.py (телеграм-бот, aiogram) и api.py (FastAPI — админка + выдача подписок) читают одну SQLite-базу; Xray — отдельный процесс, который реально гоняет трафик. Панель никогда не проксирует VPN-трафик сама, только управляет конфигом Xray и читает его статистику через встроенный Stats API.
На 443 порту одновременно живёт и настоящий HTTPS (для сайта/подписки), и замаскированный под HTTPS VLESS+Reality — их разводит nginx stream модуль по SNI входящего TLS-соединения, до расшифровки.
Название и клиентский сайт
Настройки → «Название» — своё название бренда вместо дефолтного «MBS Panel», показывается сразу везде: заголовок и сайдбар панели, сообщения бота, страница подписки, оферта/политика, otpauth-issuer в приложении-аутентификаторе при включении 2FA. Применяется мгновенно, без рестарта.
На домене подписок (SUB_DOMAIN) панель теперь сама отдаёт готовый клиентский сайт — корень (/) рендерит site/index.html (лендинг с живыми тарифами из /api/plans), /cabinet.html — личный кабинет по токену из бота. Оба шаблона лежат в репо (site/) — правишь HTML/CSS напрямую, если нужен свой дизайн, панель только подставляет название/домены/юзернейм бота при каждом запросе.
Ноды
Локальная нода (обычно de1) — Xray на том же сервере, что и панель, управляется напрямую правкой config.json. Управляемые ноды — отдельные серверы, панель ходит на них по SSH management-ключу (генерится сам при первом добавлении ноды, публичная часть раздаётся install-скриптом ноды — панель никогда не просит пароль от нового сервера).
Добавление ноды: Ноды → Добавить ноду → один bash <(curl ...)> на чистый сервер. Редактирование существующей: кнопка «Редактировать» у ноды — для de1 доступно только название (реальные параметры подключения там берутся из .env, не из базы).
Порядок нод в списке (в каком порядке юзеры видят сервера в клиенте) — перетаскиванием за ⠿ слева от строки, сохраняется сразу без отдельной кнопки. Перед каждым рестартом Xray на ноде панель сама прогоняет xray run -test и проверяет, что TLS-сертификаты реально читаемы тем юзером, под которым крутится Xray — невалидный конфиг или неверные права на серт не применяются, а откатываются с понятной ошибкой вместо падения сервиса.
Цепочки серверов
Страница «Цепочки» — конструктор маршрута клиент → сервер A → сервер B → интернет. По умолчанию клиент ходит через одну ноду; цепочка добавляет второй прыжок: трафик заходит на сервер A, оттуда уходит на сервер B и только он выпускает его в интернет. Для сайтов виден IP сервера B, а клиент подключается к A — удобно, когда вход надо держать в «чистом» регионе, а выход — в нужной стране. Больше двух серверов нельзя намеренно: каждый лишний прыжок добавляет задержку.
Как собрать: зажми левую кнопку мыши на «Клиенте» и тяни провод — когда проходишь над сервером из пула, он цепляется в маршрут (цифра 1 — вход, 2 — выход). Отпусти провод на «Интернете», чтобы замкнуть. Можно и кликами: клик по серверу добавляет его, клик по «Интернету» замыкает. Esc или «Сбросить» — начать заново, крестик на сервере убирает его и всё, что после.
Что происходит под капотом: на входной ноде панель добавляет Xray-inbound chain-код (тот же ключ Reality, что у ноды, но отдельный порт из диапазона 10443–10999 и свой short ID) и outbound до выходной ноды, а в routing — правило «всё из этого inbound уходит в этот outbound». На выходной ноде заводится служебный клиент relay-код — под ним входная нода ходит на выход. Порт открывается в ufw сам. Пользователям входной ноды в подписку добавляется ещё одна ссылка «Вход → Выход». Подписчикам выходной ноды цепочка не выдаётся.
Перед применением панель прогоняет xray run -test, проверяет, что порт не занят, и после рестарта убеждается, что Xray поднялся — если нет, конфиг откатывается сам. Любая ошибка цепочки не блокирует синхронизацию подписчиков: клиенты всё равно применятся, а проблема покажется в ответе.
Выходом может быть и внешняя нода с общим (shared) UUID — тогда служебный клиент не нужен. Входом — только локальная или управляемая нода, потому что панель правит её конфиг. Ноду, которая участвует в цепочке, нельзя удалить — сначала удали цепочку.
Важно для Reality: SNI-маскировка (dest) не должна быть сайтом с пост-квантовым обменом ключами (например, www.microsoft.com) — на таком Reality не работает ни в цепочке, ни без неё. Дефолтный www.wildberries.ru подходит.
Юзеры и выдача подписок
Страница «Юзеры» — все, кто уже есть в базе, включая тех, у кого подписок не было ни разу (в «Подписках» они не появляются, потому что там только выданное). Поиск идёт по юзернейму и Telegram ID. «Выдать подписку» открывает карточку юзера: выбираешь ноду и срок, подписка создаётся сразу, а клиент добавляется в Xray. Поле «Выдать по Telegram ID» работает и для тех, кого в базе ещё нет: запись создастся при выдаче, подписка будет ждать, пока человек зайдёт в бота. Каждая выдача попадает в журнал.
Журнал действий
Страница «Журнал» — кто из админов и когда менял ноды, цепочки, подписки, настройки, скачивал бэкап и входил в панель (включая неудачные входы и неверные коды 2FA, с IP). Хранится последние 5000 записей. Содержимое запросов (пароли, ключи, токены) в журнал не пишется — только факт и адрес действия.
Поиск и команды
Ctrl K (или ⌘ K) открывает палитру: быстрый переход на любую страницу, к любой ноде или цепочке, экспорт подписок в CSV, бэкап, смена акцентного цвета панели. Выбранный акцент хранится в браузере.
Пароль и безопасность
Пароль админ-панели меняется командой mbs pass на сервере (без аргумента — сгенерит случайный). Панель физически откажется стартовать, если в .env стоит "change-me"/"admin"/что-то короче 8 символов — так что пропустить это не выйдет по-тихому.
Сессия логина живёт в httpOnly-куке, опционально поверх пароля — 2FA (TOTP). На /admin/api/login и /admin/api/login/totp висит rate-limit (10 попыток за 15 минут на пароль, 10 за 5 минут на код — с одного IP). SSH-доступ на сервер — сам по себе, панель на него не влияет; отдельно стоит подумать про отключение root-логина по паролю в пользу ключей, если этого ещё не сделано.
Логинов может быть несколько (Настройки → Админы) — у каждого свой пароль и своя 2FA, нельзя удалить последнего оставшегося админа или себя самого, пока залогинен под этим аккаунтом.
Страницу входа можно увести с дефолтного /admin на свой путь — переменная ADMIN_PATH в .env на сервере (не через UI — это единственная настройка, которая намеренно не в панели, чтобы нельзя было опечататься и остаться без доступа без SSH). Требует mbs restart. Это доп. слой поверх rate-limit и 2FA, не замена — сам /admin/api/* не двигается, он и так защищён логином.
Бэкапы
Настройки → Бэкап и восстановление. Архив — консистентный снапшот базы (через встроенный backup API SQLite, безопасно даже при активной записи) плюс .env. Перед восстановлением панель сама сохраняет копию текущей базы на сервере (mbs.db.before-restore-...) и держит только 5 последних таких копий — старые чистятся сами. Восстановление .env требует ручного mbs restart, чтобы применилось и в API, а не только в боте.
Платежи и вебхуки
Вкладка Платежи → «Настройка приёма платежей» собирает публичную оферту и политику конфиденциальности (/offer, /privacy) из введённых реквизитов — ЮKassa их спросит при регистрации магазина. Дата вступления в силу проставляется один раз, правки реквизитов её не двигают.
Ключи ЮKassa проверяются вживую через их /v3/me перед сохранением; у Platega такого эндпоинта нет, ключи сохраняются без проверки. Оба провайдера включаются независимо.
Исходящие вебхуки (Настройки → Webhook на события) — панель стучится на указанный URL при оплате (payment.paid), ручной выдаче подписки админом (subscription.granted_by_admin), отзыве (subscription.revoked), постановке на паузу (subscription.held) и возобновлении (subscription.resumed), а также при добавлении (node.added), удалении (node.deleted) и включении/выключении ноды (node.enabled/node.disabled — только когда состояние реально поменялось, не на каждое сохранение формы редактирования). Тело подписано X-Signature (HMAC-SHA256). Секрет выдаётся один раз и не меняется при правке URL — для интеграций со своими системами, без опроса API.
Вкладка Платежи → «Тарифы» — цены по срокам и общий рубильник приёма оплаты. Как и реквизиты с ключами провайдеров, это читается панелью напрямую из .env при каждом запросе — правки в UI применяются мгновенно везде (бот, API, проверка вебхуков), рестарт панели нигде не требуется.
Лимит устройств (HWID)
Настройки → «Лимит устройств» — глобальный рубильник и лимит по умолчанию (как у Remnawave: клиент шлёт заголовок x-hwid при запросе конфига, панель запоминает первые N уникальных устройств на юзера и отказывает новым сверх лимита). У конкретного юзера лимит можно переопределить отдельно — в его карточке (Подписки → кнопка «Карточка» → таб «Устройства»), это имеет приоритет над глобальным значением по умолчанию.
Пауза подписки
Кнопка «Пауза» у активной подписки (в Подписках и в карточке юзера) — не то же самое, что «Отозвать». Пауза сразу убирает клиента из Xray (доступ пропадает), но остаток срока сохраняется: сколько дней было на паузе — ровно столько добавится к expires_at при нажатии «Возобновить». «Отозвать», наоборот, необратимо — новую подписку тогда выдаёт только «Карточка» → ручная выдача.
fail2ban
install.sh ставит и включает fail2ban автоматически (дефолтный jail — защита SSH от перебора паролей). Проверить, что работает:
Посмотреть забаненные IP по конкретному джейлу: fail2ban-client status sshd. Разбанить: fail2ban-client set sshd unbanip АЙПИ.
Название
Показывается везде, где сейчас видят клиенты и ты сам: сайт, бот, страница подписки, оферта/политика, вход в панель.
Применяется сразу везде, без рестарта.
Telegram-бот
Сейчас: — (токен: —)
Панель сама проверит токен у Telegram (запрос getMe) перед применением и подставит настоящий юзернейм бота — придумывать не нужно. Применяется сразу — бот перезапускается сам, а панель (уведомления об оплате, ссылки на бота) подхватывает новый токен и юзернейм без рестарта.
Админы
Отдельные логины для входа в панель — на случай если админов несколько.
| Логин | Создан |
|---|
Двухфакторная аутентификация
Код из Google Authenticator/Authy/1Password при входе, в дополнение к паролю. Настраивается для твоего текущего логина.
Бэкап и восстановление
Бэкап — это база (юзеры, подписки, ноды, платежи) и .env одним файлом. Держи копии где-то отдельно от сервера.
⚠ Заменяет текущую базу целиком. Перед заменой панель сама делает копию текущей базы на сервере (файл .before-restore-...), но проверь, что заливаешь именно тот файл, что нужно.
Webhook на события
Панель сама постучится на твой URL при оплате или ручной выдаче подписки — для своих интеграций (CRM, аналитика, что угодно), без опроса API.
События: payment.paid, subscription.granted_by_admin, subscription.revoked, subscription.held, subscription.resumed, node.added, node.deleted, node.enabled, node.disabled, chain.created, chain.deleted, chain.enabled, chain.disabled. Тело — JSON {"event": "...", "data": {...}}, подписано заголовком X-Signature (HMAC-SHA256 от тела запроса на секрете ниже) — так получатель проверяет, что запрос реально от панели.
Секрет для проверки: —
Лимит устройств (HWID)
Ограничивает число разных устройств на одну подписку — как у Remnawave. У конкретного юзера лимит можно переопределить в его карточке, это значение — только дефолт для тех, у кого свой не задан.
Применяется сразу, без рестарта панели.