V2Ray Routing Rules: Split Traffic with geosite and geoip

Learn how domain, IP, geosite, and geoip rules are evaluated, configure common direct connections in mainland China and proxy routing elsewhere, and troubleshoot rule conflicts.

At a glance

This guide is for users who can already connect through a proxy node and want to fine-tune traffic routing. First, distinguish domain rules from IP rules. Then use a routing configuration to establish a baseline: explicit exceptions first, direct connections in mainland China, and proxy routing for everything else. Finally, use DNS, the client-generated configuration, and connection logs to investigate misrouted traffic. The examples use common V2Fly and Xray JSON routing structures; they are not complete client configurations you can drop in as-is.

1. Check that traffic reaches the core

Routing rules only apply to connections that reach the core. v2rayN is a desktop client; v2rayNG is an Android client that uses the Xray core, while v2flyNG uses the V2Fly core. The graphical interface manages the configuration, but the active core performs the actual matching. VMess and VLESS are proxy protocols; switching protocols will not fix incorrectly ordered rules.

App request Inbound receives connection Target identified Routing rules evaluated Outbound connection

System proxy settings usually affect only apps that respect them. If an app connects directly, the corresponding connection will not appear in the core's logs. Android VPN mode may also be configured to bypass selected apps. Before adding geosite categories, make sure the target app's connection is reaching the intended inbound.

10808
SOCKS port used in this example
53
Common port for traditional DNS
443
Common destination port for HTTPS

Port 10808 is used for this example only; it is not the default for every version. Check the active inbound configuration in your client for the listening address, port, and whether SOCKS is enabled. The port is the local entry point, while 443 is usually used by the remote website—don't confuse the two. DNS can also use encrypted transport, so not every DNS request uses UDP port 53.

2. What domain, IP, and data-set rules match

domain and ip are routing rule fields. geosite: and geoip: reference data sets used by those fields. The former does not look up a domain's country in real time, and the latter does not determine where a website's business is based. Matching uses data files bundled with or installed for the client or core, so results depend on the data source and its update date.

Rule syntaxWhat it matchesLimitations
full:example.comExact domainMatches only that domain, not its subdomains
domain:example.comDomain and subdomainsIncludes example.com and www.example.com
geosite:cnDomain categories in the data setMay not include every domain serving users in mainland China
192.168.0.0/16IPv4 address rangeRequires a destination IP to match
geoip:cnAddress ranges in the data setCannot establish the visitor's physical location

When you need a precise domain boundary, use full: or domain:. A plain string without a prefix is usually matched as a substring, which can also catch unrelated domains with similar names. Category names must exist in the data files actually installed; copying a category name from elsewhere does not guarantee that your local data files include it.

Rule of thumb: use domains for service exceptions and IPs for address ranges

To pin a specific site to an outbound, start with an explicit domain rule. For local networks, use address-range rules. Don't use a single CDN-resolved IP as a substitute for an entire service domain.

3. Rules are evaluated in order, not by specificity

Common field-based rules are checked from top to bottom, and the first matching rule determines the outbound. The core won't automatically let a more specific rule below override a broader one above. Put manual exceptions before category rules, and category rules before the fallback behavior.

  1. Put explicit exceptions first: For example, a test domain that must use the proxy, even if it also belongs to a direct-connection category.
  2. Next, add local and category rules: For example, private addresses, domains in mainland China, and address ranges in mainland China.
  3. Set the default outbound last: When no rule matches, use the fallback path defined by your configuration.

Within a rule, multiple entries in the domain array mean “match any.” But different condition fields in the same rule usually must all match. For example, combining domain and port means the specified domain and port must both match—not either one. If domain and address categories are separate reasons to connect directly, use two rules.

4. A routing snippet for direct connections in mainland China and proxy routing elsewhere

The snippet below shows only the routing object. It assumes your existing configuration has a direct outbound tagged direct and a proxy outbound tagged proxy, with proxy as the first entry in the outbounds array to serve as the default for unmatched traffic. Tags are references: a UI label that says “direct” does not guarantee the internal tag is actually named direct.

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

example.com is a reserved example domain used to demonstrate exception priority, not a recommended service to route. The configuration sends the specified domain through the proxy, connects directly to recognized private destination addresses, connects directly when a domain or address matches a mainland China category, and sends remaining requests through the first proxy outbound. This is one routing policy, not a universal answer for every network.

5. How domainStrategy interacts with DNS

AsIs does not resolve domains for routing. If the inbound supplies a domain, IP rules generally cannot match it on their own. IPIfNonMatch tries to resolve the domain after it fails to match a rule, then uses the resulting IP for matching. IPOnDemand may trigger a lookup as soon as rule evaluation encounters a condition that requires an IP. The timing differs, which can affect whether earlier IP rules get a chance to match.

