V2Ray Custom Routing Rules: Domain, IP, geosite Syntax and Rule Priority

Learn domain prefixes (full, domain, keyword, regexp), IP and geoip syntax, geosite categories, rule order, and how domainStrategy affects routing.

At a glance

For users who have imported a subscription and want to customize routing in v2rayN. This guide explains how V2Ray/Xray routing handles domains, IPs, category data, and rule order. It also clarifies the difference between keyword matching and the nonexistent native keyword: prefix. By the end, you’ll be able to write a minimal rule set, spot exceptions masked by earlier rules, and verify outbound selection in connection logs.

1. Routing rules apply to connections, not subscription nodes

Importing a subscription provides server addresses, authentication, and transport settings. Routing determines which outbound handles each connection. VMess and VLESS are proxy protocols; routing.rules selects traffic. They serve different purposes. A successful subscription update does not mean custom routing is enabled in the active configuration.

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

Routing may see a domain name or only an IP address. If an application passes the domain through the proxy protocol, domain rules can match it directly. If the application resolves the name first and passes only an IP, domain rules may have nothing to match. Sniffing may recover domain information for supported traffic, but it cannot turn arbitrary encrypted traffic back into a website name.

2. Domain syntax: exact matches, subdomains, keywords, and regular expressions

domain is an array of strings. Entries in the same array are joined with “OR,” so any matching entry satisfies the field. Prefer precise patterns: use full: to match one host, domain: to include a root domain and its subdomains, and an unprefixed string only when you specifically need substring matching.

PatternWhat it matchesNotes
full:example.comOnly example.comDoes not include www.example.com
domain:example.comexample.com and its subdomainsDoes not match notexample.com
exampleThe substring example anywhere in a domainMay also match unrelated sites
regexp:^api[0-9]+\.example\.com$For example, api1.example.comBackslashes must be escaped in JSON
geosite:cnDomains in the cn category in the data fileDepends on the data file installed

keyword: is not a native prefix here

Some rule editors label their keyword option as keyword, but in the native V2Ray/Xray domain array, keyword matching uses a plain string. Don’t copy keyword:example as a universal pattern; it does not automatically mean “a domain containing example.” The editor’s type selector and the core’s JSON are separate layers, so check the rule that is actually generated.

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

This is a rule object, not a complete client configuration. The three entries match a login host, a documentation domain and its subdomains, and API hosts with numbered names. In the regular expression, \\. is the JSON string representation; the regex engine receives \. after decoding. If you enter a regex in a plain-text field in the client, follow that field’s format—don’t mechanically add another layer of backslashes.

Bottom line: use full: for domain exceptions

To route a specific login or payment host differently, put its exact domain before broader categories. Avoid using a short keyword to cover an entire site, since it may also redirect unrelated domains with similar names.

3. ip, geoip, and geosite: keep address ranges and domain sets separate

ip accepts IP addresses, CIDR ranges, and geoip: data references. domain accepts domain patterns and geosite: references. These represent different kinds of data: domain categories classify names, while IP categories classify address ranges. Neither tells you for certain what a website contains, who owns it, or where its servers are physically located.

Domain category rules

Field
domain
Reference
geosite:cn
Resource
geosite.dat
Requirement
The target domain must be available to routing

The category must exist in the current data file; don’t assume it is available based on its name.

IP category rules

Field
ip
Reference
geoip:private
Resource
geoip.dat
Requirement
The target must be an IP or have a resolved IP address

Category contents vary by data file. For testing a specific address, start with an explicit CIDR range.

The example uses two separate rules for direct connections to domain and private IP targets, meaning “direct if either set matches.” Putting domain and ip in the same rule would require both fields to match, not either one.

{
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "192.0.2.10/32"],
        "outboundTag": "direct"
      }
    ]
  }
}

4. Priority: top to bottom, stop at the first match

Routing does not automatically put “more specific” rules first. Each scan follows the order of the rules array, and the first match selects its outbound. Even if an exact domain is more specific than a geosite category, it won’t get a chance to run if it sits below a category rule that has already matched.

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

This snippet shows only the routing section and assumes the full configuration already has outbounds tagged proxy and direct. These are example tags, not names every client uses. In particular, writing direct as a tag does not create a direct outbound.

  1. Put specific exceptions first, such as a login host that must use the proxy.
  2. Next, add basic network rules, such as explicit local network targets.
  3. Then add broader domain or IP categories.
  4. Finally, decide what should happen by default. If no rule matches, V2Ray/Xray typically uses the first outbound in the list.

