This guide is for users who can already connect to a proxy node and want to fine-tune DNS routing. First, identify whether DNS queries are handled by the app, the operating system, or the core. Then route mainland China domains to a preferred local resolver and other queries to remote DoH, and verify the path in the logs. These examples are configuration snippets to merge into your existing setup; they do not take over system DNS or replace a working proxy outbound.
1. DNS routing vs. connection routing
DNS routing determines which resolver looks up a domain; connection routing determines which outbound carries the site connection. They’re related, but they aren’t the same rule. Routing a mainland China site directly doesn’t guarantee it uses a mainland China DNS resolver. Routing a DNS server through a proxy doesn’t automatically send the site connection through that proxy.
This sequence describes a typical flow when the core handles DNS; not every request passes through every step. If a browser resolves a domain to an IP using its own secure DNS before passing the IP to the proxy, the core may never see the original DNS query. Conversely, when an app passes a domain to a SOCKS proxy, the domain may be forwarded to the proxy server for resolution there.
- System resolution: The app calls the operating system’s resolver. Results are typically affected by the network adapter’s DNS settings, the system cache, and the local network.
- Core resolution: V2Ray or Xray’s built-in DNS may be used when routing decisions or outbound connections require an IP address.
- App-level resolution: A browser’s built-in DoH can bypass system DNS, so check it separately.
- Server-side resolution: When a domain is sent through a VMess or VLESS outbound to a remote server, the server may resolve it. This is not directly controlled by the local
dns.serverssetting.
2. What servers, domains, and expectIPs do
dns.servers is the list of DNS resolvers available to the core. Entries can be simple addresses or objects with domain-matching conditions. An object’s domains field selects a preferred resolver for matching domains; expectIPs checks whether returned addresses fall within the expected ranges. It is not a connection-routing rule or proof that a DNS response is authentic.
| Field | Value used here | What it does |
|---|---|---|
servers | Mainland China UDP DNS and remote DoH | Defines the resolvers available to the core. |
address | 223.5.5.5 | In this example, a plain IP address is used for a UDP DNS query. |
domains | geosite:cn | Prefer this resolver for matching domains; the corresponding domain data file must be available. |
expectIPs | geoip:cn | Filters results against an address set. A mismatch may reject the result and trigger another attempt. |
skipFallback | true | This resolver is excluded from ordinary fallback queries but can still be selected by its own domain rules. |
queryStrategy | UseIPv4 | This example requests IPv4 addresses only, making it easier to rule out IPv6 as a variable. |
geosite:cn is a domain category in a data set, not a catch-all for domains ending in .cn. geoip:cn also depends on the IP data file in use. Cross-region CDNs, corporate networks, and data file updates can all affect the result. So a domain associated with mainland China returning an overseas IP does not, by itself, mean the response was poisoned.
Bottom line: verify the domain category before tightening address filters
If a mainland China site stops resolving after you add expectIPs, temporarily remove the restriction and compare the returned addresses. If they’re legitimate CDN results, set a resolver specifically for that domain rather than repeatedly switching nodes to work around a classification issue.
3. Configuration: prefer mainland China DNS, use remote DoH for other queries
The basic setup below prefers a mainland China resolver for domains in the mainland China category and uses remote DoH for other queries. The first entry is a public resolver in mainland China, not a home router address. If you need to resolve internal ISP domains, specify the actual DNS server for that network. The second entry uses an IP-based DoH address, avoiding a separate bootstrap lookup for the DoH server’s hostname.
{
"dns": {
"queryStrategy": "UseIPv4",
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn"
],
"expectIPs": [
"geoip:cn"
],
"skipFallback": true
},
"https://1.1.1.1/dns-query"
]
}
}
This is not a complete config.json. Merge the dns object into your existing top-level configuration; don’t add duplicate keys to a JSON object. If DNS settings already exist, edit that section instead of pasting both snippets in sequence. JSON does not allow explanatory comments.
- Make sure you’re running a V2Fly or Xray core that supports these fields, and check the current core startup log. The client name and core version are not the same thing.
- Make sure the core can read domain and IP data files that include the
cncategory. If data is missing, resolve the loading error first. - Keep your existing
inboundsandoutbounds, merge in the DNS settings, reload the configuration, and check the error log. - Start by testing a few known domains, then expand the matching rules gradually. If your network needs IPv6, adjust the query strategy only after verifying dual-stack connectivity.
4. Route DNS queries through the right outbound
Adding a DoH address specifies the query protocol, not the network route. Built-in DoH using a standard https:// URL follows the core’s routing rules. If the default outbound is direct, remote DoH may connect directly. Don’t confuse this with local resolution modes that bypass normal routing, or assume that encryption means traffic is already going through a proxy.
The routing snippet below assumes you already have outbounds tagged direct and proxy. Replace these with the actual tag values in your configuration, or define the corresponding outbounds first. The example matches exact IPs and ports for DNS connections, so it won’t route all traffic to those addresses through the same rule.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["223.5.5.5"],
"port": "53",
"network": "udp",
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["1.1.1.1"],
"port": "443",
"network": "tcp",
"outboundTag": "proxy"
}
]
}
}
Merge these two rules into your existing routing.rules, placing them before any broad rule that could match first. Rules are evaluated in order; once an earlier rule matches, later DNS-specific rules won’t apply. This snippet routes resolver connections only; it does not configure full site routing.
IPIfNonMatchmeans the core may resolve a domain before trying IP rules when no domain rule matches. If a domain already matches a proxy rule, the local built-in DNS may not be used.- Proxy nodes specified by domain names also need bootstrap resolution. Avoid a loop where connecting to DoH requires the proxy, while establishing the proxy itself depends on that same DoH resolver.
- This guide uses a DoH address in numeric IP form, but TLS certificate verification must remain enabled. Don’t disable certificate checks to work around connection failures.
- If your current network can’t reach the remote DoH server, verify the proxy outbound first, then revisit DNS settings. Changing
domainsalone won’t fix an outbound connectivity issue.
5. Verify the setup in v2rayN and Android clients
In v2rayN, the client often generates the standard node configuration for you. Direct edits to a temporary config in the runtime directory may be overwritten when you switch nodes or restart. Use the DNS settings or custom configuration entry point provided by your version, then inspect the config it generates. v2rayNG uses the Xray core, while v2flyNG uses the V2Fly core. Client options for remote DNS, VPN, and routing don’t necessarily map directly to native JSON fields.
- Record a baseline: Save your current configuration and note the active node, local listening ports, system DNS, and browser secure DNS status. Change one DNS setting at a time.
- Check the proxy entry: These commands assume a SOCKS inbound is listening at
127.0.0.1:10808. If the client shows a different port, update the commands first; don’t assume this is the default for every version. - Compare the paths: Test both local app-level resolution and requests that pass the domain to the proxy. Different results mean you should investigate where resolution is happening.
- Check the logs: Temporarily set
log.logleveltoinfoand compare DNS and outbound entries against the request timestamps. Log details vary by core; usedebugbriefly if needed, then restore the original level.
curl --socks5 127.0.0.1:10808 -I https://www.qq.com
curl --socks5-hostname 127.0.0.1:10808 -I https://www.qq.com
nslookup www.qq.com 223.5.5.5
The first command usually has curl resolve the site domain locally. The second passes the domain to the SOCKS proxy, and where it’s resolved depends on core routing and the outbound. So a successful second command alone doesn’t prove the local built-in DNS was used. The third queries a specified public DNS server; it’s only a resolver connectivity check and doesn’t prove that dns.servers is working. In Windows PowerShell, use curl.exe if you run into command alias differences.
Bottom line: verify the configuration by checking the query path, not just whether a site opens
After making changes, restart the relevant apps and wait for or clear the appropriate caches, then test again. If the logs don’t show the expected DNS activity, first confirm that the request reaches the core. A site opening or a one-off change in latency isn’t proof that DNS routing is working.
6. DNS poisoning prevention and common issues
Preventing DNS poisoning depends on how queries are transmitted, whether you trust the resolver, where results are used, and how fallback works. DoH can protect traffic between the client and the DoH resolver, but it won’t fix incorrect domain classification, an unreachable proxy outbound, or app-level DNS. expectIPs only restricts address ranges; it neither encrypts DNS traffic nor detects every false response.
Why can’t I reach mainland China sites after adding expectIPs?
Temporarily remove expectIPs from that resolver, reload the configuration, and look up the same domain again. If it returns a legitimate overseas CDN address, adjust the domain’s resolution strategy or check the IP data file instead of forcing every result to fall within mainland China address ranges.
Why do I still see local DNS requests after setting up remote DoH?
First identify which process is making the request. Browsers, system services, and apps that don’t use the proxy may resolve domains independently; proxy node hostnames may also need bootstrap resolution. Check system DNS, browser secure DNS, and the client’s DNS takeover settings—not just the dns section.
Web pages load slowly. Do I need more DNS servers?
First separate DNS lookup time from TCP connection and TLS handshake time. Use one preferred mainland China resolver and one reachable remote DoH server as a baseline, then check timeouts and fallback logs. Adding several unreachable resolvers can increase delays and spread queries across more servers.
Why did my JSON changes disappear after switching nodes?
The client probably regenerated its runtime configuration. Save your changes through the DNS settings or custom configuration entry point supported by the client, then check the generated config after switching nodes. A subscription updates node details; it doesn’t automatically preserve manual edits to a temporary config.
Can I use IPv4 only long term?
UseIPv4 is useful for ruling out dual-stack issues, but it disables IPv6 address lookups. If both your network and proxy outbound have reliable IPv6 connectivity, try UseIP and check IPv4 and IPv6 routing and app behavior separately.
Keep three verifiable details: where each domain is resolved, which outbound carries the DNS connection, and where queries fall back if resolution fails. For an overview of how top-level settings fit together, see the configuration reference. If you have questions about proxy, core, or routing terminology, start with the glossary.