Skip to content

Client balancer (Xray JSON)

The client balancer gives users one entry in the subscription that always works well. When one of the hosts gets weak or goes down, there is nothing to reconfigure: the client measures the latency of every host and keeps traffic on the two best ones. The panel assembles this config automatically, nothing changes on the nodes, and the original hosts are not deleted. While the balancer lives they are hidden from the subscription: dead entries would only confuse users. Removing the balancer brings back both the nodes and the entries.

Two presets

A single pool where the fastest wins, or main hosts with a backup that takes over when the mains are unreachable.

Hidden copies

The config is assembled from hidden clones of your hosts, and for Mihomo a ready group is added. Regular subscriptions keep the original list untouched.

Checker-safe

Xray Checker and other subscription types never see the balancer entry, so no false down alerts.

Panel-driven

The Xray JSON template, the clones and the wrapper host are created through the API, with cleanup on teardown.

The entry lives in the script menu: 4. Node extensions → Client balancer.

clientv2rayN · Happone subscription entryprobe every minuteGermany12 ms · trafficEstonia34 msFrankfurt48 msleastLoad · two best hoststhe client measures latency itself and keeps traffic on the two best hosts

Xray JSON clients

the panel assembles one config from hidden clones of your hosts
every 30 seconds the client measures every host through burstObservatory
leastLoad keeps connections on the two best, a degraded host is left on its own

Mihomo clients

a ready group with your hosts is added to the default Mihomo template
“Always the fastest” works as url-test, “Main with backup” as fallback with your order
the client picks the fastest itself, the plain host group stays next to it, one switch in the client

The subscription shows one entry with the balancer name, and it has no address of its own: the client connects straight to the hosts inside the balancer.

  1. Open 4. Node extensions and pick Client balancer:

    root@server: ~
    Node Extensions
    
    1.Selfsteal node template
        disguise the node as a regular website
    2.Node Plugins
        extra features for the node
    3.SSH access to remote machines
        saved servers and running commands on them
    4.Server routing
        Russian domains through the bridge to the exit server, the rest directly
    5.Client balancer
        one subscription entry instead of a host list
    
    0.Exit
    
    Select action (0-5):5
  2. No balancers yet, create the first one:

    root@server: ~
    Client balancer
     Details in the wiki: https://wiki.egam.es/configuration/client-balancer/
    
     No balancers configured
    
    1.Create a balancer
    
    0.Exit
    
    Select action (0-1):1
  3. Pick who will use the balancer. The examples below follow Xray JSON, the Mihomo variant is described in the subsection later:

    root@server: ~
    Who will use the balancer?
    
    1.Xray JSON
        v2rayN, Happ and other full Xray config clients
    2.Mihomo
        Clash Meta, Stash and the like: an auto-picking group in the subscription
    
    0.Exit
    
    Select action (0-2):1
  4. Pick the preset. The examples below follow “Always the fastest”:

    root@server: ~
    How should the client pick a host?
    
    1.Always the fastest
        the client measures latency and keeps traffic on the two best hosts
    2.Main with backup
        traffic uses the main hosts, the first backup takes over when they are unreachable
    
    0.Exit
    
    Select action (0-2):1
  5. When no inbound offers two fitting hosts (the common picture right after add-node, where every node carries a profile of its own), the wizard offers hosts from all inbounds on its own. When fitting inbounds exist, it lists them as in the subsection below. Pick the main hosts, numbers are entered comma separated:

    root@server: ~
     No inbound offers 2 fitting hosts: hosts will be picked across all inbounds and gathered onto a dedicated profile
    
    Main hosts:
     the selection order is kept in the client config
    
    1.Germany (de-1.example.com) — Germany / VLESS
    2.Estonia (ee-1.example.com) — Estonia / VLESS
    
    Host numbers, comma separated (1-2):1,2
  6. The hosts sit on different inbounds, so the wizard offers to gather them onto a dedicated profile. The old profiles and hosts stay exactly as they are and wake up once the balancer is removed:

    root@server: ~
    The picked hosts sit on different inbounds. A dedicated profile will be created for the balancer, the nodes switch to it, and the old profiles and hosts stay exactly as they are: they wake up once a node returns. Removing the balancer sends the nodes home automatically
    [?] Proceed with a dedicated profile? (y/n): y
    Creating a dedicated profile Balancer and moving the nodes onto it...
    Nodes are on profile Balancer, the old profiles are untouched
  7. Enter the name. This is what users see in their subscription, Enter picks “Auto”:

    root@server: ~
    Name in the subscription (Enter picks Auto):Germany+Estonia
    Creating the Xray JSON subscription template: CB balancer
    Template created
    Hiding a copy of host Germany...
    Copy hidden: Germany
    Hiding a copy of host Estonia...
    Copy hidden: Estonia
    Writing the balancer config into the template...
    Config written
    Creating the wrapper host Germany+Estonia...
    Wrapper host ready
    
    Hiding the sleeping original hosts...
    Original hosts hidden: 2. They return to the subscription once the balancer is removed
    Done: subscriptions of type Xray JSON now show host Germany+Estonia with 2 main hosts inside
     Regular subscriptions and Xray Checker never see it, that is by design
     The original hosts sleep hidden from the subscription while their nodes serve the balancer: remove it and both the nodes and the entries come back on their own

