For users who already have v2rayN, v2rayNG, or v2flyNG working and want more control over direct, proxied, and blocked traffic. This guide covers the exact meaning of domain, full, regexp, geosite, CIDR, and geoip, how to combine conditions, and how to order rules from specific exceptions to the fallback.
What routing rules actually do
V2Ray routing does not benchmark multiple nodes. It selects an outbound based on the connection's destination. After an application opens a connection, the core reads fields such as the destination domain or IP, destination port, network type, and inbound tag, then checks rules starting with the first entry in routing.rules. The first rule whose conditions are all satisfied determines outboundTag; later rules are not considered for that connection.
So routing configuration must define usable outbound tags first. For example, mark the proxy outbound as proxy, direct connections as direct, and blocked traffic as block. Tags in rules only reference these outbounds, so their spelling must exactly match the tag in outbounds, including letter case.
A type: field rule can contain multiple fields. Values within the same field array use an “any match” rule—for example, listing three domains in a domain array requires only one to match. Different fields are combined with “all conditions must match”: a rule containing both domain and port requires the destination to satisfy the domain condition and fall within the specified port range.
| Rule field | Information read | Example | Combination logic |
|---|---|---|---|
domain |
Destination domain | full:api.example.com |
Any item in the array matches |
ip |
Destination IP or resolved address | 10.0.0.0/8 |
Any item in the array matches |
port |
Destination port | 53、80-443 |
Must match alongside other fields |
network |
Transport network | tcp,udp |
Must match alongside other fields |
inboundTag |
Which inbound accepted the connection | socks-in |
Must match alongside other fields |
domain, full, regexp, and geosite
The domain field carries domain conditions, and each string in its array can use a different prefix. A plain string without a prefix uses keyword matching and has the broadest scope; domain: matches a domain and its subdomains; full: matches only the exact domain; regexp: uses a regular expression; and geosite: references a domain category in the local rule data.
Exact domain
- Syntax
- full:api.example.com
- Matches
- api.example.com
- Does not match
- www.example.com
Best for controlling a single API domain, update domain, or fixed service endpoint.
Domain and subdomains
- Syntax
- domain:example.com
- Matches
- example.com
- Both match
- cdn.example.com
Commonly used to send a root domain and all its subdomains through the same outbound.
Regular expression matching
- Syntax
- regexp:^img[0-9]+\.example\.com$
- Matches
- img12.example.com
- Cost
- Higher matching overhead
Use only when a prefix, suffix, or rule set cannot express the target.
Domain category
- Syntax
- geosite:cn
- Data source
- Local geosite data file
- Update method
- Updated with the rule data
Useful for covering many domains at once, but the contents depend on the version of the local data file.
Plain keyword patterns can match far more than intended. If an array item is example, any domain containing those characters may match, including example.net and cdn-example.org. When the full domain is known, prefer full:. To cover a root domain and its subdomains, use domain:; both are easier to review than a broad keyword.
The expression in regexp: must also be escaped for a JSON string. The regular-expression \. must be written as \\. in JSON. Leaving out one layer of backslash escaping can make the configuration fail to parse or change the expression's meaning. The following rule sends a specific API domain and a group of image subdomains through the proxy:
{
"type": "field",
"domain": [
"full:api.example.com",
"regexp:^img[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
geosite is not an online lookup service. It reads categories from a local data file. Common forms include geosite:cn, geosite:private, and geosite:category-ads-all. Whether a category exists and which domains it contains depends on the data file currently used by the client. If the log says a category is missing, update the Geo data first and then verify the category name instead of repeatedly changing the outbound.
full:: Narrowest scope; ideal for one specific hostname.domain:: Covers a root domain and its subdomains; suitable for ordinary site routing.regexp:: Powerful and flexible; suitable for dynamic subdomains with a consistent pattern.geosite:: References a group of domains at once; suitable for category-based rules.- Keyword without a prefix: broad matching scope; use with care in large rule sets.
ip, CIDR, geoip, and domainStrategy
The ip field accepts a single address, a CIDR network, or a geoip: category. An IPv4 address can be written as 192.0.2.10, while a network can use 192.168.0.0/16; IPv6 uses CIDR as well, such as fd00::/8. Private networks are usually handled together with geoip:private, avoiding separate entries for 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16.
Whether an IP rule can match a domain request depends directly on routing.domainStrategy. When a browser accesses a domain, the core may initially receive the domain name. With AsIs, the routing stage does not resolve the domain for IP rules, so geoip:cn should not be treated as a replacement for domain categories.
| domainStrategy | Handling | Best suited for |
|---|---|---|
AsIs |
Match the original destination without actively resolving the domain for routing | Primarily domain and geosite rules |
IPIfNonMatch |
Resolve the IP after domain rules miss, then try IP rules | Prioritize domain rules, with geoip as a supplement |
IPOnDemand |
Resolve the destination when a rule requires IP information during matching | Rule structures that depend heavily on IP conditions |
Most configurations that use “domain categories for direct connections, IP categories as a supplement” can start with IPIfNonMatch. This checks geosite:cn first, then uses the resolved address to check geoip:cn if there is no match. When DNS returns multiple addresses, the actual connection and routing result can also be affected by DNS settings, caching, and address selection, so do not judge an entire rule set from a single resolution result.
{
"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"
}
]
}
}
Conclusion: domain and IP categories are not interchangeable
Use geosite first when grouping by site, and use geoip to supplement decisions based on the resolved network location. Set domainStrategy to a strategy that matches this order.
Match priority and rule ordering
V2Ray does not assign a global priority automatically to full:, geosite:, or geoip:. “Specific rules first” simply means placing precise rules earlier in the configuration. Once an earlier rule matches and selects an outbound, a more precise condition later cannot override the result.
The most reliable order is “exceptions first, categories in the middle, fallback last.” Start with precise targets that must be blocked or sent direct, then private networks and regional categories, followed by categories that need the proxy. Finish with a rule containing only network: tcp,udp to catch remaining connections. Never place the fallback in the middle, or later rules for the same network types will never run.
- Layer 1: Explicit exceptions such as specific domains, IPs, and ports.
- Layer 2: Ad categories and destinations that must be blocked.
- Layer 3: LAN hosts, private addresses, and sites that must use a direct connection.
- Layer 4: Regional domain and IP categories.
- Layer 5: Specified domains or categories that require the proxy.
- Final layer: A fallback outbound covering
tcp,udp.
Here is an organization example that is easy to extend. It blocks ad categories first, sends private addresses and specified sites direct, handles regional categories next, and finally sends other TCP and UDP connections through the proxy. The proxy, direct, and block values in this example must be replaced with outbound tags that actually exist in the complete configuration.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"full:telemetry.example.com",
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"full:intranet.example.com",
"domain:office.example.net"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
Writing domain and ip in the same rule usually does not mean “either/or”; it requires both fields to match. If the goal is to send “a specific domain or a specific IP” direct, split them into two rules and use the same outboundTag. This is one of the most common logic mistakes in custom routing.
Conclusion: split rules first, then adjust their order
When a rule with multiple fields never matches, first split domain, ip, and port into separate rules for testing; once each condition works, decide whether to combine them with an “all conditions required” rule.
Implementing and verifying rules in the client
On desktop, v2rayN 7.x lets you open “Settings” → “Routing settings”, copy the current routing profile, and edit the copy instead of overwriting the active profile. Save and select the profile when finished, then restart the core. To inspect the final generated configuration, open “Settings” → “View configuration file” and review the JSON passed to the core, especially routing, rules, and outboundTag.
The interface locations in Android v2rayNG and v2flyNG may change between versions, but the verification process is the same: confirm that custom routing is enabled, then check whether predefined rules, the domain strategy, and application-level proxy settings override one another. Subscription updates usually refresh server configuration; do not assume they preserve every client-specific routing profile. Save the rule text before editing to make migration easier.
- Start with
full:for one known domain and point it to an easy-to-identify outbound. - After restarting the core, visit the domain and check the destination and outbound tag in the connection log.
- Then test a domain that is not covered by the rule to confirm that the fallback works.
- Visit a LAN address such as
192.168.1.1:80and confirm that private addresses use the direct connection. - Add
geositeandgeoipcategories last, so problems remain easy to isolate instead of appearing all at once after importing a large rule set.
When testing port conditions, distinguish the local proxy listening port from the destination port. v2rayN commonly uses 10808 as a local SOCKS listening port, which belongs to the inbound. The port: 443 in a routing rule refers to the remote destination port. Putting 10808 in a destination-port rule generally will not route “all browser traffic” as intended.
If no websites connect after an edit, first revert to a minimal configuration with one fallback rule and restore rules one at a time. When the core log shows failed to parse, check JSON commas, quotation marks, and regular-expression escaping. If a geosite or geoip category is missing, update the corresponding data file. If the connection succeeds but uses the wrong outbound, check rule order and tag spelling first.
Why does a full rule still use the fallback proxy?
First confirm in the log that the destination is still a domain rather than an IP resolved by the application. Then check the full domain, port condition, and outbound tag. If the application connects directly to an IP, a standalone full: rule will not match.
Should I keep only one of geosite:cn and geoip:cn?
They process different information. You can use geosite:cn to match domains first, then use geoip:cn under IPIfNonMatch to supplement decisions based on the resolved address.
Why does putting direct first disable the proxy rules?
Check whether the first rule contains network: tcp,udp and therefore covers every connection. This is a fallback rule and should be moved to the end; otherwise, later rules for the same network types cannot match.
What happens when domain and port appear in the same rule?
Both fields must match. For example, domain:example.com together with port:443 handles connections from that root domain and its subdomains to destination port 443, but not to destination port 80.
Final checks for maintainable rules
A maintainable routing configuration does not need large stacks of duplicate entries. Prefer explicit full: and domain: rules for exceptions, use geosite and geoip for categories, and keep one readable fallback rule at the end. Change only one type of condition at a time and use logs to confirm the rule and outbound actually selected.
As the rule count grows, group entries in this order: “block, private networks, forced direct, direct by category, forced proxy, fallback proxy.” Even if the client interface supports drag-and-drop, keep a formatted JSON copy for reference, recording domainStrategy, outbound tags, and the Geo categories required. This makes it easier to transfer the approach between v2rayN, v2rayNG, and v2flyNG without mistaking interface options for core syntax.
- Confirm that every
outboundTagexists inoutbounds. - Confirm that precise exceptions appear before category rules.
- Confirm that
geoiprules are used together withdomainStrategy. - Confirm that different fields require “all conditions to match”, while items within an array use “any match”.
- Confirm that the
network: tcp,udpfallback rule is last. - Confirm that backslashes are escaped correctly in JSON regular expressions.
- Confirm that the Geo data contains every category referenced by the configuration.