3x-ui3x-ui

Outbounds & Routing

Shape egress in 3x-ui — WARP and NordVPN outbounds, outbound subscriptions (server pools), routing rules, and load balancers.

Inbounds accept clients; outbounds decide where their traffic goes next. 3x-ui can route traffic through Cloudflare WARP, NordVPN, 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.

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