At a Glance

For users who can already connect to a node and want to customize traffic routing. Starting with the difference between domain and IP fields, this guide walks through rule order, outbound tags, and DNS resolution strategies using five example rules, then shows how to reorder and test them in v2rayN. The focus is on finding out which rule a connection matches—not guessing whether a setting works based on whether a webpage loads.

Routing rules only apply after a connection reaches the core

System proxy settings, TUN capture, and Xray routing operate at different stages. The system proxy determines whether apps that support it send connections to the local inbound. Routing rules then handle connections that have reached the core and choose whether to send them direct, through a proxy, or block them. If a browser bypasses the system proxy, even perfectly configured routing rules won't affect its connections.

App connection Inbound reception Target identification Rule matching Outbound forwarding

This guide uses Xray's native JSON fields. v2rayN and v2rayNG convert their settings into core configuration; v2flyNG uses the V2Fly core, so don't assume every Xray field can be copied over as-is. Before editing, check which core you're using and back up your current routing profile.

domain, full and regexp: narrow down what matches

Overly broad matching is a common cause of misrouted traffic. A bare string is treated as a substring match by Xray. To match a domain and all its subdomains, use domain: explicitly. Enter a hostname in the rule—not a full URL with a scheme, path, or query string.

SyntaxWhat it matchesBoundary example
example.comSubstring in a domain nameMay also match notexample.com
domain:example.comThe domain and all its subdomainsMatches example.com and img.example.com, but not notexample.com
full:example.comExact match for the full domainDoesn't include www.example.com
regexp:^img[0-9]+\.example\.com$Regular expression matchMatches img12.example.com, but not img.example.com
geosite:cnReferences the cn collection in the domain data fileResults depend on the current data file; this doesn't mean all servers in mainland China

Regular expressions also require JSON escaping. The raw expression in the routing editor can contain \.; in a JSON string, each backslash must be written as \\. The example below is a valid JSON rule object, not a complete configuration that can start the core on its own.

{
  "type": "field",
  "domain": [
    "full:example.com",
    "domain:example.net",
    "regexp:^img[0-9]+\\.example\\.com$"
  ],
  "outboundTag": "direct"
}

ip, geoip and geosite: different data sources

geosite matches domain collections; geoip matches IP address collections. A site may use multiple content delivery addresses, so its domain category and the geographic location of its actual connection address may differ. To always route a specific site through a proxy, add a domain exception rather than relying only on the IP's location.

{
  "type": "field",
  "ip": [
    "192.168.0.0/16",
    "10.0.0.0/8",
    "geoip:private",
    "geoip:cn"
  ],
  "outboundTag": "direct"
}

The first two entries above show CIDR notation and overlap partly with geoip:private; you can remove the duplicates in practice. IPv4 private ranges alone don't cover local IPv6 addresses, so check whether the private address collection you're using covers both in a dual-stack network.

Rule priority: top to bottom, first match wins

For each routing decision, Xray checks the rules array in order and uses the first rule that meets all its conditions. A more specific domain in a later rule won't make Xray choose that rule automatically. Put exact exceptions before broader categories, and leave catch-all rules until the end.

