diff --git a/README.md b/README.md index 46548d8..c14dbe2 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,70 @@ -# Py-3XUI-multiserver +# ZernProxy Manager (Py-3XUI-multiserver) -Объединение нескольких серверов 3x-UI в единую VPN-подписку. Soft-tariff система с веб-панелью, донатной оплатой и Happ-совместимостью. +Объединение нескольких серверов 3x-UI в единую VPN-подписку. Soft-tariff система с веб-панелью, донатной оплатой, Happ и WDTT совместимостью. ## Architecture ``` -servers.conf ──→ 3x-UI сервера (API + sub URL) -settings.conf ──→ тарифы, платежи, админка +servers.conf ──→ 3x-UI сервера (API + sub URL + status URL) +settings.conf ──→ тарифы, платежи, админка, auto-propagate users.db ───────→ пользователи (SQLite) ↓ aggregator.py ──→ FastAPI сервер ↓ - /sub/{id} ────→ подписка для клиента (VLESS links) + /sub/{id} ────→ подписка для клиента (VLESS / Trojan / VMess / Shadowsocks) /admin/* ─────→ веб-панель управления + /admin/api/propagate/{server} → синхронизация пользователей между серверами + / ────────────→ статус-пейдж с health-check серверов ``` **Soft-tariff**: пользователь создаётся на всех inbounds один раз, tier (free/test/paid) меняется локально в БД, без дёргания 3x-UI API. ## Features -- Multi-server: объединение любого количества 3x-UI серверов -- Multi-inbound: поддержка нескольких inbound на сервере -- Soft-tariff: free / test / paid tier без пересоздания клиентов -- DonationAlerts: приём платежей (50₽ → test 7д, 150₽ → paid 30д, 990₽ → paid 365д) -- Веб-панель: дашборд, CRUD пользователей, просмотр трафика, QR-коды -- Happ.su совместимость: hide-settings, sub-expire, announce через HTTP-хедеры -- In-memory кеш: ссылки кешируются на 7 дней, трафик — на 2 минуты -- ShortID ротация: автоматическая смена shortId на серверах каждые N часов -- MOTD: объявления из motd.txt или settings +- **Multi-server**: объединение любого количества 3x-UI серверов +- **Multi-inbound**: поддержка нескольких inbound на сервере (разные протоколы) +- **Soft-tariff**: free / test / paid tier без пересоздания клиентов +- **Propagate**: синхронизация пользователей между серверами по strict majority (>50%) +- **Auto-propagate**: фоновая синхронизация по расписанию (по умолчанию 30 мин) +- **DonationAlerts**: приём платежей с поиском донатера по ID/username +- **Веб-панель**: дашборд со статистикой, CRUD пользователей, просмотр трафика, QR-коды +- **Статус-пейдж**: публичная страница с health-check серверов (CPU/RAM/Disk/Net/I/O) +- **Happ.su / WDTT совместимость**: заголовки profile-title, sub-expire, announce, hide-settings +- **Абсолютный expire**: `tariff_end_at` (Unix timestamp) — дни считаются динамически, автопонижение tier при истечении +- **In-memory кеш**: ссылки кешируются на 7 дней, трафик — на 2 минуты +- **ShortID ротация**: автоматическая смена shortId на серверах каждые N часов +- **MOTD**: объявления из motd.txt или settings +- **Health scoring**: взвешенная оценка здоровья сервера (CPU 30%, RAM 25%, Disk 20%, Net 15%, I/O 10%) +- **Trojan support**: создание клиентов на Trojan инбаундах (password вместо uuid) + +## wdtt (Zern-BlackOut) Compatibility + +Проект полностью совместим с клиентом **Zern-BlackOut** (форк wdtt), доступным по адресу: +[https://git.swe.zernmc.ru/sasheg/Zern-BlackOut](https://git.swe.zernmc.ru/sasheg/Zern-BlackOut) + +> **Важно:** Клиент wdtt был модифицирован для совместимости с данным агрегатором. +> Использование оригинального wdtt без модификаций может привести к некорректной работе. +> Репозиторий Zern-BlackOut находится в активной разработке для полной интеграции. + +Поддерживаемые возможности: +- VLESS + XTLS Vision / Reality +- Trojan + HTTP + Reality +- Автообновление подписки +- Отображение expire-даты и лимитов трафика +- Hide-settings, announce, support-url через subscription-заголовки ## Quick Start ```bash pip install fastapi uvicorn httpx py3xui qrcode[pil] Pillow -git clone https://github.com/SashegDev/Py-3XUI-multiserver.git +git clone ssh://git@git.swe.zernmc.ru:2222/sasheg/Py-3XUI-multiserver.git cd Py-3XUI-multiserver # настроить servers.conf, settings.conf (см. ниже) python3 aggregator.py ``` +Для production: `screen -S aggregator python3 aggregator.py` + ## Configuration ### servers.conf @@ -48,17 +74,27 @@ python3 aggregator.py "servers": [ { "name": "ru-1", - "subscription_url": "https://panel.domain.com:2096", - "api_base_url": "https://panel.domain.com:65431/PATH", - "country": "RU", + "subscription_url": "http://panel.domain.com:2096", "sub_path": "/sub/{sub_id}", + "country": "RU", + "status_url": "http://domain.com:18765/status?secret=...", "inbounds": [ { "id": 1, "name": "Reality", - "api_host": "https://panel.domain.com:65431/PATH", + "api_host": "http://panel.domain.com:22881/PATH", "api_user": "admin", - "api_pass": "password" + "api_pass": "password", + "is_free": true + }, + { + "id": 2, + "name": "Trojan-Inbound", + "protocol": "trojan", + "api_host": "http://panel.domain.com:22881/PATH", + "api_user": "admin", + "api_pass": "password", + "is_free": false } ] } @@ -70,14 +106,16 @@ python3 aggregator.py |-------|------|-------------| | `name` | string | Unique server name | | `subscription_url` | string | Base URL for subscription links | -| `api_base_url` | string | API URL for traffic stats | -| `country` | string | 2-letter country code (RU, DE, NL...) | -| `sub_path` | string | Sub endpoint path on the server (`/sub/{sub_id}`) | +| `sub_path` | string | Sub endpoint path (`/sub/{sub_id}`) | +| `country` | string | 2-letter country code (RU, DE, PL, SE...) | +| `status_url` | string | URL for server health data (3x-UI status endpoint) | | `inbounds[].id` | int | Inbound ID in 3x-UI | | `inbounds[].name` | string | Display name | +| `inbounds[].protocol` | string | *(optional)* protocol type (`trojan`) | | `inbounds[].api_host` | string | 3x-UI API URL for this inbound | | `inbounds[].api_user` | string | API login | | `inbounds[].api_pass` | string | API password | +| `inbounds[].is_free` | bool | Доступен ли inbound для free-тарифа | ### settings.conf @@ -93,32 +131,46 @@ python3 aggregator.py "tiers": { "free": { "name": "Free", - "servers": ["ru-1"], "traffic_limit_gb": 0 }, "test": { - "name": "Test 7 days", - "servers": ["ru-1", "nl-1"], + "name": "Test", "traffic_limit_gb": 5, - "price": 50, - "duration_days": 7 + "prices": { + "test": 50 + }, + "days": { + "test": 7 + } }, "paid": { "name": "Premium", - "servers": ["ru-1", "nl-1", "de-1"], - "traffic_limit_gb": 0 + "traffic_limit_gb": 0, + "prices": { + "monthly": 150, + "yearly": 990 + }, + "days": { + "monthly": 30, + "yearly": 365 + } } }, "payments": { "donationalerts": { "enabled": true, - "token": "your_donationalerts_token", + "api_token": "...", + "webhook_secret": "...", "url": "https://www.donationalerts.com/r/you" } }, "admin": { "username": "admin", "password": "secure_password" + }, + "auto_propagate": { + "enabled": true, + "interval_minutes": 30 } } ``` @@ -127,46 +179,48 @@ python3 aggregator.py | Tier | Servers | Traffic | Price | Duration | |------|---------|---------|-------|----------| -| free | subset marked `is_free: true` in config | unlimited (0 = ∞) | free | forever | -| test | all servers | 5 GB | 50₽ | 7 days | -| paid | all servers | unlimited | 150₽/30d, 990₽/365d | configurable | +| free | inbounds with `is_free: true` | unlimited (0 = ∞) | free | forever | +| test | all inbounds | 5 GB | 50₽ | 7 days | +| paid | all inbounds | unlimited | 150₽/30d, 990₽/365d | configurable | -Free servers are defined in `servers.conf` per-server via `is_free: true`. +### Propagate -### MOTD +При добавлении нового сервера или инбаунда пользователи НЕ создаются автоматически на нём. +Для синхронизации используется **strict majority**: пользователь добавляется на целевой сервер только если он существует на >50% других активных серверов. -Two ways: -1. `motd.txt` — plain text file in project root -2. `settings.conf → announcement` — string (plain or base64) +```bash +curl -X POST http://localhost:8000/admin/api/propagate/{server_name} -b "admin_token=..." +``` + +В админ-панели кнопка 🔄 на каждом сервере. Auto-propagate запускается фоном каждые N минут. ## Endpoints | Path | Method | Description | |------|--------|-------------| | `/sub/{id}` | GET | Subscription (format: base64/json/raw) | -| `/sub/{id}` | GET (HTML accept) | Web page with QR and info | -| `/admin/login` | POST | Admin auth | +| `/sub/{id}` | GET (HTML) | Web page with QR and info | +| `/admin/login` | GET/POST | Admin auth | | `/admin/users` | GET | User management panel | -| `/admin/dashboard` | GET | Stats dashboard | +| `/admin/dashboard` | GET | Stats dashboard with server health | | `/admin/api/users` | POST | Create user | | `/admin/api/users/update` | POST | Update user | -| `/admin/api/users/delete` | POST | Delete user | +| `/admin/api/users/delete` | POST | Delete user (with 3x-UI) | | `/admin/api/reload` | POST | Reload configs + clear cache | +| `/admin/api/propagate/{server}` | POST | Sync users to server | | `/admin/api/rotate-shortids` | GET | Rotate short IDs on all servers | -| `/` | GET | Landing page | +| `/` | GET | Landing page with server status | ## DonationAlerts -Polling-based (every ~2 seconds). Amount mapping: -- 50₽ → test tier (7 days) -- 150₽ → paid tier (30 days) -- 990₽ → paid tier (365 days) +Polling-based (every ~2 seconds). Amount mapping from `settings.conf → tiers → prices`: +- Any configured amount → corresponding tier + days +- Donor identified by `id` or `username` from donation message +- `tariff_end_at` extends dynamically (MAX of current end, now + days) -Other amounts are ignored. Donor identified by `id` (priority) or `username` from message parts. +## Happ.su / WDTT Support -## Happ.su Support - -Subscription response includes Happ-compatible headers: +Subscription response includes compatible headers: - `Profile-Title`, `Profile-Update-Interval`, `Profile-Web-Page-Url` - `Subscription-Userinfo` (upload/download/total/expire) - `Announce`, `Support-Url`, `Hide-Settings` @@ -179,3 +233,5 @@ Subscription response includes Happ-compatible headers: - **py3xui** — 3x-UI API client - **httpx** — async HTTP for sub links - **qrcode** — QR generation +- **Plus Jakarta Sans / JetBrains Mono** — UI typography +- **Glassmorphism** — design system