StrategyWhen routing resolves the domainWhat to watch for
AsIsNo extra resolution for routingRelies mainly on domain rules or an existing destination IP
IPIfNonMatchAttempts resolution after no domain rule matchesA broad domain rule earlier in the list may prevent IP rules from being evaluated
IPOnDemandWhen a condition requires an IPConsider the effect of earlier IP rules and the resolved address

In the snippet above, only requests that fail to match a domain rule can use the resolved IP to match geoip:cn. If you add a catch-all domain proxy rule at the end of the rules list, it will match during domain evaluation, so IPIfNonMatch won't fall back to IP matching because the request has already matched. To preserve that fallback path, use the default outbound instead of adding a catch-all rule.

The routing resolution strategy and the way the final outbound resolves a destination are separate settings. Even with AsIs for routing, a direct outbound may still need to resolve the domain. DNS responses can point to CDN addresses in different regions or return IPv4 only or both IPv4 and IPv6, changing the address category match. Record the domain, resolved address, and outbound tag separately instead of checking only whether the page loads.

Try this: preserve the domain, then verify IP fallback

First, use an explicit domain rule to confirm the correct outbound tag. Then remove the temporary rule and test IP fallback. Change only one condition at a time to distinguish missing domain categories, DNS changes, and rule-order issues.

6. Troubleshoot rule conflicts with a consistent test

In v2rayN, open Settings → Routing settings and check which rule set is active. The menu names may vary between versions, so follow the current interface. In v2rayNG and v2flyNG, check each client's own routing settings and active configuration; don't assume another client's option names apply. When copying configurations between cores, also check that the fields and data-file formats are compatible.

  1. Record the baseline: Note the active core, routing mode, rule order, and local listening port. First confirm that the proxy node itself can connect.
  2. Check the inbound: On desktop, run the command below to send traffic explicitly through the local SOCKS endpoint and let the proxy resolve the domain. Replace the port with the one in your configuration.
  3. Check the outbound: Find the test domain, destination IP, and outbound tag in the client's connection or access logs. Log formats vary by core version.
  4. Isolate the rules: Temporarily put a full-match rule for the test domain first, directing it to direct and then to proxy. If the outbound changes accordingly, the routing path and tags are probably working.
  5. Restore the categories: Remove the temporary rule. Test one domain serving mainland China, one other domain, and one local address to confirm category matching and fallback behavior.
curl --socks5-hostname 127.0.0.1:10808 --connect-timeout 10 --max-time 20 -I https://example.com/

The 10-second value here is the connection timeout; 20 seconds is the overall command timeout, not a performance test result. --socks5-hostname takes a different path from resolving the domain locally and submitting an IP, so it's useful for testing domain rules. A successful HTTP request confirms only that this path works; it doesn't prove that UDP, every app, or TUN routing is configured correctly.

7. Common questions about geosite and geoip routing

Why does a website in mainland China still use the proxy after I add geosite:cn?

Check the domain used by the actual connection first; a webpage may load resources from other domains. Then confirm the data set includes that domain and the active mode uses this rule set. Temporarily add a full-match rule for the domain at the top to test it. If it should always connect directly, replace that with a domain rule scoped appropriately.

Why does geoip:cn never match?

Check whether the inbound provides a domain or an IP. With AsIs, an IP condition has nothing to match if the inbound provides only a domain. With IPIfNonMatch, check whether an earlier domain or catch-all rule ends evaluation first. Then verify that the resolved address belongs to the relevant address set.

Will custom routing change when I update my subscription?

Subscriptions usually update the node list, while routing rules and geographic data are often managed elsewhere. The exact behavior depends on the client and subscription format. After an update, check the active node, routing rules, and generated configuration. If you need to keep manual rules, export a backup first; don't rely on saving only the subscription URL.

Does enabling sniffing route every IP connection by domain?

Don't assume it will. Sniffing can extract a domain only from supported traffic with recognizable information, and results depend on the protocol and core configuration. Where possible, have the app connect through a proxy inbound that can pass the domain. If sniffing is necessary, check that your version supports the relevant destination override and route-only options.

Reliable traffic splitting isn't about having more rules; each rule needs a clearly defined scope and a result you can explain from the logs. Start with a small set of exceptions, categories, and a default outbound, then fix real misrouting one case at a time. This is easier to review than importing a large set of overlapping rules all at once. For more on how clients and cores work together, see the protocol reference and concept glossary.

Download a clientChoose v2rayN / v2rayNG for your platform