Start by separating three paths: interception, resolution, and connection routing

Enabling DNS does not mean every app is using this DNS configuration. To troubleshoot mihomo DNS, break the process into three steps: whether the app's queries reach the core, which upstream the core queries, and which proxy rule handles the connection after resolution. Any of these can fail and make a site unreachable, but changing one setting rarely fixes all three.

  • Interception: dns.listen provides a DNS listener; under TUN, dns-hijack redirects matching DNS traffic to the built-in resolver.
  • Upstream selection: Fields such as nameserver, nameserver-policy, and fallback determine the resolution path and how results are selected.
  • Connection routing: rules determine whether site connections go direct or through a proxy. With respect-rules enabled, connections to DNS upstreams are routed by the rules too.

This guide is for clients running the mihomo core. Original Clash, Premium, and Meta cores from different eras do not support exactly the same fields. Check the core details in your client or its startup logs before editing the active configuration; the GUI client's version number is not a substitute for the core version.

default-nameserver: Resolve the DNS server's hostname first

When an upstream is set to https://dns.alidns.com/dns-query, the core must first resolve dns.alidns.com to an IP address before it can establish an HTTPS connection. default-nameserver handles this initial lookup; it is not the DNS server used by default for every website. The names are similar, but the troubleshooting steps are very different.

DNS bootstrap resolution example
dns:
  enable: true
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query

The two IP addresses above are used for bootstrap resolution. DNS servers specified as plain IP addresses typically use UDP port 53; they do not automatically become encrypted just because the next upstream uses DoH. If your network requires encrypted bootstrap queries too, choose an IP-based encrypted endpoint supported by your core that does not depend on another hostname lookup, and make sure its certificate and connection requirements are compatible.

nameserver and fallback: fallback isn't used only after the primary server times out

nameserver provides the standard resolution results

nameserver is the set of primary upstreams used when no more specific DNS policy applies. Multiple addresses can improve resilience, but don't assume they are queried strictly in order, with the second used only after the first fails. The core may query them in parallel, and DNS caching may mean the upstreams aren't contacted at all for a given request.

DoH typically uses TCP port 443, while DoT typically uses TCP port 853. Encryption protects the query in transit; it does not determine which proxy node the connection uses. Being able to open a DoH URL in a browser does not prove mihomo can reach it with the current routing, certificates, and proxy configuration.

fallback works together with result filtering

Don't think of fallback as a traditional backup server that's used only after a network timeout. When configured, the core selects results in conjunction with fallback-filter, and related queries may run in parallel. Seeing queries reach both upstreams during troubleshooting doesn't mean the configuration was loaded twice.

FieldPrimary roleDon't confuse it with
default-nameserverResolves the hostnames of DNS upstreams during bootstrapThe default upstream for every website
nameserverStandard domain name resolutionA list processed in strict order
fallbackProvides another set of results for filteringA backup server queried only after a timeout
fallback-filterControls when fallback results are selectedProxy rules or firewall rules
dns-hijackIntercepts matching DNS traffic on the TUN pathA switch that decrypts apps' private DoH traffic

fallback-filter: filter by region, IP address, and domain

The example below combines an upstream in mainland China with another public DoH resolver to demonstrate filtering. It's meant to explain the fields, not to imply every network can connect directly to every endpoint. If the fallback upstream is unreachable, fix its connectivity or routing first; then check whether its responses are trustworthy.

Merge into the existing dns section
dns:
  enable: true
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query
  fallback:
    - https://1.1.1.1/dns-query
    - https://dns.google/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 240.0.0.0/4
    domain:
      - '+.google.com'
  • geoip: true and geoip-code: CN: In general, if the primary upstream returns an address outside the specified region, the fallback result is preferred. This check depends on the GeoIP data used by the core.
  • ipcidr: If an address returned by the primary upstream matches one of the listed ranges, fallback result selection is triggered. The 240.0.0.0/4 range in this example is reserved address space, not a comprehensive list of problematic addresses.
  • domain: Matching domains use the fallback path directly. The example +.google.com matches the domain and its subdomains. Quoting the string can help avoid YAML parsing ambiguity.

Geographic filtering is a policy, not mathematical proof of DNS pollution. A domain outside mainland China may use a CDN inside it, and a service based in mainland China may return an address outside it. Stale GeoIP data can also cause false positives. If you only need to route a few known domains to specific resolvers, nameserver-policy is usually more straightforward than stacking complex geographic conditions. Once that policy matches, don't assume the query must also go through the general fallback process described here.

If you don't need geographic checks, set geoip: false explicitly and keep only domain and address conditions you can justify. Don't add a long list of private IP ranges just to silence a timeout log; an internal site returning a private IP is often the correct result.

respect-rules: route DNS upstream connections according to rules

respect-rules: true controls how the core routes connections to DNS upstreams; it does not enable domain rules. Before turning it on, configure proxy-server-nameserver to resolve proxy node hostnames and avoid a circular dependency: resolving a node requires the proxy, but connecting to the proxy requires resolving the node.

Add to or edit the existing dns mapping
dns:
  respect-rules: true
  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query

