This guide is for users who can import nodes and enable a system proxy, and want precise control of connection exits in v2rayN or Xray. It covers domain and IP rule syntax, rule-array order, combining conditions, domainStrategy, and ways to trace routing issues through logs and generated configuration.
Routing flow and first-match behavior
The V2Ray and Xray routing modules do not establish node connections. Once a request enters the core, they choose an outbound based on the target domain, target IP, port, network type, inbound tag, and other details. The final choice is usually selected by outboundTag, which points to a defined outbound such as proxy, direct, or block.
Rules are stored in the routing.rules array, and the core checks them from the first entry downward. Once a rule satisfies all conditions, scanning stops immediately and later rules do not participate in that request. Therefore, placing more specific rules first and broader rules later is the foundation of a stable configuration.
Different fields in the same rule generally use an “AND” relationship. For example, if a rule contains both domain and port, the target must satisfy both the domain and port conditions. Multiple items within one field generally use an “OR” relationship: if a domain array lists three domains, matching any one of them satisfies that field.
| Relationship | Evaluation | Result |
|---|---|---|
| Between different rules | Scanned from top to bottom | The first fully matching rule applies |
| Different fields in one rule | All conditions must match | Both domain and port must match |
| Multiple values in one field | Any one value may match | Array items use an “OR” relationship |
| No rule matches | Use the default outbound | Usually falls back to the first available outbound in the configuration |
domain: exact domains, subdomains, and keyword matching
The domain field handles the target hostname. Common prefixes include full:, domain:, keyword:, regexp:, and geosite:. The prefix determines the matching scope, so choosing the wrong one can make a rule too broad or prevent it from matching at all.
full:example.com matches only the complete hostname example.com; it does not treat www.example.com as the same target. domain:example.com matches that domain and its subdomains, making it suitable for sending an entire site family through the same outbound.
{
"type": "field",
"domain": [
"full:api.example.com",
"domain:static.example.net",
"keyword:media",
"regexp:^cdn-[0-9]+\\.example\\.org$"
],
"outboundTag": "proxy"
}
- full: Suitable for clearly defined hostnames such as login and update endpoints; it has the narrowest scope.
- domain: Suitable for a root domain and all subdomains; it is the more common form for everyday rules.
- keyword: Matches when the target domain contains the specified string; short keywords can easily match unrelated domains.
- regexp: Suitable for domains with a fixed structure and changing numbers, but complex expressions increase maintenance costs.
- geosite: References a prepared domain category set, which is useful for routing by service type or region.
Exact endpoint rule
- Field
- domain
- Syntax
- full:api.example.com
- Scope
- One complete hostname
- Outbound
- proxy
Use this when the scope is explicit and subdomains must not be included.
Direct rule for an entire site
- Field
- domain
- Syntax
- domain:example.cn
- Scope
- Root domain and subdomains
- Outbound
- direct
Suitable when all services on the target site should use the same exit.
If an exact domain needs to be an exception to a category rule, place the exact rule first. For example, send full:download.example.com directly, then send domain:example.com through the proxy. If the order is reversed, the download domain will be caught by the whole-site rule first.
ip and geoip: address ranges and domain-resolution conditions
The ip field can contain a single address, a CIDR range, or a geoip: category. A single IPv4 address can be written as 198.51.100.20, while a network can use 198.51.100.0/24. IPv6 ranges also use CIDR notation, such as 2001:db8:1200::/48.
geoip:private is commonly used to match LAN, loopback, and other non-public addresses. Placing these addresses near the start of the direct rule set prevents local router pages, LAN file services, or local interfaces from being sent to a remote proxy.
{
"type": "field",
"ip": [
"geoip:private",
"192.0.2.0/24",
"2001:db8:1200::/48"
],
"outboundTag": "direct"
}
Whether an IP rule can handle a request that originally used a domain also depends on domainStrategy. When a target has a domain but no target IP, the core must decide whether to resolve that domain before comparing the result against ip rules.
| domainStrategy | Resolution behavior | When to use |
|---|---|---|
| AsIs | Routes the domain as received without actively resolving it for IP rules | When routing mainly relies on domain and geosite rules |
| IPIfNonMatch | Resolves the IP after domain rules fail, then continues checking | When domain rules take priority and IP categories provide a fallback |
| IPOnDemand | Resolves on demand when a rule requires the target IP | When important IP rules appear near the start of the configuration |
Takeaway: decide the resolution strategy first
When a target arrives as a domain and the configuration uses AsIs, a later geoip rule failing to match does not mean the address database is broken. Check domainStrategy first, then inspect the target form in the logs before changing CIDRs or rule order.
geosite and geoip: different boundaries
geosite is a domain collection, while geoip is an IP address collection. They classify information at different stages and cannot replace one another. For sites using dynamic addresses, shared cloud services, or frequently changing DNS results, a domain collection usually expresses service ownership better than a fixed IP range.
A geosite:cn rule checks whether the target domain belongs to the corresponding category; a geoip:cn rule checks whether the target IP falls within the corresponding address set. A domain and its server location are not necessarily the same, so the two rules can classify the same connection differently.
geosite domain collection
- Input
- Target domain
- Example
- geosite:cn
- Dependency
- Domain data file
- Common use
- Routing by service ownership
The domain rule can remain stable even when the target address changes.
geoip address collection
- Input
- Target IP
- Example
- geoip:private
- Dependency
- Address data file
- Common use
- Routing LAN and regional addresses
Whether a domain request enters address matching is controlled by domainStrategy.
Data files must match the core version and the capabilities supported by the configuration. If you see “failed to load geosite” or a category name is not recognized, first confirm that the data file is in the directory actually read by the core, then confirm that the category exists. Changing rule order alone cannot fix a missing data file.
outboundTag and complete rule composition
The value of outboundTag must exactly match the tag of an outbound in the outbounds array. Differences in letter case also count as different names. When a rule contains "outboundTag": "direct", the configuration must define an outbound tagged direct.
A typical order can be divided into four layers: direct access for private addresses, exact exceptions, category routing, and fallback handling. If a blocking rule targets a specific domain or port, place it before any broad proxy rule that could capture it.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"domainMatcher": "hybrid",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["full:updates.example.com"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:cn"],
"outboundTag": "direct"
}
]
}
}
- The first rule handles LAN and local addresses, keeping internal services out of the proxy chain.
- The second defines a clear exception so the specified update domain always uses a direct connection.
- The third handles categorized sites by domain without waiting for IP classification.
- The fourth supplements the decision with resolved address categories when domain rules do not cover the target.
- Unmatched requests continue along the default path, with the actual exit determined by the complete outbound structure.
Takeaway: fix outbound tags before expanding conditions
Start with three clear outbounds named proxy, direct, and block, then add rules one at a time. Stable tags make it easier to connect routing results in the logs to real connections, without debugging conditions and outbound definitions at the same time.
If the configuration uses a load balancer, a rule may point to it through balancerTag instead of selecting one outbound directly. For ordinary custom traffic splitting, prefer outboundTag. Introduce balancerTag only when selectors and a load balancer are actually configured, avoiding an unnecessary troubleshooting layer.
Configuration paths and verification in v2rayN
In v2rayN 7.x, open “Settings” → “Routing Settings” to review the current routing configuration and preset rules. Button locations may change between minor versions, but the verification goal is the same: confirm that the active routing configuration, rule order, and generated core configuration agree.
After making changes, do not rely only on whether a browser can open a page. Browser caches, DNS caches, and reused connections can hide the result. Restart the core, connect to a new target, temporarily set the log level to info or debug, and inspect the routing records.
- Open “Settings” → “Routing Settings”, confirm the selected rule set, and note the expected matching rule.
- Check each rule’s
outboundTagand compare it character by character withoutbounds[].tagin the generated configuration. - Open “Settings” → “Parameter Settings” and confirm local listening and logging options. Common SOCKS and HTTP ports are 10808 and 10809.
- Save the configuration and restart the core. Close existing browser connections or use a new test domain.
- Inspect the target domain, target address, and outbound tag in the logs to determine where rule scanning stopped.
- Move or change only one rule at a time, test again, and then handle the next change to avoid interference between multiple changes.
Checklist
1. Is the target a domain or an IP
2. Does domainStrategy trigger resolution
3. Is the exact rule before the category rule
4. Does outboundTag exist with matching letter case
5. Did geosite and geoip data load successfully
6. Is the test connection new after the change
Common questions when rules do not work
Routing issues are usually not caused by one syntax error. The target form, resolution strategy, ordering, and outbound tags all contribute. Confirm the target that actually appears in the logs, then compare it with the rule conditions instead of simply widening the match scope.
Why does a domain still use the proxy after adding geoip:cn?
Check domainStrategy first. With AsIs, a domain request is not actively resolved just for a later IP rule. Depending on the configuration goal, use IPIfNonMatch, establish a new connection, and inspect the logs.
Why does the exact domain rule not override geosite?
Check that the exact rule appears before the geosite rule and that it uses full:hostname. If a broad rule earlier in the list has already matched, the later exact rule will not run.
What happens when one rule contains both domain and ip?
Both conditions must be satisfied. If the target domain matches domain but its resolved address is not in the ip collection, the entire rule still fails. To express “domain or IP matches,” split the conditions into two rules.
Why does the connection still fail when outboundTag is spelled correctly?
Check whether the corresponding outbound can establish a connection independently, along with tag case, node parameters, and transport settings. A routing match only selects the exit; it does not guarantee that the outbound connection will succeed.
Why is there no change after editing the rules?
Save the configuration and restart the core, close existing long-lived connections, and clear connection reuse in the test application. Then send a new request to a previously unused test hostname and confirm the outbound tag in the latest logs.
The final configuration should make each rule’s purpose readable: one clear intent per rule, tag names that describe the exit, and exception rules placed next to the objects they cover. As the rule set grows, clear ordering and minimal conditions are easier to maintain than layers of keywords.