V2Ray Routing Rules

Learn how domain:, full:, regexp:, geosite: and geoip: prefixes work, how rules are evaluated from top to bottom, and how to avoid common syntax mistakes.

At a glance

For users who have imported a server and are ready to customize routing in v2rayN. First, learn the difference between domain and IP fields, then use inspectable JSON snippets to understand prefixes, rule order, and domain resolution strategies. Finally, follow the in-client checks to tell a rule mismatch apart from a bad outbound tag or DNS failure.

First, understand the fields, match values, and outbound tags

Common V2Ray and Xray routing settings are in the routing.rules array. Each entry defines which connections match and which outbound handles them. domain and ip are field names; domain:, full:, and geosite: are prefixes used in domain match values. Don't confuse these two parts of the syntax.

Request enters the core Target information is read Rules are checked in order Outbound tag is selected Connection to the target is established

This is a complete routing rule, not a full core configuration. It sends TCP connections to port 443 whose exact target domain is example.com to the outbound tagged proxy. The port is the target service port, not the client's local listening port.

{
  "type": "field",
  "domain": ["full:example.com"],
  "network": "tcp",
  "port": "443",
  "outboundTag": "proxy"
}

Domain prefixes: domain, full, regexp, and geosite

The same domain can match very different sets of hosts depending on the prefix. Use domain: to cover a base domain and all its subdomains; use full: to match one exact hostname. Both are easier to verify than broad keyword matches.

SyntaxMatchesNotes
domain:example.comexample.com and its subdomains, such as api.example.comDoes not match notexample.com
full:example.comOnly example.comDoes not include www.example.com
regexp:^api[0-9]+\.example\.com$For example, api1.example.com and api20.example.comUse regex anchors to match the full hostname
geosite:cnDomain entries in the cn category of the data fileThe category depends on the data file in use
example.comTargets whose domain contains this textA bare string does not match on a domain-suffix boundary

geosite: uses local domain-category data; it does not look up a site's location in real time. geosite:cn does not mean “every domain ending in .cn”: it may include domains with other suffixes and may not yet include new sites. Check the data file in use for available categories, attributes, and entries.

Regular expressions also have to be escaped in JSON. The regex shown in the table is a matching expression; in a JSON string, escape the backslash before a literal dot by writing it twice. If you're entering a rule in a regular text field in the client, follow that field's format instead of blindly adding another layer of escaping.

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

Takeaway: test an exact rule first, then broaden the match

When troubleshooting a single site, start with a full: rule. Once it matches, decide whether to switch to domain: or a category rule. Don't start with a broad regex that covers many targets.

IP rules: addresses, CIDR, and GeoIP

Put IP conditions in the ip array. Enter a single address directly, use CIDR notation for a subnet, and use geoip: for a region or special address set. The standard syntax does not add an ip: prefix to an address; using ip:192.168.1.1 as an array value may cause the configuration to fail to load.

Addresses and subnets

Configuration field
ip
Single address
192.168.1.1
IPv4 subnet
192.168.0.0/16
IPv6 subnet
fc00::/7

Useful for specific device addresses or internal subnets, without relying on domain categories.

IP data sets

Configuration field
ip
Region sets
geoip:cn
Private address sets
geoip:private
Data dependency
geoip.dat

Check the current data file to see whether a set exists and which addresses it covers.

If a request reaches the core with an IP destination, IP rules can match it directly. If the destination is still a domain, whether the resolved address can be used for matching depends on domainStrategy. Browser-side DNS resolution, apps connecting directly to IP addresses, and client sniffing that recovers the domain can all change what destination information the router sees.

Rule priority: first match wins, not the most specific

Routing rules are checked from top to bottom in array order. The first rule that matches determines the outbound. The core does not choose whichever matching rule “looks most specific.” To reliably handle an exception with an exact domain, place it before broader rules.

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

This is a routing snippet to merge into an existing configuration; it does not include inbound, outbound, or DNS settings. Assume all three tags are defined: ads.example.com matches the first rule and is blocked; www.example.com matches the second and uses the proxy; direct access to a private address can match the third; all other TCP and UDP connections fall through to the final rule.

  1. Put exact exceptions that must override other rules first, such as blocking a specific domain or routing a particular service through a proxy.
  2. Next, add domain and IP sets. If they might overlap, decide explicitly which one should take priority.
  3. Add broad catch-all rules last. If you move a rule matching network: tcp,udp to the top, later rules for ordinary TCP and UDP traffic will never get a chance to match.

