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

Learn V2Ray routing syntax for domain, full, regexp, IP, GeoSite, and GeoIP rules. See how rules are evaluated in order, avoid common conflicts, and use ready-to-adapt examples.

At a glance

For custom routing, check rule order first, then match conditions, and finally DNS policy. This guide is for users with a working connection who need site-specific exceptions. It covers common V2Ray and Xray field rules, how to configure them in v2rayN, and how to verify the results. Examples use reserved documentation domains and addresses; they do not represent real site categories.

1. Routing rules match conditions, then select an outbound

Routing is separate from node connection settings. Protocols such as VMess and VLESS connect to a server; routing decides which outbound handles a request that has reached the core. v2rayN provides the configuration interface, but the active core applies the rules. The JSON syntax below is for V2Ray/Xray and cannot be pasted unchanged into editors for other configuration formats.

A typical rule includes type: "field", match fields, and outboundTag. The tag must match an existing outbound's tag. Setting the tag to proxy does not create a proxy node, and direct does not create a direct outbound. Clients may generate different tags, so check the actual configuration before editing.

53
Common destination ports for traditional DNS
443
Common destination ports for HTTPS
/32
IPv4 single-address CIDR prefix

These are destination ports, not the client's local listening ports. For example, the rule below sends only requests to port 443 for hosts under example.com through the proxy outbound; it does not cover every connection to that domain.

{
  "type": "field",
  "domain": ["domain:example.com"],
  "port": "443",
  "outboundTag": "proxy"
}

2. Domain, full, and regexp: where domain matching applies

Use domain: to match a base domain and all its subdomains; use full: to match one exact hostname. Don't treat them as interchangeable just because both refer to domains. The domain field takes a hostname, not a URL: leave out the scheme, path, and query string.

Rule syntaxWhat it matchesCommon boundary confusion
domain:example.comexample.com and its subdomains, such as api.example.comDoes not match notexample.com or example.com.test
full:example.comOnly example.comDoes not match www.example.com
exampleA string appearing anywhere in the domainMay match unrelated-example.test; unsuitable for a precise site exception
regexp:^api[0-9]+\.example\.com$For example, api1.example.com and api25.example.comRequires start and end anchors; backslashes must also be escaped in JSON

Use regular expressions only when you need pattern matching. In the example below, the backslash is doubled in the JSON string so the core receives \. to match a literal period. If the interface accepts raw rule text rather than a JSON string, this extra JSON escaping is unnecessary.

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

Bottom line: use full for a single-host exception

For a single login host, start with an exact hostname rule and test it. Expand to a domain rule only if all subdomains need the same outbound, so static assets and other services aren't affected.

3. IP, GeoIP, and GeoSite: keep address and domain sets separate

ip is a JSON field; geoip: is a set reference that goes in its array. Put geosite: in the domain array instead. Both types of set require the corresponding data files to be available to the core. The data files define the set names and contents; the core does not generate results dynamically from a name.

{
  "type": "field",
  "domain": ["geosite:cn"],
  "outboundTag": "direct"
}
{
  "type": "field",
  "ip": [
    "192.0.2.15/32",
    "2001:db8::15/128",
    "geoip:private",
    "geoip:cn"
  ],
  "outboundTag": "direct"
}

The 192.0.2.15 and 2001:db8::15 addresses above are reserved for documentation; replace them with the target service's address when applying the example. IPv4 /32 and IPv6 /128 prefixes each represent a single address. Shorter prefixes generally cover larger ranges. Don't add a large network range just to fix access to one address.

4. Match priority: put exceptions before broad rules

The core does not automatically rank an exact hostname above a domain set. Rules are evaluated from top to bottom in the rules array. If the first rule sends domain:example.com direct, a later proxy rule for full:api.example.com cannot override it. Put exceptions first, broader sets next, and the fallback last.

This is a routing snippet to merge into an existing configuration, not a complete client configuration. It assumes that outbounds already contains tags named proxy and direct, and that the referenced data sets are available. If your tags differ, update them to match; copying only the rules is not enough.

