3x-ui3x-ui

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:

  • freedom sends traffic straight to its destination — the default egress. Optionally set a domainStrategy (e.g. UseIP) to control how hostnames resolve.
  • blackhole drops traffic. Route unwanted destinations (ads, torrents) here.
freedom + blackhole
{
  "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.

Outbound (Xray JSON)
{
  "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.

FieldDefaultMeaning
urlThe remote subscription URL (SSRF-guarded).
tagPrefixautoPrefix for generated outbound tags (e.g. hk-); blank = subN-.
updateInterval600Refresh interval in seconds.
prependfalsePlace these outbounds before your manual ones.
priority0Merge 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.

route ads to blackhole, private IPs direct
{
  "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:

StrategyPicks…Needs a monitor
randoma random member per connectionno
roundRobinmembers in rotationno
leastPingthe lowest-latency memberobservatory
leastLoadthe most stable member by sampled loadburstObservatory

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 block (Xray JSON)
{
  "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.

On this page