V2Ray Routing Rules: Split Traffic with geosite and geoip

Learn how to route traffic directly in mainland China and through a proxy elsewhere, with geosite and geoip rules, domainStrategy choices, and rule-ordering pitfalls.

At a glance

This guide is for Mac users who can already connect to a server with v2rayN and want to adjust routing. First, understand the difference between domain lists and IP databases. Then set up rules to send private addresses and mainland China domains and IPs directly, while routing everything else through a proxy. The examples show a readable routing snippet and explain how the default outbound, DNS, and rule order affect the result.

geosite vs. geoip: Different Match Targets

Routing does not determine where traffic goes based on a webpage's language or your device's location. When V2Ray core receives a request, it reads available information such as the destination domain, destination IP, and port, then checks for a match in routing.rules from top to bottom. When a rule matches, traffic is sent to the outboundTag specified by that rule. The tag must correspond to a tag that actually exists in outbounds.

SyntaxMatchesKey limitation
geosite:cnDomain category listDepends on the geosite data file in use; it does not include every website in mainland China
geoip:cnIP ranges classified as China in the databaseDoes not indicate where a website's company is based or what language its content uses
geoip:privatePrivate and special-use address rangesCheck the data file in use for the exact ranges
domain:example.comA specified domain and its subdomainsDoes not cover other domains with similar names
full:example.comExact domainDoes not include subdomains

geosite:cn is a category entry, not a guess based on a domain suffix. A .com domain may be on the list, while a site using an overseas CDN may have a domain category that differs from its IP's location. When domain information is available, routing by domain is usually easier to maintain than routing only by the resolved address.

v2rayN Routing Setup: Back Up Before Editing

v2rayN manages configuration and connections; the selected core actually applies the rules. Configurations in the Project V, V2Fly, and Xray ecosystems share some fields, but also have core-specific extensions. This guide uses only common field rules and does not transplant extensions from one core to another.

  1. Note your current configuration

    On the main screen, note the current server, routing mode, and system proxy status. Open Settings → Parameter Settings and note the core in use and local listening ports. The interface may vary between versions, so follow what you see. Do not switch to a core that does not support your current server's protocol just to use this example.

  2. Back up your routing rules

    Go to Settings → Routing Settings and back up the existing rules before creating or editing a routing profile for testing. Make sure this profile is selected on the main screen, rather than Global Proxy or Global Direct mode.

  3. Check the outbound tags

    Check the configuration actually loaded by the core and verify the tag values for the proxy and direct outbounds. This guide uses proxy and direct as example tags. If your tags differ, update the rules' outboundTag values to match.

  4. Apply the rules and check the logs

    Save the rules and have the client reload the core configuration, then check the startup results in the logs. If you see an unknown outbound, a data file loading failure, or a JSON parsing error, restore your backup before making further changes.

The client usually regenerates its runtime configuration. Direct edits to the temporary config.json may be overwritten when you switch servers or restart. For everyday use, save rules through Routing Settings. If you manage the configuration manually, maintain the snippet below in your own configuration source.

Routing Example: Direct in Mainland China, Proxy Everywhere Else

This is a standalone routing snippet, not a complete client configuration. Before using it, make sure you have a working proxy outbound and a direct outbound with protocol set to freedom; their tags should be proxy and direct, respectively. Also confirm that the core can read geosite and geoip data files containing the relevant categories.

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "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"
      }
    ]
  }
}

When no rule matches, the core typically uses the first outbound in outbounds. So you can send everything else through a proxy either with an explicit rule or by making the proxy the default outbound. These approaches affect IPIfNonMatch differently, so do not copy the rules without checking the outbound order.

domainStrategy: When to Resolve Domains for Routing

routing.domainStrategy determines whether routing tries to resolve a domain to an IP address for matching. It is not a system DNS setting, nor is it the same as the domain handling strategy on a direct outbound. Changing this field does not automatically take over DNS requests, encrypt them, or select an upstream resolver.

IPIfNonMatch

Recommended

Try matching with the information already available. If a domain does not match any rule, try resolving it and match again using the result. This is a good starting point, but check whether a catch-all rule already covers every request. If you need resolution as a fallback, using the proxy as the first outbound makes the default behavior clearer.

