⚡ Fast. Simple. Long-lasting.
C³ CELERITY by Click Connect — modern web panel for managing Hysteria 2 proxy servers with centralized HTTP authentication, one-click node setup, and flexible user-to-server group mapping.
Dashboard — real-time server monitoring and statistics
1. Install Docker (if not installed):
curl -fsSL https://get.docker.com | sh2. Deploy panel (Docker Hub):
mkdir hysteria-panel && cd hysteria-panel
# Download required files
curl -O https://raw.githubusercontent.com/ClickDevTech/hysteria-panel/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/ClickDevTech/hysteria-panel/main/docker.env.example
cp docker.env.example .env
nano .env # Set your domain, email, and secrets
docker compose up -dAlternative: Build from source
git clone https://github.com/ClickDevTech/hysteria-panel.git
cd hysteria-panel
cp docker.env.example .env
nano .env # Set your domain, email, and secrets
docker compose up -d3. Open https://your-domain/panel
Required .env variables:
PANEL_DOMAIN=panel.example.com
ACME_EMAIL=admin@example.com
ENCRYPTION_KEY=your32characterkey # openssl rand -hex 16
SESSION_SECRET=yoursessionsecret # openssl rand -hex 32
MONGO_PASSWORD=yourmongopassword # openssl rand -hex 16- 🖥 Web Panel — Full UI for managing nodes and users
- 🔐 HTTP Auth — Centralized client verification via API
- 🚀 Auto Node Setup — Install Hysteria, certs, port hopping in one click
- 👥 Server Groups — Flexible user-to-node mapping
- ⚖️ Load Balancing — Distribute users by server load
- 📊 Statistics — Online users, traffic, server status
- 📱 Subscriptions — Auto-format for Clash, Sing-box, Shadowrocket
- 🔄 Backup/Restore — Automatic database backups
- 💻 SSH Terminal — Direct node access from browser
┌─────────────────┐
│ CLIENTS │
│ Clash, Sing-box │
│ Shadowrocket │
└────────┬────────┘
│
hysteria2://user:pass@host
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Node │ │ Node CH │ │ Node DE │
│ Hysteria 2 │ │ Hysteria 2 │ │ Hysteria 2 │
│ :443 + hop │ │ :443 + hop │ │ :443 + hop │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
│ POST /api/auth │ │
│ GET /online │ │
└────────────────────────┼────────────────────────┘
▼
┌────────────────────────┐
│ HYSTERIA PANEL │
│ │
│ • Web UI (/panel) │
│ • HTTP Auth API │
│ • Subscriptions │
│ • SSH Terminal │
│ • Stats Collector │
└───────────┬────────────┘
│
▼
┌────────────────────────┐
│ MongoDB │
└────────────────────────┘
- Client connects to Hysteria node with
userId:password - Node sends
POST /api/authto the panel - Panel checks: user exists, enabled, device/traffic limits
- Returns
{ "ok": true, "id": "userId" }or{ "ok": false }
Instead of rigid "plans", use flexible groups:
- Create group (e.g., "Europe", "Premium")
- Assign nodes to group
- Assign users to group
- User gets only nodes from their groups in subscription
Validates user on node connection.
// Request
{ "addr": "1.2.3.4:12345", "auth": "userId:password" }
// Response (success)
{ "ok": true, "id": "userId" }
// Response (error)
{ "ok": false }Universal subscription endpoint. Auto-detects format by User-Agent.
| User-Agent | Format |
|---|---|
shadowrocket |
Base64 URI list |
clash, stash, surge |
Clash YAML |
hiddify, sing-box |
Sing-box JSON |
| Browser | HTML page |
| Other | Plain URI list |
Query params: ?format=clash, ?format=singbox, ?format=uri
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/users |
List users |
| GET | /api/users/:userId |
Get user |
| POST | /api/users |
Create user |
| PUT | /api/users/:userId |
Update user |
| DELETE | /api/users/:userId |
Delete user |
| POST | /api/users/:userId/enable |
Enable user |
| POST | /api/users/:userId/disable |
Disable user |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/nodes |
List nodes |
| GET | /api/nodes/:id |
Get node |
| POST | /api/nodes |
Create node |
| PUT | /api/nodes/:id |
Update node |
| DELETE | /api/nodes/:id |
Delete node |
| GET | /api/nodes/:id/config |
Get node config (YAML) |
| POST | /api/nodes/:id/update-config |
Push config via SSH |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/sync |
Sync all nodes |
- Add node in panel (IP, SSH credentials)
- Click "⚙️ Auto Setup"
- Panel will automatically:
- Install Hysteria 2
- Configure ACME certificates
- Set up port hopping
- Open firewall ports
- Start service
# Install Hysteria
bash <(curl -fsSL https://get.hy2.sh/)
# Create config /etc/hysteria/config.yaml
listen: :443
acme:
domains: [your-domain.com]
email: acme@your-domain.com
auth:
type: http
http:
url: https://panel.example.com/api/auth
insecure: false
trafficStats:
listen: :9999
secret: your_secret
masquerade:
type: proxy
proxy:
url: https://www.google.com
rewriteHost: true# Start
systemctl enable --now hysteria-server
# Port hopping
iptables -t nat -A PREROUTING -p udp --dport 20000:50000 -j REDIRECT --to-port 443| Field | Type | Description |
|---|---|---|
userId |
String | Unique ID (e.g., Telegram ID) |
subscriptionToken |
String | URL token for subscription |
enabled |
Boolean | User active status |
groups |
[ObjectId] | Server groups |
trafficLimit |
Number | Traffic limit in bytes (0 = unlimited) |
maxDevices |
Number | Device limit (0 = group limit, -1 = unlimited) |
expireAt |
Date | Expiration date |
| Field | Type | Description |
|---|---|---|
name |
String | Display name |
ip |
String | IP address |
domain |
String | Domain for SNI/ACME |
port |
Number | Main port (443) |
portRange |
String | Port hopping range |
groups |
[ObjectId] | Server groups |
maxOnlineUsers |
Number | Max online for load balancing |
status |
String | online/offline/error |
| Field | Type | Description |
|---|---|---|
name |
String | Group name |
color |
String | UI color (#hex) |
maxDevices |
Number | Device limit for group |
Configure in Settings:
- Enable balancing — Sort nodes by current load
- Hide overloaded — Exclude nodes at capacity
Algorithm:
- Get user's nodes from groups
- Sort by load % (online/max)
- Filter overloaded if enabled
- Fall back to
rankingCoefficient
Limit simultaneous connections per user.
Priority:
- User's personal limit (
maxDevices > 0) - Minimum limit from user's groups
-1= unlimited
On each POST /api/auth:
- Query
/onlinefrom all nodes - Count sessions for userId
- Reject if
>= maxDevices
- Auto backups — Configure in Settings
- Manual backup — Dashboard button, auto-downloads
- Restore — Upload
.tar.gzarchive
version: '3.8'
services:
mongo:
image: mongo:7
restart: always
volumes:
- mongo_data:/data/db
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER:-hysteria}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
backend:
image: clickdevtech/hysteria-panel:latest # or build: . for development
restart: always
depends_on:
- mongo
ports:
- "80:80"
- "443:443"
volumes:
- ./logs:/app/logs
- ./greenlock.d:/app/greenlock.d
- ./backups:/app/backups
env_file:
- .env
volumes:
mongo_data:| Variable | Required | Description |
|---|---|---|
PANEL_DOMAIN |
✅ | Panel domain |
ACME_EMAIL |
✅ | Let's Encrypt email |
ENCRYPTION_KEY |
✅ | SSH encryption key (32 chars) |
SESSION_SECRET |
✅ | Session secret |
MONGO_PASSWORD |
✅ | MongoDB password |
MONGO_USER |
❌ | MongoDB user (default: hysteria) |
PANEL_IP_WHITELIST |
❌ | IP whitelist for panel |
SYNC_INTERVAL |
❌ | Sync interval in minutes (default: 2) |
Pull requests welcome!
MIT