docs: readme, MIT license, CI workflow
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
b7792421dd
commit
0333f33b29
3 changed files with 181 additions and 0 deletions
62
.github/workflows/ci.yml
vendored
Normal file
62
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pip install -r requirements.txt
|
||||||
|
|
||||||
|
- name: Compile check all Python files
|
||||||
|
run: python -m compileall -q .
|
||||||
|
|
||||||
|
- name: Shell syntax check
|
||||||
|
run: |
|
||||||
|
bash -n install.sh
|
||||||
|
bash -n mbs
|
||||||
|
|
||||||
|
- name: Smoke test install-script rendering
|
||||||
|
env:
|
||||||
|
BOT_TOKEN: "x"
|
||||||
|
BOT_USERNAME: "x"
|
||||||
|
ADMIN_IDS: "1"
|
||||||
|
ADMIN_PANEL_PASSWORD: "x"
|
||||||
|
PANEL_DOMAIN: "panel.test"
|
||||||
|
SUB_DOMAIN: "sub.test"
|
||||||
|
SITE_DOMAIN: "test"
|
||||||
|
XRAY_PUBLIC_KEY: "x"
|
||||||
|
XRAY_SHORT_ID_TCP: "x"
|
||||||
|
XRAY_SHORT_ID_GRPC: "x"
|
||||||
|
XRAY_SHORT_ID_XHTTP: "x"
|
||||||
|
run: |
|
||||||
|
python - << 'PYEOF'
|
||||||
|
import json
|
||||||
|
import nodeprov
|
||||||
|
|
||||||
|
transports = nodeprov.build_transports("fi2.example.com", 443, "www.microsoft.com", "PUBKEY", include_ws=True)
|
||||||
|
node = {
|
||||||
|
"provision_token": "TESTTOKEN",
|
||||||
|
"address": "fi2.example.com",
|
||||||
|
"sni": "www.microsoft.com",
|
||||||
|
"private_key": "PRIVKEY",
|
||||||
|
"transports_json": json.dumps(transports),
|
||||||
|
"hysteria_enabled": 1,
|
||||||
|
"hysteria_port": 443,
|
||||||
|
"hysteria_password": "hypass",
|
||||||
|
"hysteria_obfs_password": "obfspass",
|
||||||
|
}
|
||||||
|
script = nodeprov.render_install_script(node)
|
||||||
|
assert "PRIVKEY" in script
|
||||||
|
assert len(script) > 500
|
||||||
|
print("node install script rendered OK,", len(script), "bytes")
|
||||||
|
PYEOF
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 savsis
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
98
README.md
Normal file
98
README.md
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
# MBS Panel
|
||||||
|
|
||||||
|
Самостоятельная VPN-панель на VLESS+Reality (+ gRPC/XHTTP/WS-TLS транспорты) и Hysteria2. Телеграм-бот для выдачи подписок, веб-сайт с личным кабинетом, и админ-панель для управления нодами, юзерами и трафиком — всё в одном репозитории, без сторонних панелей типа x-ui или Marzban под капотом.
|
||||||
|
|
||||||
|
Сделано by savsis. Изначально писалось под конкретный проект (шеринг VPN среди своих), но получилось достаточно универсально, чтобы выложить как есть.
|
||||||
|
|
||||||
|
## Что внутри
|
||||||
|
|
||||||
|
- **Бот** (aiogram 3) — выдача подписок по кнопкам, гифт-коды, привязка тарифов (7 дней / месяц / 3 месяца / полгода / год), автоматическое отключение по истечении подписки (не раз в полчаса, а раз в 90 секунд — важно, чтобы просрочка реально обрывала доступ, а не продолжала работать).
|
||||||
|
- **API + сайт** (FastAPI) — страница подписки со ссылкой `happ://` и QR-кодом, личный кабинет, JSON API для сайта.
|
||||||
|
- **Админ-панель** (чистый HTML/CSS/JS, без фреймворков и сборки) — дашборд, юзеры, подписки, гифт-коды, ноды, трафик по Stats API самого Xray.
|
||||||
|
- **Мультинодовость** — добавляешь новую ноду в панели, получаешь одну команду `bash <(curl ...)`, вставляешь на чистый сервер — нода сама ставит Xray, генерит ключи, регистрируется в панели. Как у Remnawave/3x-ui, только свой велосипед.
|
||||||
|
- **Протоколы на выбор при добавлении ноды**: VLESS TCP+Reality, VLESS gRPC+Reality, VLESS XHTTP+Reality, VLESS WS+TLS (с реальным Let's Encrypt сертификатом), Hysteria2 (QUIC, отдельный процесс, obfs).
|
||||||
|
- **CLI `mbs`** — управление панелью прямо с сервера: пароль, статус, рестарт, логи.
|
||||||
|
|
||||||
|
## Архитектура
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐ ┌──────────────────────────────┐
|
||||||
|
│ Telegram │──────▶│ bot.py (aiogram) │
|
||||||
|
│ юзер │ │ выдаёт токен подписки │
|
||||||
|
└─────────────┘ └──────────────┬────────────────┘
|
||||||
|
│ SQLite (db.py)
|
||||||
|
┌─────────────┐ ┌──────────────▼────────────────┐
|
||||||
|
│ браузер / │──────▶│ api.py (FastAPI) │
|
||||||
|
│ Happ клиент │ │ /sub/{token}, /admin/api/* │
|
||||||
|
└─────────────┘ │ админка на / (admin.html) │
|
||||||
|
└──────────────┬────────────────┘
|
||||||
|
│ SSH (paramiko)
|
||||||
|
┌──────────────▼────────────────┐
|
||||||
|
│ Xray на этой же ноде │
|
||||||
|
│ + управляемые ноды по SSH │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Панель и первая VPN-нода живут на одном сервере. На 443 порту нельзя одновременно держать и настоящий HTTPS (для сайта/подписки), и замаскированный под HTTPS VLESS+Reality трафик — поэтому перед Xray стоит `nginx stream` модуль с `ssl_preread`, который смотрит SNI входящего TLS-соединения и роутит: домены панели/подписки идут на nginx-бэкенд, всё остальное (в том числе Reality-трафик с левым SNI) — на Xray.
|
||||||
|
|
||||||
|
## Установка — одна команда
|
||||||
|
|
||||||
|
Нужен чистый сервер на **Ubuntu 22.04/24.04** или **Debian 11/12**, root-доступ и три поднятых DNS A-записи (см. таблицу ниже).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ImSavsis/mbs-panel.git && cd mbs-panel && sudo bash install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт спросит домен панели, домен подписки, токен бота от [@BotFather](https://t.me/BotFather) и список Telegram ID админов — и дальше всё сам: ставит зависимости, Xray, nginx, выпускает сертификаты Let's Encrypt, генерирует Reality-ключи, поднимает systemd-сервисы, настраивает firewall (ufw) и fail2ban. В конце покажет пароль от админки и ссылку на панель.
|
||||||
|
|
||||||
|
### DNS-записи
|
||||||
|
|
||||||
|
Подними их **до** запуска `install.sh` — иначе Let's Encrypt не сможет выпустить сертификаты.
|
||||||
|
|
||||||
|
| Запись | Тип | Куда указывает | Зачем |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `panel.example.com` | A | IP сервера панели | Админка (веб-интерфейс) |
|
||||||
|
| `sub.example.com` | A | IP сервера панели | Страница подписки + личный кабинет |
|
||||||
|
| `de1.example.com` | A | IP сервера панели | Адрес, на который подключаются VPN-клиенты (первая нода) |
|
||||||
|
|
||||||
|
Для каждой **дополнительной** ноды (добавляется позже через панель) — ещё одна A-запись на IP той ноды, например `de2.example.com`, `nl1.example.com` и т.д. Панель сама подскажет, какую запись нужно создать, и выдаст готовую команду установки, когда жмёшь «Добавить ноду».
|
||||||
|
|
||||||
|
Если Cloudflare — держи эти записи **DNS only** (серое облако), не проксируй: и Reality-трафику, и Let's Encrypt нужен прямой доступ до сервера.
|
||||||
|
|
||||||
|
### После установки
|
||||||
|
|
||||||
|
- Зайди на `https://panel.example.com`, залогинься паролем из вывода скрипта.
|
||||||
|
- Смени пароль в любой момент: `mbs pass новый_пароль` (без аргумента — сгенерит случайный).
|
||||||
|
- В боте у себя (Telegram ID из ADMIN_IDS) появится админ-меню.
|
||||||
|
|
||||||
|
## CLI `mbs`
|
||||||
|
|
||||||
|
Ставится автоматически в `/usr/local/bin/mbs`.
|
||||||
|
|
||||||
|
```
|
||||||
|
mbs pass [пароль] сменить пароль админ-панели (без аргумента — случайный)
|
||||||
|
mbs status статус bot / api / xray / nginx
|
||||||
|
mbs restart перезапустить bot + api
|
||||||
|
mbs logs [bot|api|xray] последние строки лога (по умолчанию api)
|
||||||
|
mbs domain текущий домен панели
|
||||||
|
```
|
||||||
|
|
||||||
|
## Добавление ноды
|
||||||
|
|
||||||
|
В панели: Ноды → Добавить ноду → выбираешь страну, протоколы (Reality-транспорты всегда включены, WS+TLS и Hysteria2 — опционально) → получаешь команду вида:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash <(curl -Ls https://panel.example.com/install/ТОКЕН.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вставляешь на чистый сервер (тот же Ubuntu 22/24 или Debian 11/12) — нода сама всё ставит и регистрируется. Если включал WS+TLS — скрипт выпустит для неё отдельный Let's Encrypt сертификат (нужна ещё одна A-запись, см. таблицу выше). Если включал Hysteria2 — поднимет отдельный процесс на UDP.
|
||||||
|
|
||||||
|
## Разработка / вклад
|
||||||
|
|
||||||
|
Код простой — без сборки фронта, без ORM, без лишних абстракций. `admin.html` — один файл, vanilla JS. Питон-часть — обычные функции, SQLite напрямую.
|
||||||
|
|
||||||
|
PR и issues welcome. CI на каждый пуш гоняет compile-check по питону, синтаксис-проверку шелл-скриптов и smoke-тест генерации install-скрипта ноды.
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT — см. [LICENSE](LICENSE).
|
||||||
Loading…
Add table
Add a link
Reference in a new issue