{
  "routing": {
    "domainStrategy": "IPOnDemand",
    "rules": [
      {
        "type": "field",
        "domain": ["full:api.example.com"],
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "domain": ["domain:example.com", "geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "geoip:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}
Test targetFirst matching ruleExpected outbound
api.example.com:443Rule 1: exact hostname exceptionproxy
www.example.com:443Rule 2: base domain and subdomainsdirect
192.168.1.20:80Rule 3: private address setdirect
Public destination not matched by the sets aboveRule 4: TCP/UDP fallbackproxy

This table shows how the configuration evaluates; it is not a network speed test. The example domains may not host real services, so use a known working target to verify a website. If you remove the final fallback rule, unmatched requests usually use the first outbound in the configuration. You can't generally say that unmatched traffic will always use the proxy or always go direct without seeing the full configuration.

5. domainStrategy: why IP rules may not match

When a request reaches the core, its destination may be a domain or an IP address. If only the IP is available, adding a domain rule will not restore the original hostname. Conversely, a request with only a domain usually needs the routing resolution strategy to provide an address before it can match an ip condition. That's why domainStrategy needs to be checked separately.

StrategyWhat happens during routingConfiguration notes
AsIsDoes not resolve the destination domain to an IP for routing matchesIP rules can still match when the destination is already an IP; this does not mean the outbound never resolves domains
IPIfNonMatchIf no rule matches the domain in the first pass, attempts to resolve it and match againIf an unconditional fallback matches in the first pass, this additional resolution is not triggered
IPOnDemandAttempts to resolve the destination domain when routing encounters a rule that requires an IPMay add DNS queries; consider both resolution latency and the DNS egress route

The previous section uses IPOnDemand so the third address-set rule can be checked before the final fallback. If you switch directly to IPIfNonMatch, a domain request may match the broad fourth rule first, preventing the intended address-based routing. This is not a GeoIP syntax error; the difference is when resolution is triggered.

Bottom line: identify what information the rule needs

For site-based routing, make sure requests include the hostname; for IP-based routing, choose an appropriate DNS resolution strategy. Check the DNS server, DNS query routing, and sniffing coverage separately—changing domainStrategy alone won't address them all.

6. Configure and verify rules in v2rayN

For everyday use, manage rules in the routing settings interface. v2rayN generates the runtime configuration, so direct edits to temporary JSON files may be overwritten when you restart the service or switch nodes. The steps below use a desktop interface with a 「Settings」→「Routing Settings」 menu; button locations may vary across versions, but you still need to check rule order and outbound mappings.

  1. Keep a copy of the existing configuration

    Open 「Settings」→「Routing Settings」 and note the active rule set and domain resolution strategy. Back up the current configuration before making changes; don't clear the default rule set.

  2. Add one rule

    In the target rule set, add an exact hostname condition such as full:api.example.com, then select the proxy outbound. Enter only the rule in the domain field; don't paste the entire routing object.

  3. Reorder the rules

    Move this exception above the relevant domain:, geosite:, or other broad rules. After saving, confirm that the main window has the edited rule set selected.

  4. Reconnect

    Restart the service or reload the configuration, then close the target page's existing connections and visit it again. Existing connections generally won't switch to a different outbound just because you changed a rule.

  5. Check the runtime logs

    In the core logs, check the destination hostname, destination port, and outbound tag. Start with a known working website before broadening the rule. If the log level doesn't show enough detail, temporarily set it to info or debug, then restore the previous level when you're done.

Test at least three types of requests: the exception hostname, a regular hostname under the same base domain, and a local network resource. The first two test the boundaries of the domain rule; the third checks whether a broad proxy rule is overriding direct access to private addresses. If no request appears in the logs, first check whether the app is using the current proxy entry point instead of changing the routing expression again.

7. Quick answers to common rule conflicts

Why does traffic still go direct when I added full?

Check whether a preceding domain:, geosite:, or catch-all rule already matches the hostname. Move the exact-host exception above broader rules, save, and test with a new connection. Also verify the outbound tag selected for that rule.

Why doesn't a rule with both domain and ip match?

In one field rule, both are required conditions. If either the domain or the address should match, split them into two rules with the same outbound. Keep them together only when you specifically need both conditions to apply.

Why do some sites still use the proxy with geosite:cn enabled?

First check the hostname used by the actual request; a page may load resources from different domains. Then check earlier rules, whether the data files loaded, and whether the set includes that domain. Try an explicit full: rule to verify the route, then confirm the actual outbound in the access log.

Does setting port 443 match every website?

No. It only restricts the destination port; traditional HTTP may use port 80, and other services may use custom ports. HTTPS can also use TCP or UDP. If you add network: "tcp", UDP requests won't match.

Will custom rules still work after a subscription update?

Node subscriptions and routing rules are separate parts of the configuration. After an update, check that your rule set is still selected and that the proxy outbound still points to a valid node. Don't use a subscription URL as routing configuration, or paste routing JSON into the subscription URL field.

Follow the same troubleshooting order each time: confirm the request reaches the core, confirm the hostname or address is available, find the first matching rule, then check whether the outbound can connect. Change one type of condition at a time to tell whether the result comes from rule boundaries, DNS policy, or the node's network.

Download v2rayNChoose an installer for your platform