MBS Panel
made by savsis

Вход

Логин и пароль администратора

MBS Panel/Дашборд
Поиск и командыCtrl K
онлайн
Дашборд
Что происходит с сервисом прямо сейчас

Сеть

Последние действия

Последние подписки

ПользовательСерверТарифИстекаетСтатус
Юзеры
Все, кто уже есть в системе, в том числе те, у кого ни разу не было подписки (в «Подписках» их не видно). Открой карточку и выдай подписку на любую ноду и срок.
ПользовательПодпискиАктивна доУстройствЗарегистрирован
Подписки
Все выданные подписки
ПользовательСерверТарифВыданаИстекаетСтатус
Гифт-коды
Ссылки, которые сразу выдают подписку — работают даже для тех, кто ни разу не открывал бота
СерверСрокСозданСтатусСсылка
Ноды
Локации, из которых бот выдаёт подписки
ЛокацияАдресТипСтатусПингLive

Добавить ноду

Гайд по установке
Вручную

Заполни данные новой локации — панель сгенерирует ключи и команду, включит TCP+Reality, gRPC+Reality и XHTTP+Reality разом. Выполни команду на чистом Ubuntu-сервере (по SSH) — Xray установится и настроится сам, ничего дополнительно передавать не нужно.

Цепочки
Собери маршрут клиент → сервер → сервер → интернет. Зажми левую кнопку мыши на «Клиенте» и протяни провод через серверы из пула к «Интернету». Один сервер — это обычное подключение, два — цепочка. Больше двух нельзя: каждый прыжок добавляет задержку.
Клиент
зажми ЛКМ и тяни
Пул серверов
Интернет
зажми ЛКМ на клиенте, веди провод через серверы, отпусти на интернете · клик по серверу тоже добавляет его · Esc — сбросить

Маршрут

Мои цепочки

Журнал
Кто и что менял в панели — последние 300 действий. Пароли и ключи сюда не попадают, только факт действия.
ВремяАдминДействиеДеталиIP
Трафик
Суммарно по всем нодам, live через Xray Stats API

По подпискам

ПользовательСерверВходящийИсходящийВсего
Платежи
ЮKassa / Platega — история и статус, с проверкой на стороне провайдера при пропущенном вебхуке

Настройка приёма платежей

Заполни один раз — панель сама соберёт из этого публичную оферту и политику конфиденциальности (обязательны для подключения Ю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 нет публичного эндпоинта для проверки ключей без реального платежа, так что сохраняется без предварительной проверки — если ключи неверные, это будет видно по первой неудачной оплате. Применяется сразу, без рестарта.

Тарифы

Цены по срокам подписки и общий приём оплаты — меняются здесь, применяются сразу, рестарт не нужен.

История

ПользовательСерверТарифПровайдерСуммаСозданСтатус
Документация
Как устроена панель и как её обслуживать — без похода на GitHub

Архитектура

Панель — три процесса: 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 от перебора паролей). Проверить, что работает:

fail2ban-client status

Посмотреть забаненные 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. У конкретного юзера лимит можно переопределить в его карточке, это значение — только дефолт для тех, у кого свой не задан.

Применяется сразу, без рестарта панели.

↑↓ выбратьEnter открытьEsc закрыть