This is an incremental snippet; don't use it to replace your entire DNS configuration. Keep the existing default-nameserver for bootstrap resolution, your regular upstreams, and other settings. Make sure the upstream used to resolve node hostnames is reachable during startup. Configuring a resolver for proxy nodes does not configure resolvers for all your regular domains.

  1. First, confirm the proxy nodes are reachable and that every policy group referenced by your rules exists.
  2. Check which rule matches the DNS server's hostname or destination IP. If a rule sends the upstream over an unreachable route, enabling this setting will only make the failure more consistent.
  3. Check the outbound route selected for upstream connections in the logs, then test a website connection. A node latency indicator alone doesn't tell you whether DNS is working.

dns-hijack under TUN: intercept DNS traffic entering the virtual interface on port 53

Setting only dns.enable: true does not change every DNS resolution path on the operating system. In TUN mode, dns-hijack can send matching DNS traffic entering the TUN interface to the core. The snippet below is a basic configuration to merge into an existing mihomo setup; keep your existing proxies, policy groups, and rules.

Basic TUN and fake-ip configuration
dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53

any:53 handles UDP DNS, while tcp://any:53 adds TCP DNS. You don't need to change the destination port to the local port 1053 first; interception sends matching traffic to the built-in DNS resolver. listen is a separate listener for explicit queries. Keeping it on a loopback address avoids unintentionally exposing the resolver to your LAN.

Here, 198.18.0.1/16 is used for fake-ip mapping. A query returning a synthetic address in this range is expected; it doesn't mean the upstream actually returned that address. The core uses the mapping to recover the domain and handle the connection. If an app needs a real IP, consider fake-ip-filter for that specific use case instead of treating the entire reserved range as a DNS failure.

  • Desktop: TUN may require administrator privileges, service mode, or specific network permissions, depending on the client and operating system.
  • Android: VPN authorization may conflict with other VPN apps, and the system's Private DNS setting may change the resolution path.
  • Browsers: Built-in Secure DNS sends queries over HTTPS on port 443, so don't expect interception on port 53 to capture them automatically.
  • LAN and IPv6: Check separately for traffic that doesn't enter the TUN interface, excluded routes, and traffic using other interfaces.

The example's dns.ipv6: false controls how DNS handles AAAA queries; it does not disable IPv6 in the operating system or provide complete IPv6 leak protection. Local DNS services on Linux, LAN resolution on macOS, and Android VPN implementations may also have their own limitations. To confirm interception is working, inspect the actual requests.

Verify each stage with commands: check the listener, then interception, then the upstream

Step 1: Check the configuration and local listener

Back up your existing configuration before editing. When running the core independently, you can use the commands below to check it. For a GUI client, use the core and working directory it actually runs so you don't validate a different file with the same name.

Terminal: validate the configuration and run an explicit DNS query
mihomo -t -f config.yaml

dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp

The first two queries test UDP and TCP access to the listener on port 1053. On Windows without dig, run nslookup -port=1053 example.com 127.0.0.1. A fake-ip response proves only that the request reached the resolver and got a mapping; it doesn't prove the specified DoH server successfully returned a real IP.

Step 2: Check whether TUN intercepts port 53

Terminal: compare UDP and TCP interception
dig @8.8.8.8 example.com A
dig @8.8.8.8 example.com A +tcp

The explicitly specified 8.8.8.8 is the test destination; if TUN intercepts the request, it may not be the upstream that actually receives the query. Use core logs and the fake-ip response to check. Don't rely only on the SERVER line in dig output, which may still show the destination originally specified by the program.

Step 3: Confirm resolution and website connectivity

  1. Temporarily set the log level to debug and capture the domain, error, and upstream address for a single failed request. Hide subscription URLs and node credentials before sharing logs.
  2. Clear the client's DNS cache or restart the core, then test a domain that hasn't been queried yet. On Windows, clear the system cache with ipconfig /flushdns; this does not clear browser or core caches.
  3. To inspect the real response, temporarily switch to enhanced-mode: redir-host in a controlled test and query again after restarting. Restore the original configuration when you're done to avoid confusion from stale fake-ip mappings cached by apps.
  4. Finally, visit the site and check which connection rule applies. If DNS succeeds but HTTPS times out, investigate the proxy exit, connection routing, TLS, and MTU instead of repeatedly switching resolvers.

The commands in this guide are for reproducing and isolating issues; they are not latency benchmarks for any particular network. To compare performance, record both cold-cache and warm-cache results on the same network. Comparing only the second query often measures how quickly the cache responds.

Common issues and a safe rollback sequence

SymptomCheck firstWhat to do
Local query to port 1053 times outConfiguration loading, port conflicts, core logsRestore the listener first, then check the upstream
Port 1053 works, but apps still use system DNSTUN permissions, routes, browser Secure DNSCheck whether requests fall within the interception scope
Everything times out after enabling respect-rulesNode hostname resolution and outbound rules for DNS upstreamsSet up a separate resolution path for proxy nodes
Only some domains have issuesPolicy matching, fallback conditions, cacheTest domains one at a time; don't change the entire section at once
Issue returns after a subscription updateEffective configuration and merged overridesPut the changes in a persistent override

To roll back, first restore a setup with one reachable upstream and complex filtering disabled, then confirm standard resolution works. Next enable TUN interception, and finally add fallback and rule-based routing. Keep a copy of the configuration and query results at each step. More fields don't mean more reliable resolution; a maintainable setup is one where you can explain why each request went to a particular upstream.