Initial release: soft-tariff multi-server VPN aggregator with Happ support

This commit is contained in:
SashegDev
2026-05-16 16:45:47 +00:00
commit ac70aaae03
4 changed files with 1626 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
# Py-3XUI-multiserver
Объединение нескольких серверов 3x-UI в единую VPN-подписку. Soft-tariff система с веб-панелью, донатной оплатой и Happ-совместимостью.
## Architecture
```
servers.conf ──→ 3x-UI сервера (API + sub URL)
settings.conf ──→ тарифы, платежи, админка
users.db ───────→ пользователи (SQLite)
aggregator.py ──→ FastAPI сервер
/sub/{id} ────→ подписка для клиента (VLESS links)
/admin/* ─────→ веб-панель управления
```
**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
## Quick Start
```bash
pip install fastapi uvicorn httpx py3xui qrcode[pil] Pillow
git clone https://github.com/SashegDev/Py-3XUI-multiserver.git
cd Py-3XUI-multiserver
# настроить servers.conf, settings.conf (см. ниже)
python3 aggregator.py
```
## Configuration
### servers.conf
```json
{
"servers": [
{
"name": "ru-1",
"subscription_url": "https://panel.domain.com:2096",
"api_base_url": "https://panel.domain.com:65431/PATH",
"country": "RU",
"sub_path": "/sub/{sub_id}",
"inbounds": [
{
"id": 1,
"name": "Reality",
"api_host": "https://panel.domain.com:65431/PATH",
"api_user": "admin",
"api_pass": "password"
}
]
}
]
}
```
| Field | Type | Description |
|-------|------|-------------|
| `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}`) |
| `inbounds[].id` | int | Inbound ID in 3x-UI |
| `inbounds[].name` | string | Display name |
| `inbounds[].api_host` | string | 3x-UI API URL for this inbound |
| `inbounds[].api_user` | string | API login |
| `inbounds[].api_pass` | string | API password |
### settings.conf
```json
{
"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",
"servers": ["ru-1"],
"traffic_limit_gb": 0
},
"test": {
"name": "Test 7 days",
"servers": ["ru-1", "nl-1"],
"traffic_limit_gb": 5,
"price": 50,
"duration_days": 7
},
"paid": {
"name": "Premium",
"servers": ["ru-1", "nl-1", "de-1"],
"traffic_limit_gb": 0
}
},
"payments": {
"donationalerts": {
"enabled": true,
"token": "your_donationalerts_token",
"url": "https://www.donationalerts.com/r/you"
}
},
"admin": {
"username": "admin",
"password": "secure_password"
}
}
```
### Tiers
| 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 servers are defined in `servers.conf` per-server via `is_free: true`.
### MOTD
Two ways:
1. `motd.txt` — plain text file in project root
2. `settings.conf → announcement` — string (plain or base64)
## 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 |
| `/admin/users` | GET | User management panel |
| `/admin/dashboard` | GET | Stats dashboard |
| `/admin/api/users` | POST | Create user |
| `/admin/api/users/update` | POST | Update user |
| `/admin/api/users/delete` | POST | Delete user |
| `/admin/api/reload` | POST | Reload configs + clear cache |
| `/admin/api/rotate-shortids` | GET | Rotate short IDs on all servers |
| `/` | GET | Landing page |
## DonationAlerts
Polling-based (every ~2 seconds). Amount mapping:
- 50₽ → test tier (7 days)
- 150₽ → paid tier (30 days)
- 990₽ → paid tier (365 days)
Other amounts are ignored. Donor identified by `id` (priority) or `username` from message parts.
## Happ.su Support
Subscription response includes Happ-compatible headers:
- `Profile-Title`, `Profile-Update-Interval`, `Profile-Web-Page-Url`
- `Subscription-Userinfo` (upload/download/total/expire)
- `Announce`, `Support-Url`, `Hide-Settings`
- `Sub-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