If no rule matches, a standard V2Ray/Xray configuration uses the first outbound; it does not automatically infer “direct in mainland China, proxy elsewhere.” An explicit catch-all makes the configuration easier to read, but it can also affect matching after domain resolution, so don't change it without considering the domain strategy.

domainStrategy: when domains are resolved and IP rules are retried

routing.domainStrategy controls how routing handles domains during matching. It is not the client's entire DNS configuration, and it does not guarantee that an app passes a domain to the core. First check whether the inbound receives a domain or an IP, then choose a strategy.

StrategyBehavior during routingWhen to use it
AsIsDoes not resolve the target domain specifically for routing matchesWhen relying mainly on domain rules or minimizing DNS lookups during routing
IPIfNonMatchIf no domain rule matches, tries to resolve the domain and match against IP rulesWhen domain rules take priority and IP rules are a fallback
IPOnDemandTries to resolve the domain when a rule requires an IP checkWhen earlier IP rules need to participate in routing decisions

A key pitfall is combining IPIfNonMatch with an unconditional catch-all. If the first pass matches the final TCP/UDP catch-all, that counts as a match, so the core won't then resolve the domain and try to match geoip:cn. If you rely on this strategy for IP-based fallback routing, check for broad rules that stop matching early and confirm which outbound is used when nothing matches.

With IPOnDemand, rule order needs particular attention. An earlier IP rule may trigger resolution and match, preventing later domain exceptions from being considered. To ensure a domain always uses a proxy, put its exact rule before any IP rule that could catch it.

Takeaway: check catch-all placement whenever you change the domain strategy

After switching to IPIfNonMatch, don't just test whether one site loads. Also check whether the target was caught by a catch-all on the first pass and whether the outbound shown in the logs is the one you expect.

Edit and verify rules in v2rayN

The v2rayN routing editor may change between versions. A common path is Settings → Routing Settings. Before editing, confirm which rule set is open, then check that the routing set enabled in the main window is the same one. Changes to an inactive rule set won't affect routing for current connections.

  1. Save the current setup: Back up your active rules and note the core type, domain strategy, and final outbound. This article covers V2Ray/Xray configuration; don't copy these rules directly into a different configuration format used by another core.
  2. Add one rule you can verify: Enter full: followed by the actual target hostname in the domain field, choose the appropriate outbound, and move the rule above any broad rule that could match the target.
  3. Apply the change and reconnect: Save the rules and restart the core if needed. Close any existing connection from the test page before trying again; established long-lived connections won't switch outbounds automatically when rules change.
  4. Check the logs: Use the logging settings available in your version and temporarily raise the level to info or the level needed for troubleshooting. Look for the target domain, destination port, and outbound tag, then restore your usual log level when finished.
  5. Expand the rule gradually: After the exact-domain test passes, switch to domain: or add geosite:. Change one thing at a time to make regressions easier to diagnose.

Common rule mistakes and fixes

I added domain:example.com. Why is another site also using the proxy?

First check for other rules that match, such as bare strings, category rules, or a proxy catch-all. domain:example.com itself matches only that domain and its subdomains; it does not match notexample.com. Check the actual outbound in the logs, then narrow the rules one by one.

I added geosite:cn. Why does the core report a missing category at startup?

Check that geosite.dat is present for the current core and that it contains the cn category. Update the data through the option provided by your client and try again. Don't rename a data file for another rule format and use it as a replacement.

My regex causes an escape error in JSON. What should I change?

Check the backslashes: the regex \. for a literal dot must be written as \\. in a JSON string. Also check for straight double quotes and commas between array items. If the configuration loads but the rule doesn't match, check the anchors and the actual hostname.

I added an exact direct rule. Why is the connection still going through the proxy?

Move the rule above broad proxy rules, confirm you're editing the active rule set, and reconnect. If the logs show only the destination IP, check whether the app resolves domains itself and whether sniffing is enabled and applicable. An exact domain rule can't match if the core never receives the domain.

If domain and ip are in the same rule, does either one matching make the rule apply?

No. Different condition fields must all match. To route either a domain or a subnet directly, split them into two rules and assign the same direct outbound to both. This also makes it easier to test the domain and IP conditions separately.

Client downloads