Fields in a rule are generally combined with “AND,” while values within a field’s array are generally combined with “OR.” For example, a rule with both domain: ["domain:example.com"] and port: "443" matches connections to port 443 on that domain and its subdomains. This is the target port, not the client’s local listening port.

443
Example HTTPS destination port
53
Common destination port for traditional DNS
/32
Prefix length for a single IPv4 address

5. domainStrategy: whether and when to resolve domains

routing.domainStrategy controls how routing uses DNS results. It is not the browser’s DNS setting, nor a replacement for an option with the same name in an outbound module. Changing it can affect matches and when resolution occurs, but it does not change the basic priority of the rules array.

ValueRouting behaviorWhat to check
AsIsDoes not actively resolve domains for routing matchesIP rules can still match when the original target is an IP address
IPIfNonMatchIf a domain request has no match on the first pass, resolve it and retry the rulesA domain rule or catch-all match on the first pass prevents this process from running
IPOnDemandResolve on demand when a domain request reaches a rule that needs an IP matchAn earlier IP rule may match before a later domain rule

For example, place geoip:cn before a domain rule that routes traffic through a proxy. With IPOnDemand, the earlier IP condition may trigger a lookup and select direct if the address belongs to that category. With AsIs, a domain-only request won’t be resolved just for this IP rule and may match the later domain rule instead. Different results don’t mean rule order stopped working; the available match data changed.

Now consider IPIfNonMatch: the core resolves and scans the rules again only if the first pass finds no matching domain rule and no other rule catches the request. If the target was already an IP when it entered the inbound, there is no need for an initial domain-based pass. When troubleshooting, record the input target type instead of assuming every connection starts with a domain.

6. Verify custom rules in v2rayN

The routing scheme in the GUI, the configuration used by the running core, and an edited file on disk may not contain the same settings. Save the current routing scheme first. In v2rayN’s main window, open the routing configuration entry and confirm which scheme is active, then check routing.domainStrategy and routing.rules in the generated configuration. Menu names may vary between interface layouts; rely on the fields and active configuration, and don’t expect edits to a temporary generated file to persist.

  1. Create a single test rule. Choose a fully qualified host you can access, use full: at the top of the rules, and point it to an existing outbound tag. Leave regular expressions and category data out for now.
  2. Save and apply the configuration again. Reload through the client or restart the core so the changes take effect in the active configuration. Check the startup output for errors such as unknown fields, missing outbounds, or failed category loads.
  3. Start a new connection. Close the relevant page and visit it again; restart the test application if needed. Persistent HTTP/2 connections and connection reuse may keep using the old outbound, so refreshing a page may not create a new connection.
  4. Check the actual logs. If access logging is enabled, verify the target and outbound tag; temporarily increase the log level if needed. Log formats vary by core, so whether a page opens is not enough to tell which rule matched.
  5. Restore complex conditions one at a time. After the exact-domain test works, add domain categories, IP conditions, and DNS strategies. Change only one variable at a time and compare the logs before and after.

A browser session may also connect to the main site, static assets, login APIs, and media domains. A page loading successfully does not mean all its connections use the same outbound. Check logs by target host; don’t treat every request from a page as one connection.

I set domain:example.com. Why is another domain being routed the same way?

Check that the saved entry actually includes domain:. The plain string example.com uses substring matching and has a wider scope. To match just one host, change it to full:example.com, reapply the configuration, and start a new connection.

I saved a geosite rule. Why does the core report an error at startup?

Check the startup output for a missing category or unreadable data file, then verify the data resource path used by the current core and the exact category name. Test basic routing with a full: rule first; a data-loading failure does not mean the node is unavailable.

IPIfNonMatch is enabled, but why aren’t my IP rules matching?

Check whether an earlier domain rule already matches and whether a catch-all such as network: "tcp,udp" appears at the end. Once the first pass finds a match, this strategy won’t trigger a DNS lookup and retry. Then check whether the request entered the core as a domain or an IP address.

Will routing port 53 directly control all DNS traffic?

No. Destination port 53 covers only qualifying traditional DNS connections. Encrypted DNS may use other ports, and the core’s own DNS queries follow a separate path. Check both the application’s DNS settings and the core’s DNS configuration instead of relying on a port rule alone.

Bottom line: verify the target, rule order, and outbound

For each change, record the test hostname, rule position, and outbound tag shown in the logs. Verify an exact-match rule before expanding to category sets. This helps separate syntax errors, overly broad matching, and DNS timing issues.

Download v2rayNChoose a platform and installer