Table of Contents
- What a XUI.ONE Load Balancer Actually Does
- Architecture Overview
- Before You Start: What to Prepare
- Step 1 - Open MySQL on the Main Server
- Step 2 - Prepare the LB Server
- Step 3 - Run the XUI.ONE LB Installer
- Step 4 - Register the LB in the Admin Panel
- Step 5 - Test and Route Streams
- Troubleshooting
- Scaling Limits of XUI.ONE Load Balancers
- FAQ
What a XUI.ONE Load Balancer Actually Does
A XUI.ONE load balancer is a second server running the panel code in “load balancer” mode. It has no admin UI and no independent database. Instead, it connects back to the main server's MySQL, receives stream assignments from the admin, and serves HLS/TS/RTMP output to end users.
The pattern exists because a single server cannot handle both the admin PHP workload (resellers logging in, users authenticating, M3U playlists generating) AND the streaming bandwidth (gigabits of TS/HLS traffic). Splitting them across servers lets you scale streaming independently of admin traffic.
Architecture Overview
[ End Users ]
|
v
+------------------------+
| Load Balancer(s) | <-- serves HLS/TS/RTMP
| :8080 :25461 |
+------------------------+
|
| Paramiko (SSH) for sync
| + remote MySQL :3306 for reads
v
+------------------------+
| Main Server | <-- admin, DB, cron
| MySQL + admin UI |
+------------------------+
The LB talks to the main server in two ways:
- MySQL on 3306 so the LB can read which streams, users, and permissions are current.
- SSH + paramiko (Python 2) so the main server can push config changes, restart services, and run FFmpeg orchestration on the LB.
Before You Start
- Main server: already running XUI.ONE (see the install guide).
- LB server: a fresh Ubuntu 20.04 LTS VPS (20.04 is the safest LB OS - fewer compatibility issues than 22.04/24.04).
- Network: both boxes on the public internet with a static public IPv4 each. Private networking is optional.
- MySQL root password from the main server.
- Root SSH access to both.
- Bandwidth: the LB is only useful if its NIC and transit pipe are larger than your main server's. 10 Gbps uplink is typical for serious LBs.
1Open MySQL on the Main Server for Remote Access
On the main server, open MariaDB to connect from the LB's public IP:
Find and comment out bind-address:
Grant remote privileges for the LB's IP (replace LB_PUBLIC_IP):
% (anywhere). That is a popular shortcut that leaks your database to the open internet. Lock it to the LB's specific IP and firewall everything else.
Open port 3306 in UFW only to the LB IP:
Confirm the main server is listening on 0.0.0.0:3306:
2Prepare the LB Server
On the LB server, run a clean base install:
Test the MySQL connection from the LB to the main server before doing anything else - it is the most common point of failure:
If this fails, fix it now. The XUI.ONE LB installer will fail in confusing ways otherwise.
File descriptor limits (same as main):
Install paramiko for Python 2 (the main server will SSH into this box via paramiko):
3Run the XUI.ONE LB Installer
Still on the LB, fetch and run the installer but pick load_balancer at the prompt:
At the prompts:
- Installation type:
load_balancer - MySQL host: the main server's public IP (or private IP if both boxes are on the same internal network)
- MySQL password: the XUI.ONE DB user password
- Server name: give it something descriptive (e.g.,
lb1-london) - Server IP: the LB's own public IP
- Client port: match the main server's client port (usually
2086or25461)
The installer downloads the same content bundle as the main server (sans admin UI) and starts Nginx, PHP-FPM, and the stream workers.
4Register the LB in the Admin Panel
Go to the main server's admin UI → Management → Streaming Servers → Add Server. Fill in:
- Server name: matches what you typed during install.
- IP address: LB's public IP.
- SSH port: 22.
- SSH user:
root. - SSH password: the LB's root password (or drop an SSH key in
/root/.ssh/authorized_keyson the LB). - Total bandwidth: the LB's uplink in Gbps.
- Enabled for: tick the stream types this LB should serve (Live, VOD, HLS, RTMP).
Save. The admin will run an SSH check via paramiko. If it succeeds you will see online next to the server name.
ssh-keygen -t ed25519 -N '' -f /root/.ssh/xui_lb, then ssh-copy-id -i /root/.ssh/xui_lb.pub root@LB_IP. Paste the private key content into the panel's SSH field and your sync is password-less.
5Route Streams to the LB and Test
In the admin go to Management → Streams → edit a test stream → Streaming servers. Add the new LB to the list. Save. The main server will push the FFmpeg command to the LB via paramiko.
On the LB, verify FFmpeg is running the stream:
Test that the stream is reachable directly on the LB:
You should get a 200 OK with a TS content type.
If your panel is using a DNS hostname (e.g. cdn.mypanel.tv) that load-balances across multiple LBs, add an A record for each LB IP and rely on DNS round-robin. For serious setups, use a front door like HAProxy or a managed CDN.
Troubleshooting
LB shows “offline” in the main panel
In 90 percent of cases: paramiko cannot SSH to the LB. On the main server run:
If this fails, the issue is on the LB (root SSH disabled, wrong password, UFW blocking port 22 from the main server).
“Permission denied (publickey)”
The LB has PermitRootLogin prohibit-password set. Open /etc/ssh/sshd_config, change to PermitRootLogin yes, then systemctl restart sshd. Or add the main server's SSH key to the LB's /root/.ssh/authorized_keys.
Streams run on LB but show offline on main panel
MySQL sync between LB and main is broken. Check the LB can reach MySQL:
If this times out, open 3306 from LB IP on the main's firewall.
LB runs 100 percent CPU with one stream
Transcoding profile is wrong. The LB is re-encoding when the main server intended a copy. In the stream settings set Transcoding Profile to Copy for live TV.
“paramiko.ssh_exception.SSHException: Server '…' not found in known_hosts”
Xtream UI forks sometimes write a strict host policy. Force auto-add:
Scaling Limits of XUI.ONE Load Balancers
A XUI.ONE LB handles 500-1500 concurrent HLS users per 10 Gbps of NIC, depending on bitrate. It does not:
- Share nothing between LBs. Each LB runs its own FFmpeg workers. Restreaming the same channel on four LBs costs four times the source bandwidth.
- Have automatic failover. If a LB dies, streams assigned to it go offline. You must manually re-assign or use external DNS health checks.
- Support DRM. There is no Widevine key pipeline on the LB path.
- Protect itself from DDoS. The LB's Nginx and PHP-FPM will fold under any serious Layer 7 attack. You need Cloudflare or a dedicated scrubber in front.
For small setups (1-3 LBs, < 2000 total users) XUI.ONE's LB feature is workable. For anything larger, you run into the above limits hard.