Arrays within the same field generally work as “OR”: a domain array matches if any expression matches. Different filter fields within one rule generally work as “AND”: setting domain, port, and network requires all those conditions to be met. Putting domain and IP conditions in the same rule does not mean “match either one to go direct.”

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "domain": ["geosite:category-ads-all"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "domain": ["full:example.com"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "geoip:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}

This routing snippet illustrates rule order. It assumes the configuration already has three outbounds—direct, proxy, and block—and that the data file includes the example collections. These tag names aren't reserved action names: a typical direct outbound uses freedom, a blocking outbound uses blackhole, and a proxy outbound references the protocol of the actual node.

5 rules
Example rules are evaluated in array order
3 outbounds
Must reference an existing outbound tag
443
Can test an HTTPS port condition

First decide whether the exception should override the block

If a domain must go direct even though it's included in an ad-blocking collection, move its exact-match direct rule above the ad-blocking rule. Putting it only above the cn collection isn't enough.

domainStrategy: when domains are checked against IP rules

Whether an IP rule can match a domain target depends on the routing domainStrategy. This field controls whether the domain is resolved for routing matches; it is not the client's overall DNS setting, nor does it determine how the direct outbound ultimately resolves the target address.

AsIs: keep the original target type

Field
routing.domainStrategy
Value
AsIs
Domain target
Don't actively resolve to an IP for routing matches
IP target
Can match IP rules directly

Useful for testing domain rules first, without mixing DNS resolution results into initial troubleshooting.

IPIfNonMatch: resolve only if nothing matches

Field
routing.domainStrategy
Value
IPIfNonMatch
Trigger
No rule matches the domain target in the first pass
What happens next
Resolve the domain, then try matching again, including IP rules

A catch-all rule at the end already matches in the first pass, so it won't trigger a second IP-based check.

So although the five rules in the previous section specify IPIfNonMatch, a domain target that reaches the final TCP/UDP catch-all has already matched in the first pass. Xray won't resolve it to check the earlier geoip:cn rule. A target that is already an IP can still match the fourth rule. This is a common reason a domain continues to use the proxy despite having a geoip rule.

Also, if the inbound receives only the target IP, domain rules can't recover the original hostname on their own. Sniffing may supply domain information for recognizable traffic, but it isn't a universal way to recover domains for every protocol. When troubleshooting, check the inbound target, sniffing settings, and final outbound together.

Reorder rules and verify matches in v2rayN

In v2rayN, open “Settings” → “Routing Settings,” select the routing profile you want to use, and open the rule editor. The edit and move up/down controls may appear in different places across versions. Check the order of the generated routing.rules, not the profile name or rule notes.

  1. Copy the profile: Keep the original as a fallback, then add a full: rule for a test domain to the copy. Don't change DNS, sniffing, or the core at the same time.
  2. Enter fields separately: Put full:example.com in the domain condition and geoip:cn in the IP condition. If the editor accepts one entry per line, enter one match per line; don't paste a whole JSON object.
  3. Check the outbound: Select the required outbound in the outbound options. For a native configuration, make sure outboundTag exactly matches the outbound tag, including capitalization.
  4. Reorder the rules: Move the test rule above any rules that could match first. After saving, confirm that this routing profile is selected, then reload or restart the core as prompted.
  5. Start a new connection: Close existing webpage connections and visit the site again. Existing long-lived connections usually won't switch outbounds automatically after a rule change; close and reopen the browser if needed.
  6. Check the logs: Make sure the core starts successfully, then check the test target's access log and outbound tag. If needed, temporarily increase log verbosity in the logging settings, then restore it after testing to avoid recording large volumes of connection data.

To test “HTTPS only goes direct,” set a domain condition, port: "443", and network: "tcp" in the same test rule. HTTP/3 uses UDP, so it won't meet the TCP condition. A browser opening the same site doesn't prove the rule is failing. The protocol and port must match your test conditions.

Why is www still proxied when I used full?

full:example.com doesn't include www.example.com. First, confirm the actual target in the logs. To include subdomains, use domain:example.com; if you only need these two hosts, add a full match for each.

Why doesn't the rule work at the end of the list?

Check for an earlier network: "tcp,udp" rule, a collection that includes the domain, or a broader domain match. Move the test rule above them, reload the configuration, and start a new connection.

Did a geo data update cause the core to fail to start?

Check the file and collection names mentioned in the startup log. Make sure the data file is readable and the collection exists. Remove the failing collection reference first to confirm the core starts, then fix the data source. Don't keep switching nodes to mask a configuration error.

Does a webpage loading prove that direct was used?

No. A page can load successfully over either a direct or proxied connection. Check the target and outbound tag in the core's access log. If the current log doesn't show the rule number, compare the outbound before and after the change, changing only one rule at a time.