This article is for users who can already import nodes and want finer control over direct, proxied, and blocked traffic. It covers domain and IP matching, geosite and geoip datasets, conflict resolution, and a routing configuration you can adapt to your outbound tags.
Understand How routing Matching Works First
V2Ray routing does not change protocols such as VMess or VLESS. It determines which outbound handles a request after it reaches the core—for example, whether a connection is proxied, sent direct, blocked, or routed through another defined exit. The result depends on the target, rule order, and outbound tags; a working node does not guarantee correct traffic splitting.
A request usually enters through a local SOCKS, HTTP, or transparent-proxy inbound before reaching routing.rules. The core checks rules from the first array item and stops at the first match, using that rule’s outboundTag or balancerTag. Later rules cannot override an earlier match, even if they are more specific.
Multiple fields in one rule usually mean “all conditions must match.” For example, a rule with network: "tcp" and port: "443" matches only TCP connections on port 443. Arrays within a field usually mean “any value may match”: if the domain array contains three domain conditions, matching one satisfies that field.
- Between rules: Check rules from top to bottom; the first match takes effect.
- Different fields: Conditions such as domain, network, and port must all be satisfied.
- Values in one field: Multiple array values usually match when any one of them matches.
- Final outbound: outboundTag must exactly match an existing tag in outbounds.
How to Write domain, full, regexp, and geosite Rules
The domain field accepts an array of strings, and each string can use a different matching syntax. A plain string performs a domain-substring match; domain: matches a domain and its subdomains; full: matches only the complete domain; regexp: uses a regular expression; and geosite: references an external domain-category dataset. For everyday traffic splitting, prefer domain, full, and geosite; use regexp only when the other syntaxes cannot express the required scope.
Exact and Suffix Matching
- Full domain
- full:api.example.com
- Domain and subdomains
- domain:example.com
- Plain string
- example
- Regular expression
- regexp:^.+\.example\.com$
When you know a fixed hostname, prefer full; use domain to cover an entire site and its subdomains.
Category-Based Matching
- Common mainland China domains
- geosite:cn
- Ad categories
- geosite:category-ads-all
- Domains outside mainland China
- geosite:geolocation-!cn
- Data source
- Data file loaded by the core
Whether a category name works depends on the data file actually loaded by the current core and its version.
domain:example.com covers example.com and www.example.com, making it suitable for site-wide policies; full:example.com does not automatically cover subdomains and is better for one fixed hostname. Plain strings have a broader scope and may unintentionally match other sites containing the same characters, so avoid using very short words as rules.
{
"type": "field",
"domain": [
"full:api.example.com",
"domain:static.example.com",
"geosite:cn"
],
"outboundTag": "direct"
}
geosite is not a live online lookup service. It is local domain-category data read by the core. After the client or core is updated, category contents may change with the data file. If the log says a geosite category is missing, first confirm that the category exists, then check whether the client uses the V2Ray or Xray core. Do not hide missing data by repeatedly changing rule order.
Matching Conditions for IP, CIDR, and geoip
The ip field checks the destination IP address. It accepts a single address, a CIDR range, or a geoip: category. Common forms include 127.0.0.0/8, 192.168.0.0/16, geoip:private, and geoip:cn. The CIDR suffix specifies the network-prefix length; changing it by one bit can significantly widen or narrow the match.
If an application connects directly to an IP address, the core can apply an ip rule immediately. For domain requests, whether routing resolves the domain for matching depends on routing.domainStrategy. AsIs primarily keeps the original domain for matching; IPIfNonMatch tries to resolve it and continue with IP matching when domain rules produce no result; IPOnDemand may trigger resolution when the matching process needs an IP condition.
| Syntax | Matching scope | Typical use |
|---|---|---|
127.0.0.0/8 |
Local loopback range | Keep local services out of the remote proxy |
192.168.0.0/16 |
Common LAN address range | Access routers, storage devices, and internal services |
geoip:private |
Private addresses defined by the data file | Handle multiple private ranges centrally |
geoip:cn |
Mainland China addresses classified by the data file | Supplement domain-based traffic splitting |
Bottom line: Use domain rules for primary splitting and IP rules as a fallback
Use full, domain, and geosite first to express clear service scopes, then use geoip:private, geoip:cn, or explicit CIDR ranges for connections that access IPs directly. This reduces unnecessary DNS resolution and makes it easier to tell from logs why a request reached a particular outbound.
With IPIfNonMatch, also pay attention to the resolution path: the IP used for routing decisions should match the IP used for the actual remote connection whenever possible. If built-in DNS, system DNS, and remote resolution return different results, the same domain may fall into different address categories at different times. When traffic splitting changes intermittently, check the dns configuration, domainStrategy, and destination addresses in the core logs together.
Rule Priority and Common Conflicts
V2Ray does not automatically determine which rule is “more specific.” Earlier array entries have higher priority, so organize rules as “exceptions first, broad ranges later, fallback last.” If a domain needs the proxy but also belongs to geosite:cn, place its proxy rule before the geosite direct rule.
- Put exact rules that must be blocked or handled separately first, such as a
full:domain. - Next, add direct rules for LAN and private addresses so local-device requests do not enter the proxy.
- Then add service-domain groups, geosite categories, and specific network ranges.
- Finally, add broad proxy or direct fallback rules.
- After editing, verify domain, IP, TCP, and UDP requests one by one in the core logs.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"full:service.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"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
The first rule above is an exception within the geosite direct range, so it comes first. The second protects LAN access. The third and fourth handle mainland China domains and addresses. The final rule sends remaining TCP and UDP requests to proxy. Before using it, confirm that outbounds contains both proxy and direct tags; otherwise, the core may fail to start because it references nonexistent outbounds.
Configure and Verify Routing in v2rayN
v2rayN menu names may change between versions; the common path is “Settings” → “Routing settings.” After creating a custom rule set, confirm that it is selected, save the configuration, and restart the current core. If you use a fully custom configuration file, check whether switching nodes or updating a subscription regenerates the file, which could overwrite manual changes.
| Check | Action | Expected result |
|---|---|---|
| Local inbound | Under “Settings” → “Parameter settings,” verify SOCKS 10808 and HTTP 10809 | The browser or test program connects to the ports actually enabled |
| Outbound tags | Check that proxy and direct in the rules match existing outbound tags | The core startup log shows no unknown outbound tags |
| Rule order | Test an exact domain, a geosite domain, a direct IP, and a LAN address separately | All four request types reach the expected outbound |
| UDP requests | Confirm the fallback rule includes udp, and review node and inbound settings | DNS and other UDP traffic is not omitted |
Do not verify routing only by checking whether a webpage opens. Enable core logging and prepare at least six targets: one exact proxy domain, one geosite direct domain, one mainland China IP, one LAN IP, one domain that should be blocked, and one domain not covered by the earlier rules. Request them one by one and record the matched outboundTag; record the rule index too when the logs show it.
Bottom line: Change One Set of Conditions at a Time
First fix domainStrategy and the outbound tags, then move one rule or change one match condition. Changing DNS, geosite categories, and rule order all at once makes the logs impossible to attribute to a single cause and prolongs troubleshooting.
- After editing the rules, save the configuration and restart the current core—not just the settings window.
- Check the logs again after switching nodes to confirm that the client did not restore its default routing.
- When a subscription update only manages node data, do not assume it preserves every custom field.
- As the rule set grows, keep notes grouped by purpose to avoid two broad rules with opposite meanings.
Common Issues and Troubleshooting Order
Routing problems usually appear as a site using the wrong exit, inaccessible LAN devices, no change after saving rules, or a core that fails to start. First confirm that the configuration was actually loaded, then check tags and order, and only afterward investigate DNS resolution and category data. This sequence rules out basic issues such as an unapplied configuration first.
Why does a domain rule still match the geosite rule above it?
Move the exact domain or full rule above the geosite rule, save, and restart the core. Rules are not sorted by specificity; once the earlier geosite rule matches, that request has already finished routing evaluation.
Why does IP traffic split correctly while domain traffic does not use geoip?
Check routing.domainStrategy. With AsIs, domain requests are not resolved for every IP rule by default. If you need IP matching after domain rules produce no match, consider IPIfNonMatch.
What should I do if the core fails to start after adding geosite?
Remove the newly added category and restore startup first, then verify the category name against the data file loaded by the current core. Reordering rules cannot fix a missing category or unreadable data file.
Why are LAN addresses being sent through the proxy?
Add geoip:private before broad proxy rules, or explicitly add 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16. Then test whether router and internal-service addresses match direct.
Why does nothing change after saving even though the rules look correct?
Confirm that the edited routing configuration is the one currently enabled, then restart the core and inspect the generated configuration. If rules disappear after switching nodes, check whether the client regenerates the routing section.
A maintainable traffic-splitting configuration does not need a pile of duplicate rules. Keep exact exceptions, private addresses, the main geosite or geoip categories, and the final fallback first; add entries only when logs show they are needed. When adding a rule, record its purpose, target outbound, and verification result so you can quickly decide whether it is still necessary after updating data files or changing cores.
- Check loading first: Review the core startup log and the generated routing configuration.
- Then check tags: Verify outboundTag spelling, letter case, and the corresponding outbound.
- Next check order: Place exact exceptions before broad categories.
- Check resolution last: Consider domainStrategy, DNS settings, and the actual destination IP.