Skip to content

V2Ray Custom Routing Rules: Domain, IP, Geosite Matching & Priority

Learn domain, full, regexp, geosite, and geoip matching, rule evaluation order, and practical JSON examples you can adapt.

At a glance

For users who have imported a subscription and want to customize routing in v2rayN. Learn how domain and IP matching differ, then order rules from specific exceptions to category matches and a final catch-all. The examples use V2Ray/Xray field-based routing and adaptable JSON snippets—not a complete client configuration. Before applying them, check your core version, outbound tags, and rule databases.

1. How a Routing Rule Works

Routing rules are not a list of subscription nodes. A subscription provides server connection details; routing determines which outbound handles each connection. Switching between VMess and VLESS nodes won’t fix an incorrect domain condition. The examples use the outbound tags direct, proxy, and block for direct, proxy, and blocked traffic. These tags must already exist in your configuration.

A connection enters the core Destination details are extracted Rules are checked in order An outbound tag is selected The outbound handles the connection

A basic rule only needs to specify what to match and where to send it. This object sends example.com and its subdomains through the proxy outbound. It is one entry in the routing.rules array, not a complete configuration. Every example.com domain in this article is illustrative; replace it with the domain you actually want to match.

{
  "type": "field",
  "domain": ["domain:example.com"],
  "outboundTag": "proxy"
}

For example, putting domain and port: "443" in the same object means both the domain and destination port 443 must match. It does not mean either condition is enough. To match a domain OR an IP, use two separate rules rather than putting both fields in one rule.

2. Choosing Between domain, full, and regexp

domain is both a JSON field name and a matching prefix used within that field. Don’t confuse the two. Plain strings in the field use substring matching by default, which can match more than intended. To match a specific site and its subdomains, use domain:.

SyntaxWhat it matchesNotes
full:api.example.comThis exact domain onlyDoes not include subdomains
domain:example.comThe root domain and its subdomainsDoes not match notexample.com
example.comDomains containing this stringMay match more than intended
regexp:...Domains matched by a regular expressionMind the anchors and JSON escaping
geosite:cnThe cn category in the domain databaseDepends on the loaded database

Domain rules do not use URL path semantics. To match https://api.example.com/v1/items, use full:api.example.com; don’t include the scheme, slashes, or path. Standard routing rules also can’t distinguish between two paths on the same HTTPS site.

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

These three conditions are joined by OR: a match on any one sends the connection through the proxy. The regular expression matches numbered domains such as edge1.example.net and edge23.example.net. In JSON, \\. is parsed into \. for the regular expression. Missing an escape level can cause a parse error or change the pattern’s meaning.

3. Where ip, geoip, and geosite Differ

geosite categorizes domains; geoip categorizes IP addresses. They use different data and are not interchangeable. geosite:cn does not mean every domain that resolves to an IP in mainland China, and geoip:cn does not guarantee that a server hosts a website based in mainland China. CDNs, shared IPs, and database updates can all affect results.

Domain category rules

Field
domain
Example
geosite:cn
Data source
The loaded geosite domain database
What it matches
The destination domain available to the connection

First check that the category exists, then check whether it includes the domain. Categories are not detected automatically in real time.

IP category rules

Field
ip
Example
geoip:cn
Data source
The loaded geoip address database
What it matches
The destination IP or an address resolved during routing

Whether a domain connection is resolved depends on settings such as domainStrategy.

For known local network ranges, use CIDR directly rather than relying on a site category to allow access to local devices. The example below sends the three common IPv4 private ranges directly. It does not cover every special-use address or IPv6 local addresses. For broader coverage, use geoip:private from the database and verify which ranges it includes.

{
  "type": "field",
  "ip": [
    "10.0.0.0/8",
    "172.16.0.0/12",
    "192.168.0.0/16"
  ],
  "outboundTag": "direct"
}
/32
CIDR prefix for a single IPv4 address
/128
CIDR prefix for a single IPv6 address
443
Common destination port for HTTPS

These are basic address and protocol values, not speed-test results. A port condition applies to the connection’s destination port, for example "port": "443"—not v2rayN’s local listening port. Routing all traffic on port 443 the same way can affect many unrelated sites, so it’s usually best paired with a domain condition.

4. Priority: The First Match Wins

Rules are checked from top to bottom in array order. As soon as one matches, its outbound is selected and no later rule is checked for a “better” match. An exact domain does not automatically override an earlier category rule, and a longer CIDR range does not take precedence over a shorter one above it. Put specific exceptions before broader rules.

  1. Start with specific exceptions: For example, block one domain or force a particular service domain through the proxy.
  2. Then allow local access: Send private addresses direct to avoid disrupting access to devices on your local network.
  3. Next, route by category: Handle most connections using categories such as geosite and geoip.
  4. Finish with a catch-all: Explicitly decide where remaining TCP and UDP connections go.