Best for: Configurations that prioritize domain rules and explicitly manage the default outbound

AsIs

The routing stage does not actively resolve domains for matching. Domain requests rely mainly on domain rules, while requests that already use an IP address can still match IP rules. This does not guarantee that no DNS queries occur anywhere in the connection process.

Best for: Configurations with a comprehensive domain list that aim to minimize routing-time DNS lookups

IPOnDemand

Try resolving domain requests when a matching rule requires IP information. If geoip:private is the first rule, resolution may happen early, making routing more directly dependent on DNS availability and the addresses returned.

Best for: Configurations that need to make decisions based on resolved IPs and have a verified DNS path

Bottom line: Set the fallback before choosing a resolution strategy

To check IPs when a domain is not in your domain list, make the proxy the first outbound, remove the final catch-all, and test with IPIfNonMatch. If you keep an explicit fallback, be clear that unknown domains will go straight to the proxy, or test the resolution results with IPOnDemand separately.

A domain can resolve to multiple IPv4 and IPv6 addresses, and changes to the DNS upstream can also change its CDN endpoint. A match for geoip:cn once does not guarantee that future connections will match. For a stable egress route, add a dedicated rule for the specific domain instead of permanently pinning a CDN IP that happened to appear.

Rule Order: First Match Wins

Rules are checked from top to bottom, and the matching rule determines the outbound. The core does not compare rules to see which is more specific. Put specific exceptions before broad categories and any catch-all rule last. This is the basic order for maintainable rules.

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

For example, if a domain is classified for direct routing by the domain database but your use case requires it to go through a proxy, put a dedicated rule for it above geosite:cn. example.com is a sample domain for demonstrating the syntax; replace it with your actual destination. To match only the exact domain and not its subdomains, use full:.

Test and Troubleshoot: Check the Destination, Rule, and Outbound

A webpage loading only proves that this request completed; it does not prove that it used the intended egress. First confirm that the core started successfully, then make a consistent test request and check the destination and outbound tag in the access logs. Log formats vary between cores, and some show the inbound-to-outbound mapping. If the log level is too low, temporarily increase it for testing, then restore it afterward.

curl --proxy http://127.0.0.1:10809 --connect-timeout 10 --max-time 20 -I https://www.baidu.com/
curl --proxy http://127.0.0.1:10809 --connect-timeout 10 --max-time 20 -I https://example.com/

10809 is an example HTTP proxy port, not a claim about the current v2rayN default. Replace it with the active HTTP or mixed listening port shown under Settings → Parameter Settings. The commands explicitly specify a local proxy to rule out whether the terminal follows system proxy settings. These requests mainly test the TCP path, not browser behavior over UDP.

Why Is a Mainland China Website Still Going Through the Proxy?

First, check the logs to see whether the destination is a domain or an IP, then check whether that domain appears in the current geosite data. If you use IPIfNonMatch and have a catch-all proxy rule at the end, the domain will not be resolved for another match. Try adding an exact-domain direct rule first; do not immediately switch to direct routing for an entire IP range.

Why Do Some Sites Stop Working After Adding geoip:cn?

Check the DNS response and the actual outbound shown in the logs. If the destination IP is classified as being in mainland China but the service cannot be reached directly on your current network, add a proxy exception for its domain and place it before the mainland China direct rules. Change one rule at a time, and keep a record of the failed destination for comparison.

What if the geosite category cannot be found?

Check the category name in the rule, the data file path actually loaded by the core, and the startup logs. Different data releases may not contain the same categories, and updating a subscription does not necessarily update the rule database. Use the data update option provided by your client, then restart the core. If the category is still unavailable, restore a category you have confirmed exists.

Rules had no effect. Do I need to reinstall?

First, make sure the new routing profile is selected, reload the core, and close any existing connections in the test app before making a new request. Existing long-lived connections will not switch outbounds automatically when rules change. Also confirm that you edited the configuration source, not a runtime file the client may overwrite.

Keep three records: the core in use, the routing rules, and the outbound tag for each test request. Before sharing logs publicly, remove subscription URLs, server credentials, and private browsing records. The goal of validating routing is to confirm that specific requests consistently use the intended outbound—not to judge every rule by a single speed test.

Download v2rayNChoose a client for your platform