Outbounds & Routing
Shape egress in 3x-ui — WARP, NordVPN, PIA WireGuard, outbound subscriptions, routing rules, and load balancers.
Inbounds accept clients; outbounds decide where their traffic goes next. 3x-ui can route traffic through Cloudflare WARP, NordVPN, Private Internet Access (WireGuard), or arbitrary outbound pools imported from a subscription, and select between them with routing rules and balancers.
Editing outbounds & routing
Outbounds, routing rules, balancers, DNS, and logging all live in the Xray configuration (the config template you edit under Xray Settings). There's no separate per-rule UI — you edit the JSON, and the panel reloads Xray. The panel also offers an outbound connectivity test and a route test (ask the running core which outbound a given destination would use).
Build an outbound
Every outbound is a JSON object with up to four parts: a tag (referenced by
routing rules and balancers), a protocol, protocol-specific settings,
and — for proxy protocols — streamSettings that must match the remote
inbound's transport and security. Two outbounds are almost always present:
freedomsends traffic straight to its destination — the default egress. Optionally set adomainStrategy(e.g.UseIP) to control how hostnames resolve.blackholedrops traffic. Route unwanted destinations (ads, torrents) here.
{
"outbounds": [
{ "tag": "direct", "protocol": "freedom", "settings": {} },
{ "tag": "block", "protocol": "blackhole", "settings": {} }
]
}A proxy outbound (VLESS, VMess, Trojan, Shadowsocks) forwards to another
server — handy for chaining or sending select traffic abroad. Mind the wire
shapes 3x-ui uses: VLESS is the flat form (address/port/id/flow/
encryption), VMess uses settings.vnext[], and Trojan/Shadowsocks use
settings.servers[]. The streamSettings must mirror the destination's
transport and security.
Assemble any outbound below and paste the JSON into Xray Settings → Outbounds:
Outbound config generator
Build an Xray outbound object — freedom, blackhole, a proxy protocol, WireGuard, or WARP — to paste into your Xray configuration.
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"address": "example.com",
"port": 443,
"id": "",
"flow": "",
"encryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"tcpSettings": {
"header": {
"type": "none"
}
},
"realitySettings": {
"fingerprint": "chrome",
"serverName": "www.microsoft.com"
}
}
}Cloudflare WARP
WARP lets your server egress through Cloudflare's network. 3x-ui can register a
WARP account for you and wire it into a WireGuard outbound tagged warp:
Add a warp-tagged outbound
Create a WireGuard outbound with the tag warp in your Xray config.
Register WARP
From the panel's WARP controls, register an account. 3x-ui fills the outbound's keys, addresses, reserved bytes, and peer endpoint automatically.
(Optional) auto-rotate the IP
Set a WARP update interval (in days) to periodically rotate the WARP IP. A free license can also be applied.
Route the traffic you want (for example specific domains) to the warp outbound
with a routing rule.
NordVPN
3x-ui can fetch NordVPN (NordLynx/WireGuard) credentials from an access token (or
accept a private key directly) and list countries/servers, so you can build a
NordVPN outbound. Open Xray → Outbounds → More → NordVPN, sign in or save a
private key, select a server, and add the outbound. You can add several servers;
each hostname has a unique nord-<hostname> tag and cannot be added twice.
Reset on an added row keeps its server, tag, peer, and routing references but refreshes its embedded private key from the currently stored NordVPN credentials. Logout clears only those stored credentials. Existing outbounds continue to use their embedded keys; remove unused NordVPN outbounds from the Outbounds list.
PIA WireGuard
3x-ui can sign in with a PIA username and password, list countries/regions/servers
from the signed PIA server list, and build a WireGuard outbound. Open
Xray → Outbounds → More → PIA, sign in, pick a server, and add the outbound.
You can add several servers (one outbound per hostname). The tag is
pia-<region>-<server> (for example pia-us-east-useast1). Adding or using
Reset on a row registers a WireGuard key with PIA /addKey for that server.
The same hostname cannot be added twice. Logout clears the stored token only;
delete unused PIA outbounds from the Outbounds list. Reset and delete do not
revoke the WireGuard peer on the PIA account.
The password is not stored. The PIA API token is stored with the same
NODE_TOKEN_ENCRYPTION setting as node API tokens. If you retire an old
XUI_NODE_TOKEN_KEY without signing into PIA again, Add/Reset fail until you
re-login. Peer allowedIPs is IPv4-only (0.0.0.0/0).
Outbound subscriptions (server pools)
An outbound subscription imports a remote share-link subscription and injects its servers as outbounds into the running Xray config — without touching your saved template. This is the recommended way to subscribe to a pool of servers.
| Field | Default | Meaning |
|---|---|---|
url | — | The remote subscription URL (SSRF-guarded). |
tagPrefix | auto | Prefix for generated outbound tags (e.g. hk-); blank = subN-. |
updateInterval | 600 | Refresh interval in seconds. |
prepend | false | Place these outbounds before your manual ones. |
priority | 0 | Merge order (lower first). |
Imported outbounds get stable tags: the same server keeps the same tag across
refreshes, so exact-tag routing/balancer selectors stay pinned — while
prefix/wildcard selectors (e.g. hk-*) automatically pick up new servers as the
pool changes. Supported link schemes: vmess, vless, trojan, ss,
hysteria2 (hy2), and wireguard (wg). The panel refreshes enabled
subscriptions on a timer and reloads Xray when something changes.
Routing rules
Routing rules decide which outbound (or balancer) each connection uses. Each
rule is a field-type matcher: set any of domain, ip, port, network,
protocol, inboundTag, sourceIP, … and point it at an outboundTag or a
balancerTag. Rules are evaluated top-to-bottom — the first match wins, so
put specific rules above general ones.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{ "type": "field", "domain": ["geosite:category-ads-all"], "outboundTag": "block" },
{ "type": "field", "ip": ["geoip:private"], "outboundTag": "direct" }
]
}
}Balancers
A balancer groups outbounds by a selector (tag prefixes, including the wildcard pools from outbound subscriptions) and spreads or fails traffic over them with a strategy:
| Strategy | Picks… | Needs a monitor |
|---|---|---|
random | a random member per connection | no |
roundRobin | members in rotation | no |
leastPing | the lowest-latency member | observatory |
leastLoad | the most stable member by sampled load | burstObservatory |
Reference a balancer from a rule via balancerTag. leastPing and leastLoad
need a health monitor, which Xray places at the top level of the config
(observatory / burstObservatory, not inside routing). The panel can
report balancer status and override a balancer to a specific outbound for
testing.
Build the routing block — rules, balancers, and the matching observatory — here:
Balancer & routing builder
Compose Xray balancers and routing rules, then copy the routing block (with a matching observatory for leastPing/leastLoad).
Balancers
Rules
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
}
],
"balancers": [
{
"tag": "balancer",
"selector": [
"proxy"
],
"strategy": {
"type": "leastPing"
}
}
]
},
"observatory": {
"subjectSelector": [
"proxy"
],
"probeURL": "https://www.google.com/generate_204",
"probeInterval": "1m",
"enableConcurrency": true
}
}Outbounds that reach external services are fetched with SSRF protection — by default private/internal addresses are blocked unless you explicitly allow them per source.

3x-ui