β‘ 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.
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=[email protected]
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: [email protected]
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