ZernProxy Manager (Py-3XUI-multiserver)
Объединение нескольких серверов 3x-UI в единую VPN-подписку. Soft-tariff система с веб-панелью, донатной оплатой, Happ и WDTT совместимостью.
Architecture
servers.conf ──→ 3x-UI сервера (API + sub URL + status URL)
settings.conf ──→ тарифы, платежи, админка, auto-propagate
users.db ───────→ пользователи (SQLite)
↓
aggregator.py ──→ FastAPI сервер
↓
/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 без пересоздания клиентов
- 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
Важно: Клиент wdtt был модифицирован для совместимости с данным агрегатором. Использование оригинального wdtt без модификаций может привести к некорректной работе. Репозиторий Zern-BlackOut находится в активной разработке для полной интеграции.
Поддерживаемые возможности:
- VLESS + XTLS Vision / Reality
- Trojan + HTTP + Reality
- Автообновление подписки
- Отображение expire-даты и лимитов трафика
- Hide-settings, announce, support-url через subscription-заголовки
Quick Start
pip install fastapi uvicorn httpx py3xui qrcode[pil] Pillow
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
{
"servers": [
{
"name": "ru-1",
"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": "http://panel.domain.com:22881/PATH",
"api_user": "admin",
"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
}
]
}
]
}
| Field | Type | Description |
|---|---|---|
name |
string | Unique server name |
subscription_url |
string | Base URL for subscription links |
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
{
"general": {
"title": "MyVPN",
"host": "conn.example.com",
"support_url": "https://t.me/support"
},
"announcement": "base64 enc or plain text",
"shortid_rotation_hours": 11,
"tiers": {
"free": {
"name": "Free",
"traffic_limit_gb": 0
},
"test": {
"name": "Test",
"traffic_limit_gb": 5,
"prices": {
"test": 50
},
"days": {
"test": 7
}
},
"paid": {
"name": "Premium",
"traffic_limit_gb": 0,
"prices": {
"monthly": 150,
"yearly": 990
},
"days": {
"monthly": 30,
"yearly": 365
}
}
},
"payments": {
"donationalerts": {
"enabled": true,
"api_token": "...",
"webhook_secret": "...",
"url": "https://www.donationalerts.com/r/you"
}
},
"admin": {
"username": "admin",
"password": "secure_password"
},
"auto_propagate": {
"enabled": true,
"interval_minutes": 30
}
}
Tiers
| Tier | Servers | Traffic | Price | Duration |
|---|---|---|---|---|
| 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 |
Propagate
При добавлении нового сервера или инбаунда пользователи НЕ создаются автоматически на нём. Для синхронизации используется strict majority: пользователь добавляется на целевой сервер только если он существует на >50% других активных серверов.
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) | Web page with QR and info |
/admin/login |
GET/POST | Admin auth |
/admin/users |
GET | User management panel |
/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 (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 with server status |
DonationAlerts
Polling-based (every ~2 seconds). Amount mapping from settings.conf → tiers → prices:
- Any configured amount → corresponding tier + days
- Donor identified by
idorusernamefrom donation message tariff_end_atextends dynamically (MAX of current end, now + days)
Happ.su / WDTT Support
Subscription response includes compatible headers:
Profile-Title,Profile-Update-Interval,Profile-Web-Page-UrlSubscription-Userinfo(upload/download/total/expire)Announce,Support-Url,Hide-SettingsSub-Expire,Sub-Expire-Button-Link
Tech
- FastAPI + uvicorn
- SQLite (users only)
- py3xui — 3x-UI API client
- httpx — async HTTP for sub links
- qrcode — QR generation
- Plus Jakarta Sans / JetBrains Mono — UI typography
- Glassmorphism — design system