V2Ray Custom Routing Rules: Domain, IP and GeoSite Matching Syntax and Priority

Learn how domain, full, regexp, IP, GeoSite and GeoIP rules match, how rules are evaluated from top to bottom, and how domainStrategy affects routing.

At a glance

This guide is for v2rayN users who need to add domain exceptions or change the order of direct and proxy routing. It starts by distinguishing domain, IP and dataset matches, then uses a routing configuration to explain first-match behavior, DNS lookups as a fallback and default outbound handling. Examples use the classic JSON routing structure common to V2Ray and Xray; rules configured in a client interface still need to be translated into a format supported by the active core.

1. Routing Rule Structure and Match Targets

The system proxy forwards app connections to the inbound; routing selects an outbound after traffic enters the core. If a browser bypasses the system proxy, even correct rules may never be evaluated. Before troubleshooting custom rules, confirm that the app is connecting through the client instead of relying only on the exit address shown by a website.

Classic configurations store rules in the routing.rules array. Each rule typically has type set to field. Match conditions can include domain, ip, port or network, and outboundTag specifies the result. A tag is a reference name in the configuration, not a built-in action provided by the core.

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

This rule requires the target domain to match any item in the array, the destination port to be 443 and the transport network to be TCP. Items within the domain array are combined with OR; different condition fields are combined with AND. The rule will not handle UDP connections on port 443 or TCP connections on port 80. The three numbers below illustrate configuration values, not speed test results.

443
Destination port specified by the example rule
53
Common destination port for standard DNS
/32
CIDR prefix for a single IPv4 address

2. Using domain, full, regexp and Plain Strings

domain is first a field name in a rule; domain: in the field array is a matching prefix. Do not confuse the two. Array items should contain only a domain or the relevant expression—not a URL scheme, path or query string. Standard domain routing cannot distinguish between URL paths on the same site.

SyntaxWhat it matchesExample
full:example.comExact match for the full hostnameMatches example.com, not www.example.com
domain:example.comA domain and its subdomainsMatches example.com and a.example.com, not notexample.com
example.comSubstring match for a plain stringMay match notexample.com; the scope is often broader than intended
regexp:^api[0-9]+\\.example\\.com$Regular expression matchMatches api1.example.com, not api.example.com

The regular expression in the table is shown as a JSON string. Use \. in the regex itself to match a literal period; JSON also requires the backslash to be escaped, so the configuration file uses \\.. In a client's plain-text input field, you usually enter a single backslash. Do not copy the JSON-escaped form into every interface.

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

In short: use full or domain for domain exceptions

Use full: for one hostname and domain: for a domain and its subdomains. Use a regular expression only when hostnames follow a clear pattern, and add start and end anchors to avoid matching unrelated domains.

3. IP, GeoIP and GeoSite: What's the Difference?

The ip field matches destination addresses and accepts a single IP, a CIDR range or a geoip: dataset reference. geosite: goes in the domain array and matches a set of domains. These datasets contain different entries; matching a GeoSite entry does not guarantee a match in the corresponding GeoIP dataset.

{
  "type": "field",
  "ip": [
    "192.168.0.0/16",
    "10.0.0.0/8",
    "geoip:private"
  ],
  "outboundTag": "direct"
}

The example first shows a CIDR range, then a private-address set; their coverage overlaps, so a real configuration usually needs only the option that fits. A single IPv6 address can use /128. Covering IPv4 alone does not handle every local network connection—check IPv6 destination addresses on dual-stack networks too.

A domain may resolve to CDN addresses in multiple regions, and IP-based rule results can change when DNS answers change. If a service must always use a particular outbound, add a specific domain exception instead of permanently pinning a single CDN address returned by one lookup.

4. Rule Priority: First Match in Order, Not by Specificity

During a rule scan, the core checks the rules array from top to bottom and selects the outbound specified by the first matching rule. It does not automatically let a more specific full: rule override an earlier geosite: rule, or reorder rules by CIDR prefix length. “Exceptions first” means moving exception rules higher in the configuration yourself.

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

Here, the single-host exception comes before the domain-set rule. If a connection matches the second rule, the third will not be considered. Whether the first private-IP rule can match during the initial scan depends on whether the destination is already an IP and whether the domain strategy triggers a lookup. A rule being first does not mean DNS resolution happens first.

  1. If the target is api.example.com and the inbound preserves the domain, the second rule can select proxy directly.
  2. For other domains matching geosite:cn, the third rule selects direct without waiting for an additional IP match.
  3. Only if no rule matches at the domain stage does IPIfNonMatch attempt a lookup and re-evaluate the rules using the resulting IP.
  4. If nothing matches, a classic configuration uses the first outbound in the outbounds array. It is not necessarily named proxy.