A balancer needs no dedicated profile when its hosts live on one inbound: it takes the existing one and the nodes are never touched. The wizard lists the fitting inbounds, the “Across inbounds” option gathers the hosts onto a dedicated profile instead:

root@server: ~
 Every eligible host already sits on one inbound: Germany / VLESS

Inbound for the balancer:
 hosts must live on one inbound, and it must be in the squads of the users who should get the balancer

1.Germany / VLESS — eligible hosts: 3
2.Across inbounds
    the hosts are gathered onto a dedicated profile the nodes switch to

0.Exit

Select action (0-2):1

From there the host picker shows only that inbound, and the dedicated-profile question is never asked.

With Mihomo things are simpler: hosts from any inbound qualify, no dedicated profile and no hidden clones. The wizard adds a ready group into the default Mihomo template, and it appears in the subscription next to the plain host list. The user switches to it once in the client:

root@server: ~
Who will use the balancer?

1.Xray JSON
    v2rayN, Happ and other full Xray config clients
2.Mihomo
    Clash Meta, Stash and the like: an auto-picking group in the subscription

0.Exit

Select action (0-2):2
How should the client pick a host?

1.Always the fastest
    the client measures latency and keeps traffic on the two best hosts
2.Main with backup
    traffic uses the main hosts, the first backup takes over when they are unreachable

0.Exit

Select action (0-2):1
Main hosts:
 the selection order is kept in the client config

1.Germany (de-1.example.com) — Germany / VLESS
2.Estonia (ee-1.example.com) — Estonia / VLESS

Host numbers, comma separated (1-2):1,2
Name in the subscription (Enter picks Auto):My Mihomo
Adding group My Mihomo to the Mihomo template...
Done: Mihomo subscriptions now show group My Mihomo
 The client measures latency itself and keeps traffic on the best host of the group

The presets turn into native Mihomo groups: “Always the fastest” becomes url-test, “Main with backup” becomes fallback with your host order. The group re-probes its hosts every 30 seconds. Adding and removing hosts rebuilds the group, teardown removes it from the template and touches nothing else.

One pool, every host equal. The balancer spreads connections across the two best hosts by measured latency (leastLoad, expected: 2). Fit for a set of similar servers where any of them is a fine choice.

clientv2rayN · HappGermany12 ms · trafficEstonia34 ms · trafficFrankfurt48 mstwo best in useleastLoad · expected 2one pool, every host equal, connections spread by measured latency

Hosts that already carry a job of their own are never offered to a balancer: VLESS Route hosts of the server routing module (they are personal exits, and the routing module may rewire them) and wrappers of other balancers.

There can be as many balancers as you need, each with its own host list, its own Xray JSON template and its own entry in the subscription. Five nodes of Germany gather into a balancer “Germany”, five nodes of Finland into another “Finland”, and the user sees both entries under different names.

With a cross-inbound build each one gets its own profile: the first takes “Balancer”, the second automatically “Balancer 2”, and so on. Tearing one down never touches the other, and wrappers of neighbouring balancers never appear in the host picker, so an accidental duplicate record is impossible.

The module menu lists every balancer at once with its mode. Pick a number and its own menu opens with a live status and five actions:

root@server: ~
Client balancer
 Details in the wiki: https://wiki.egam.es/configuration/client-balancer/

 Balancers configured: 2

1.Germany • mode: fastest of the pool
2.Finland • mode: main with backup
3.Create a balancer

0.Exit

Select action (0-3):

