This guide is for v2rayN users who can already connect through a server and are ready to edit routing rules. Using Xray routing fields as a reference, it explains where to enter domains and IPs, shows how to order direct, proxy, and block rules, and covers how to verify them with the config, logs, and a test request.
1. Check the routing entry point and active core
v2rayN is a client for configuring and managing connections; the running core handles actual traffic matching. This guide explains routing.rules, domainStrategy, and outboundTag according to Xray configuration semantics. If you use a different configuration format, don’t paste the same JSON just because menu labels look similar.
In the desktop app, open “Settings” → “Routing Settings,” select the routing profile you want to edit, then open its rule list. Depending on the version, you may need to double-click a row or use the context menu. Make sure the editor includes fields for domains, IPs, ports, and outbounds. After saving, select this profile from the “Routing” menu on the main screen to enable it; adding a profile alone does not switch to it.
- Note the current setup: Record the routing profile name, active server, and core type, and keep a working copy of the original config.
- Duplicate the profile: Make changes to a copy instead of overwriting the config you use every day.
- Check the outbounds: Verify the actual tags for direct, proxy, and block. The examples below use
direct,proxy, andblock. - Apply the changes: Save and enable the routing profile, then check the core logs for startup failures or configuration parsing errors.
2. Rule order: the first match determines the outbound
For standard field-based routing rules, the core checks the list from top to bottom and uses the outbound of the first rule whose conditions match. There is no automatic priority where an exact domain always outranks a domain list: even if a full: rule appears further down, it won’t get a chance if a broader rule above it already matched.
Multiple values in the same field usually work as “OR,” while different condition fields work as “AND.” For example, if a domain list has two entries, either one can match; if the same rule also specifies port 443, both the domain and destination port must match. Adding a domain and an IP to the same rule does not mean either one can match independently.
These are protocol ports and address ranges, not speed test results. The routing port field refers to the destination port, not the local proxy listening port. When a browser connects to the local proxy to visit an HTTPS site, the rule generally needs to match the remote port 443, not the port the browser uses to connect to the local proxy.
Bottom line: put exceptions before broad matches
To route a specific domain through a proxy, move its exact proxy rule above any direct rule that could match it, then test a new connection. Changing the prefix without changing the rule’s position won’t fix a match intercepted by an earlier rule.
3. How to write domain, full, regexp, and geosite rules
These prefixes belong in the domain field. Don’t include https://, a path, query parameters, or a port. For the browser address https://api.example.com/account, the domain is api.example.com; routing domain rules don’t split traffic by webpage path.
| Syntax | What it matches | When to use it |
|---|---|---|
domain:example.com | Matches example.com and its subdomains | Good for an entire site; does not match notexample.com |
full:api.example.com | Matches this exact domain only | Does not include other subdomains |
regexp:^api[0-9]+\.example\.com$ | Uses a regular expression to match domains such as api1 and api20 | Check anchors, escaping, and the core’s regex syntax |
geosite:cn | References the cn group in the domain data file | The group’s contents depend on the data file actually loaded |
example.com | Without a prefix, matches as a plain substring | Broader than a domain suffix match; avoid using it for exact matches |
Use domain: to route a service and its subdomains together; use full: for an exception applying to a single domain. A bare string may also match domains such as example.com.other.test, so for typical setups, prefer a prefix with clear matching boundaries.
{
"type": "field",
"domain": [
"full:api.example.com",
"domain:example.net",
"regexp:^api[0-9]+\\.example\\.org$"
],
"outboundTag": "proxy"
}
The three domain conditions here are joined with “OR.” This example uses JSON, so each backslash in the regex must be escaped with another backslash. When entering the rule directly in v2rayN’s domain text field, use regexp:^api[0-9]+\.example\.org$—no additional JSON string escaping is needed. Regex support depends on the core; don’t assume every feature available in browser regexes will work.
- geosite is a domain list:
geosite:cndoes not check in real time whether a server is located in China, nor does it match every domain ending in.cn. - Groups depend on the data file: Categories shown in online examples may not exist in your local data. If the core reports that a list can’t be found, check the data source and the exact group name.
- Updates can change what matches: Updating domain data can change matching results even when the rule text stays the same. When troubleshooting, note when the data was last updated.
4. The difference between the ip field, CIDR, and geoip
ip is a rule field name, not a prefix to add before an address. In the graphical editor’s IP field, you can enter an individual address, a CIDR range, or a geoip: group. For example, enter 192.168.0.0/16, not ip:192.168.0.0/16. Enter IPv6 addresses in the IP field as well.
{
"type": "field",
"ip": [
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"fc00::/7"
],
"outboundTag": "direct"
}
This rule covers common private address ranges, but it is not a complete list of all local, link-local, and reserved addresses. If you use geoip:private, check that your local IP data file includes this group and understand what it covers. To access a local network service, also make sure the request actually passes through the proxy core; connections bypassing the system proxy won’t appear in that route’s match logs.
| IP entry | Meaning | What to check |
|---|---|---|
192.168.1.10 | Single IPv4 address | Update the rule if the device’s address changes |
192.168.0.0/16 | Matches this IPv4 range | The broader the range, the more destinations it affects |
geoip:cn | Matches an IP group from the data file | Does not identify domain ownership or the service operator |
geoip:private | References the private address group | Make sure the loaded data file contains this group |
A website may use multiple CDN addresses, and DNS results can vary by network. Routing an entire site based on a single IP from one lookup is usually less reliable than using a domain rule. Prefer IP rules when an app connects directly to an IP, or when targeting a fixed device on your local network or a specific address range.
5. How the domain resolution strategy affects IP rules
When a request includes a domain, whether the core resolves it to an IP before checking IP rules depends on settings such as routing.domainStrategy. This is separate from which DNS server handles the final connection and whether traffic sniffing is enabled; flipping one setting won’t necessarily solve everything.
| Strategy value | What happens during routing | What to watch for |
|---|---|---|
AsIs | Does not actively resolve domains to IPs for route matching | Requests that already have an IP destination can still match IP rules |
IPIfNonMatch | If no domain rule matches, tries resolving the domain and checks again | A broad domain fallback can end rule matching early |
IPOnDemand | Resolves the domain when a rule requires an IP check | An IP rule near the top can match before a domain rule further down |
For example, if “proxy all TCP and UDP” appears at the bottom of the list, a domain request under IPIfNonMatch may hit this network-wide fallback even when no specific domain rule matches. Once a rule matches, you can’t expect the core to resolve the domain afterward and route it through geoip:cn. This is a common reason why a rule intended to route mainland China IPs directly appears to have no effect.
- Prioritize domain rules: List specific domain exceptions and groups first to avoid unnecessary DNS lookups during matching.
- Relying on IP groups: Check the current resolution strategy, make sure DNS works, and verify that no earlier rule has already matched.
- The app only provides an IP: Domain rules may have nothing to match. Whether sniffing can recover the domain depends on the protocol and configuration, and is not guaranteed for every connection.
6. Example order for direct, proxy, and block rules
A common order is “specific exceptions first, broad groups next, and the final fallback last.” Whether a block rule should come before an exception depends on what you want: to block a domain, put the block rule above any rule that might allow it; to allow one site within a blocked group, put its exact allow rule above the group rule.
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:blocked.example.org"],
"outboundTag": "block"
},
{
"type": "field",
"domain": ["full:api.example.com"],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": ["10.0.0.0/8", "192.168.0.0/16"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
The domains in this example illustrate syntax; they are not usable servers or real test services. Your config must define the corresponding outbound tags: direct for a direct outbound, block for a blocking outbound, and proxy for the actual proxy outbound. A tag is only a reference name; writing the string proxy does not create a server.
- Explicit blocks: Handle exact destinations that must be denied first.
- Domain exceptions: Assign an outbound to a specific endpoint or site before a later group rule can override it.
- Private IPs: Handle local network destinations accessed by IP. This example uses AsIs, so it won’t actively resolve domains to match this rule.
- Direct for a group: Match the remaining domains against the geosite data actually in use.
- Proxy fallback: Send any remaining TCP and UDP traffic through the proxy.
If no rule matches, Xray generally uses the first outbound in the config. Don’t assume this means traffic will always use the proxy: the client may generate outbounds in a different order. An explicit fallback is easier to understand, but keep the resolution strategy described above in mind.
7. How to verify rules and troubleshoot common issues
First, distinguish between three cases: the request never reached the core, it reached the core but matched the wrong rule, or it matched the right outbound but the connection failed. For the first case, check the system proxy and app settings. For the second, check rule order and match fields. For the third, check the server, DNS, and destination connectivity. A correct route does not guarantee that the proxy server is working.
- Change one rule: Pick a domain you actually use, add a
full:rule, and place it above any rule that could match it. - Start a new connection: Save and enable the routing profile, close the existing page or app connection, then send the request again. Existing persistent connections won’t be routed again automatically when you edit a rule.
- Check the logs: In v2rayN’s log panel, check the destination, errors, and outbound tag. Temporarily increase the log level if needed; standard access logs may not show which rule line matched.
- Check the generated config: Make sure the config loaded by the active core includes the new entry and that its tag matches the one in outbounds. Don’t make permanent edits directly to temporary configs that the client may regenerate.
- Restore your settings: Once you’ve found the cause, remove temporary test rules and restore the log level to avoid recording unnecessary connection details.
Why is my API still going direct with domain:example.com?
First, check whether a direct rule above it has already matched, then confirm that the API’s actual domain belongs to example.com. Temporarily move a full: proxy rule for that API above the relevant direct rules, save, and start a new connection. Also make sure the active routing profile is the one you just edited.
The core fails to start after I save geosite:cn. What’s wrong?
Check the specific error in the core logs. If it says a data file or group is missing, verify which geosite data file is in use and check the group name. For a JSON parsing error, check commas, quotes, and regex escaping. Remove the new entry first to restore connectivity, then fix it separately.
Why do fewer connections match when I fill in both a domain and an IP?
Different condition fields in the same rule must all match. If you mean “the domain matches OR the IP is in this range,” split them into two rules and assign the same outbound to both. Don’t put both conditions on one line and expect either to match.
The site still won’t load after I switched to proxy. Does that mean the route didn’t work?
First, check the access logs to see whether the proxy outbound was selected. If it was, investigate the current server connection error, DNS resolution, and destination service status. If the request isn’t in the logs, check whether the app follows the system proxy. Don’t infer whether a rule matched based only on whether the page loads.
When saving troubleshooting notes, keep only the rule order, destination type, outbound tag, and error details. Before sharing a screenshot or config, hide subscription URLs, server credentials, and any domain names that aren’t needed. Reproducing one clear match is more useful for diagnosing the issue than adding a large number of rules at once.