5. How domainStrategy Affects DNS and Routing

routing.domainStrategy controls whether routing resolves a target domain to an IP address for matching. It is not the system DNS setting or the similarly named strategy used by a direct outbound. Despite the similar names, these settings belong to different configuration layers and apply at different stages.

AsIs

The routing stage does not proactively resolve domains to IP addresses; IP rules can still match when the target is already an IP. Whether the connection is resolved later depends on subsequent stages, such as the outbound.

Best for: configurations built around domain rules that should not trigger additional DNS lookups during routing.

IPIfNonMatch

Recommended

Try matching with the information already available first. If no rule matches, resolve the domain and use the resulting IP for another round of rule matching. Avoid catch-all rules that match too early.

Best for: routing setups like this guide, where domain exceptions take priority and IP-based location matching is a fallback.

IPOnDemand

Resolve on demand when a rule requires IP information during matching. An earlier matching IP rule may select the outbound before a later domain exception is reached.

Best for: configurations that explicitly require IP rules to be evaluated early and allow control over DNS results and rule order.

For example, suppose the first rule is geoip:private and the second is a proxy exception for a domain. If that domain resolves to a private address, IPOnDemand may match the first rule before reaching the exception. With IPIfNonMatch, a match on the second rule means no additional lookup is needed. After changing the strategy, check which outbound is actually selected—not just whether the site loads.

6. Add and Verify Custom Rules in v2rayN

These steps refer to common interfaces in the v2rayN 7.x desktop release; button locations may vary between minor versions, so use the fields shown in your current window. Rules managed through the interface are not entered the same way as a full JSON configuration. Do not paste an entire routing object into a single domain field.

  1. Check the core

    Open “Settings” → “Parameter Settings” and check the Core type options and which core the current configuration uses. After startup, verify the core name in the logs. The syntax in this guide is for classic V2Ray and Xray routing configurations; other formats need to be converted.

  2. Open routing settings

    Go to “Settings” → “Routing Settings,” back up the current profile, then edit the rule set you intend to enable. Make sure you are editing the route selected on the main screen, not an inactive copy.

  3. Add an exception

    In the rule editor, choose the target outbound and enter full:api.example.com or the domain you need to handle in the domain field. Start without port or network restrictions. Once it works, narrow the conditions as needed.

  4. Reorder the rules

    Move the exception above any domain-set rules that could match first, then save and select the routing profile. The client will usually reload the relevant configuration. If the logs do not show the change, restart the service before testing again.

  5. Check the connection

    Close existing test tabs and create a new connection. Check the connection log for the target and outbound tag. For more detail, temporarily increase the log level under “Settings” → “Parameter Settings,” then restore your usual level when finished.

Routing changes typically apply to new connections; browser connection reuse and long-lived connections may continue using the previous outbound. One refresh is not enough to prove a rule is ineffective. Also test the main domain, a subdomain and a direct IP. Checking only the homepage may miss page resources served from other domains.

TestWhat to checkIf the result is unexpected
Exact domainWhether the full hostname uses the specified tagEarlier rules; the active routing profile
SubdomainCoverage differences between full and domainWhether a plain string was used by mistake or a subdomain was missed
Direct IPWhether the IP rule works independentlyCIDR syntax; IPv4 and IPv6 address families
Unmatched targetWhether it reaches the intended default outboundFirst outbound; catch-all rules; resolution strategy

7. Common Questions About Custom Routing

Why does traffic still go direct when my full rule is at the end?

Greater specificity does not mean higher priority. Open “Settings” → “Routing Settings,” move the rule above any geosite or plain-domain rules that could match first, save, and create a new connection. Then check the outbound tag.

Why doesn't geoip:cn route domain traffic by region?

First check routing.domainStrategy. With AsIs, routing does not resolve domains for IP rules. With IPIfNonMatch, check whether an earlier domain rule already matches or a catch-all rule at the end stops evaluation before the additional lookup.

What should I do if the core fails to start after adding GeoSite?

Remove the new entry to restore the connection, then check the startup log. Confirm that the core can read the data file and that the category you entered exists. Do not keep guessing category names; first verify the routing path with a single domain: rule.

Why do the homepage, login and images use different exits?

Check the actual hostnames used by those requests. Login APIs, static assets and download services often use different domains; a full: rule for the main hostname will not cover them. For hosts within the same controlled domain, use domain:; add separate rules for unrelated domains instead of broadening the match with a vague keyword.

Can I reuse existing rules after switching cores?

First confirm the target core's configuration format, datasets and outbound tags, then test each rule. V2Ray and Xray share some classic fields, but clients may generate configuration differently and support different extensions. A successful import only confirms that the configuration was accepted; it does not prove every connection uses the expected outbound.

Download v2rayN