The modules work together because they answer different questions: the balancer on the client picks the entry point, server routing after the entry decides where traffic goes. Russian domains travel through the bridge to the exit server, everything else leaves the entry node directly.

Build a pool of nodes with the same routing and nothing breaks: the nodes stay on their own profiles with their own rules, and the balancer simply picks the fastest among them. No dedicated profile is even created.

clientv2rayN · Happentry poolnode DE-1routing onnode DE-2routing onbalancerRU domains → exiteverything else → directlayers do not collideexit serverSS bridgeinternetdirect

Do not gather nodes with and without routing “Across inbounds”. The dedicated profile inherits the rules of the first picked host, including the reference to the RU list file, and that file is not mounted on every node: a node without it cannot load the config and drops from the panel. Once the balancer is torn down, the node comes back on its own. Personal VLESS Route exits never join a pool at all: server routing may rewire them, so the module never offers them.

clientv2rayN · Happentry poolnode with routingalivenode, no listswent down✖no list filerules of the first hostan across-inbounds build takes down the node without the mounted list fileexit serverSS bridgeinternetdirect

The per-balancer menu shows a live status and five actions:

root@server: ~
Balancer Germany+Estonia
 Details in the wiki: https://wiki.egam.es/configuration/client-balancer/

 hosts: 2 main
 mode: fastest of the pool
 wrapper host is in place
 Xray JSON template is in place

1.Show hosts
    live list from the panel with a check that nothing is lost
2.Add hosts
    a hidden copy of each host joins the config
3.Remove a host
    the hidden copy is deleted, the original stays as is
4.Rename
    clients will see the new name in the subscription
5.Remove the balancer
    wrapper, hidden copies and template are deleted, original hosts stay

0.Exit

Select action (0-5):

Show hosts checks the stored list against the panel:

root@server: ~
Main:
 Germany (de-1.example.com)
 Estonia (ee-1.example.com)

 Every host is in place

Add hosts takes candidates from the balancer’s own inbound. A balancer built on a dedicated profile answers plainly:

root@server: ~
No eligible hosts left

A balancer on a real inbound has a list to offer, and every new clone joins the config:

root@server: ~
Hosts to add:
 the selection order is kept in the client config

1.Frankfurt (de-3.example.com) — Germany / VLESS

Host numbers, comma separated (1-1):1
Hiding a copy of host Frankfurt...
Copy hidden: Frankfurt
Refreshing the template config...
Writing the balancer config into the template...
Config written
Hosts added: 1

Remove a host deletes the hidden copy and rebuilds the config. The last backup can go, the last main hosts cannot:

root@server: ~
Which host to remove?

1.Germany (de-1.example.com) — Main
2.Estonia (ee-1.example.com) — Main

Select action (0-2):1
At least 2 main hosts must stay, tear the whole balancer down instead

Host removed, config refreshed

Rename changes the entry name in the subscription:

root@server: ~
New name (Enter keeps Germany+Estonia):Europe
Host renamed to Europe

Remove the balancer puts everything back: the wrapper, all hidden copies and the template are deleted, the original hosts were never touched. Nodes borrowed by a dedicated profile return home on their own:

root@server: ~
[?] Remove balancer Europe? The wrapper host, hidden copies and the template will be deleted, the original hosts stay (y/n): y
Tearing down balancer Europe...
Returning the nodes to their own profiles...
The nodes are back on their profiles
Balancer removed, original hosts untouched

Xray and Mihomo clients

An Xray JSON subscription entry for v2rayN and Happ, a group in the Mihomo subscription. base64, Clash, Stash and sing-box clients keep seeing the plain host list.

Subscription link

For Xray JSON the direct address carries the /v2ray-json suffix, and the wizard enables the “Serve JSON at the base subscription path” setting itself, so the full config arrives from the plain link. Mihomo needs no setting: the group arrives in the plain subscription.

The checker stays quiet

Xray Checker monitors the hosts real connections use. The wrapper is excluded from its subscription and the Mihomo group lives only in the Mihomo template: no false down alerts.

Combines with server routing

They work together: the balancer picks the entry on the client, routing decides the exit after it. The limits of the combination are described in the section above.

A familiar config

The Xray config follows the official Remnawave example: leastLoad with a one-second budget, DNS 1.1.1.1, SOCKS 10808 and HTTP 10809. Mihomo uses its native url-test and fallback groups. Hand edits live until the next list change.