The following is a complete routing snippet, but it still needs to be merged with your existing inbounds, outbounds, and other settings. It blocks an example telemetry domain first, sends local network and cn-category traffic direct, then routes everything else through the proxy. If you remove rules, make sure the JSON commas remain valid.

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

If no rule matches, the core usually uses the first outbound in the list—not an outbound named proxy. An explicit catch-all makes the setup easier to read but changes matching behavior. If you remove it, still check outbound order. Automatic failover after a proxy connection fails requires a separate strategy; standard routing rules won’t retry using the next rule.

5. How domainStrategy Controls Resolution

Domain rules match domains; IP rules match addresses. If an app sends a domain through the proxy protocol, the core may not yet have the destination IP. routing.domainStrategy controls whether the routing stage resolves domains for matching. It is not the same as choosing a DNS server, and it should not be confused with an outbound option of the same name.

StrategyWhen resolution happensWhat to watch for
AsIsThe routing stage does not resolve domains for matchingA domain-only destination cannot match an IP rule using a resolved address
IPIfNonMatchResolve and retry matching only after a domain fails to match any ruleAn earlier catch-all prevents this additional lookup
IPOnDemandTry resolving when a rule requires an IP during matchingEarlier IP rules may trigger extra DNS lookups and route traffic sooner

If a service domain must use the proxy, place its full: or domain: rule before geoip:cn. With IPOnDemand, an earlier IP category rule may resolve the domain to a cn address and send it direct before the domain exception gets a chance to run.

6. Apply and Test Rules in v2rayN

v2rayN is a desktop client; the selected core executes the routing rules. This article covers the V2Ray/Xray JSON structure. Before editing, note your v2rayN version and active core. Editor locations and field names can vary between versions, so don’t paste a core JSON object into a field that accepts only a domain list.

  1. Back up your current setup. Keep a copy of the routing configuration and default outbound settings in use. A common location in the desktop client is Settings → Routing Settings. If your version uses a different menu, look for routing configuration management. Don’t change the subscription URL to troubleshoot routing.
  2. Check the tags. In the configuration editor or generated core config, check the tag values under outbounds. Map direct, proxy, and block in the examples to the tags actually in your config.
  3. Add just one exception. Test with a single full domain and put it before the category rules. Save, select this routing profile, then have the client regenerate the configuration and restart the core.
  4. Check the startup log. Look for errors such as invalid JSON, missing categories, or outbound tags that can’t be found before testing a connection.
  5. Test a new connection. Close existing page connections and make a fresh request. Check the destination and outbound tag in the access log; if those details aren’t shown, temporarily increase the log verbosity.
  6. Expand gradually. Once the test succeeds, add geosite, geoip, and catch-all rules. Keep a reversible configuration at each step.

Test at least three real destinations: a site that should go direct, a site that should use the proxy, and a local network device. If you need blocking, add a test domain you control. Rules only affect connections that enter this core; if an app bypasses the system proxy, there won’t be a matching entry even when the rule is correct. Check which traffic is handled by the system proxy in the system proxy guide.

7. Four Common Routing Issues

Why does a full rule still send traffic direct?

Check whether an earlier rule—such as geosite:cn, geoip:cn, or a catch-all—already matches. Move the exact-domain exception above it, save, and create a new connection. Also confirm that the connection provides a domain rather than an IP resolved by the app in advance.

Why does the core fail to start after adding geosite?

Check the logs for a missing category or a data file that failed to load. Confirm that the loaded database contains the category and update it using the rule data update option provided by the client. Don’t rely on a category name just because it looks plausible. Remove the new entry to restore startup, then verify each addition one at a time.

Why doesn’t a rule match when it has both a domain and an IP?

Different fields are joined by AND, and matching may also depend on domain resolution. If you want either condition to match, split them into two rules with the same outboundTag. If both must match, check that the address is valid and review how domainStrategy behaves.

Why is the browser still using the old route after I changed a rule?

Routing is generally decided when a new connection is established. Existing long-lived connections may keep their current outbound. First confirm that the edited routing profile is selected, then close the relevant app connections. If needed, restart the core and try again. If no request appears in the logs, check whether the app is reaching the proxy entry point.

Keep the configuration small and understandable: specific exceptions first, then local addresses and categories, with an explicit catch-all at the end. When something goes wrong, check in this order: did the connection enter the core, is the destination a domain or an IP, which rule matched first, and does the outbound tag exist? This is more effective than piling on more rules.

Download the client