mihomo DNS Configuration: nameserver, fallback, and DNS Hijacking
Learn what each mihomo DNS field does, including enhanced-mode, nameserver, fallback, fallback-filter, and dns-hijack, with ready-to-use examples for common setups.
First, trace where DNS requests go
First, distinguish DNS resolution from connection routing. DNS translates domain names into IP addresses; proxy rules determine whether a connection goes direct or through a proxy. Successful resolution does not mean traffic is being proxied, and enabling a system proxy does not mean all system DNS queries go through mihomo.
Next, check which core your client uses. mihomo is the actively maintained successor to Clash Meta. The GUI client generates configuration, starts the core, and manages system networking. This guide covers mihomo fields; not every example will work with the older original Clash. Check the core version in your client’s About or core information page, or run the commands below to record the version and validate the configuration.
mihomo -v
mihomo -t -f config.yaml
Work through the checks in order. Changing only the layer where the problem occurs makes it easier to find the cause than replacing DNS servers, nodes, and rules all at once.
- The app sends a query: Browsers may use their own secure DNS; command-line tools usually use the system resolver.
- The request reaches a resolver: It may go to your router, the system DNS resolver, or mihomo’s DNS listener.
- The core selects an upstream: mihomo chooses a DNS server according to its resolution strategy and filters the response based on your configuration.
- The app opens a connection: The core then selects an egress route for the connection according to the proxy rules.
Understanding the dns section: configure the listener, mode, and upstreams separately
Start by understanding each field’s role. The ports in the table are examples, not defaults for every client. Check the active configuration on your system.
| Field | Purpose | What to check |
|---|---|---|
enable | Enable the core DNS module | Setting this to true is not enough; requests must also reach the core |
listen | Set the address that listens for DNS queries | 127.0.0.1:1053 accepts connections from this machine only |
enhanced-mode | Choose an enhanced DNS mode | Common options are fake-ip and redir-host |
default-nameserver | Resolve the hostnames of DNS upstream servers | Used to bootstrap the resolution chain; it is not the default upstream for all domain lookups |
nameserver | Configure regular DNS upstreams | The list order does not simply represent a failover sequence |
fallback | Provide upstreams whose results can be considered as fallback answers | Not just an address used after the primary upstream times out |
fallback-filter | Decide when to use fallback answers | Can use domain names, GeoIP, and IP ranges as criteria |
Choosing between fake-ip and redir-host
Choose a mode based on compatibility needs. fake-ip assigns virtual addresses to eligible queries and stores the domain-to-IP mapping in the core. When an app connects to one of these addresses, the core can recover the domain and handle the connection accordingly. The 198.18.0.1/16 in this example defines the virtual address pool; it is not a server address to configure in public DNS.
If an app requires real resolved addresses, consider adding a fake-ip-filter entry for specific domains or testing with redir-host, which returns real resolved addresses. After switching modes, flush system and app DNS caches and restart existing connections. Otherwise, an app may keep using an old address, making it seem as though the change did not take effect.
Scenario 1: Validate nameserver with a minimal configuration
Start with one set of upstreams and add fallback only after basic queries work. The standalone diagnostic configuration below uses the local mixed proxy port 7890 and DNS port 1053. It has no subscription nodes and its final rules send all traffic direct. It is for testing the DNS path, not a complete proxy setup.
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
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
rules:
- MATCH,DIRECT
If you’re keeping your current subscription, merge only the dns section from this example. Don’t replace your existing routing rules with the example rules. YAML must not contain two dns: keys at the same level; use spaces for indentation. After the configuration passes validation, reload it in the client.
DoH and bootstrap resolution
Check the protocol used by each upstream. https://dns.alidns.com/dns-query is DoH (DNS over HTTPS); upstreams specified as plain IP addresses typically use traditional DNS. DoH encrypts queries between your client and that resolver. It does not mean subsequent connections to websites are routed through a proxy.
Make sure the upstream server’s hostname can be resolved before resolving other domains. In this example, the IP addresses in default-nameserver bootstrap resolution for the DoH server hostname, avoiding a loop where you need to reach DoH before you can find the DoH server’s address. Whether a public resolver is reachable depends on your network; no single address works everywhere.
Scenario 2: Configure fallback and fallback-filter
Understand how fallback answers are selected before adding servers. Don’t treat fallback as simply a “second DNS server” like the setting on a typical network device. Regular and fallback upstreams may both take part in resolution. Whether a fallback answer is used depends on filtering conditions, resolution status, and other factors—not simply on waiting for the first server to time out.
This snippet replaces the entire dns section from the previous configuration. It demonstrates using GeoIP to evaluate results from regular upstreams, and listing 240.0.0.0/4 as an IP range that triggers fallback selection.
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
fallback:
- https://cloudflare-dns.com/dns-query
fallback-filter:
geoip: true
geoip-code: CN
ipcidr:
- 240.0.0.0/4
Check each filter condition
- Check the geographic filter:
geoip: trueenables IP geolocation checks.geoip-code: CNmeans fallback answers are preferred when a regular result does not match the specified region. This is not a proxy rule that sends all domains in mainland China direct. - Check the IP ranges:
ipcidris a list of IP ranges. If an address returned by a regular upstream matches one of these ranges, fallback selection is triggered. Don’t add every private network range without a reason; doing so could break access to internal services. - Check data dependencies: GeoIP checks require usable geolocation data. If the data is missing or outdated, first address any loading errors in the core logs rather than repeatedly switching DNS servers to mask the cause.
- Check both connections: The fallback DoH server must also be reachable. A working primary upstream does not prove that the fallback upstream can connect.
To use specific DNS upstreams for certain domains, look into nameserver-policy, which lets you assign resolvers by domain, instead of continually expanding the fallback filter ranges. Corporate domains in particular should use your organization’s DNS; public resolvers may not know about internal records.
Check the egress route for DNS upstream connections separately from the route for website connections. They are two different things. To make DNS upstream connections follow routing rules, you can configure respect-rules and, as required by your core version, proxy-server-nameserver to resolve proxy server hostnames. This avoids a dependency loop between proxy connections and DNS resolution. The minimal example in this guide does not enable these advanced options.
Scenario 3: Use TUN dns-hijack to intercept port 53
Put the field at the correct level. dns-hijack belongs in the top-level tun section, not the dns section. TUN is a virtual network interface through which the core handles routed IP traffic. DNS hijacking here means redirecting matching DNS queries to the core’s DNS module.
Keep the dns section from earlier in your existing configuration, then merge in the tun section below. Before enabling it, make sure the client has the required administrator or service permissions, and avoid having another VPN take over the default route at the same time.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
Understand the two hijack rules. any:53 matches UDP queries on port 53 routed through TUN; tcp://any:53 adds TCP queries on port 53. These specify what to capture—they do not mean you should change the DNS listener address to any:53. Whether queries are captured also depends on system routing, network interfaces, and platform limitations.
Know what gets intercepted
- Check browser secure DNS: Browser DoH usually uses HTTPS on port 443. Intercepting port 53 does not automatically route it through the core’s DNS module.
- Check encrypted DNS: DoT (DNS over TLS) usually uses port 853 and is not covered by either of the rules above.
- Check LAN destinations: Whether DNS traffic to your router enters TUN depends on your routing setup. Don’t assume all local network queries will be captured.
- Check listener exposure: For personal computer testing, prefer a loopback listener. Don’t expose DNS on every network interface just to make TUN work.
Validate resolution, interception, and routing in order
Test the core listener first, then test everyday browsing. This separates “the DNS module itself isn’t responding” from “system queries aren’t reaching it.” The commands below show how to test; they do not report measured speeds for any public resolver on your network.
Step 1: Query port 1053 directly
On Linux or macOS with dig installed, run the two commands below to test UDP and TCP separately. On Windows, use the nslookup command below and specify the port.
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp
nslookup -port=1053 example.com 127.0.0.1
Check for timeouts first, then inspect the answer type. With fake-ip enabled, eligible A queries returning addresses from the virtual address pool is expected; it does not mean the upstream returned an incorrect IP. To compare real DNS answers, temporarily switch to redir-host, reload the configuration, flush the cache, and repeat the same queries.
Step 2: Query through the system’s default path
nslookup example.com
Compare an explicit query with a default query. If port 1053 works but default queries time out, first check system DNS, TUN routing, and security software instead of immediately changing nameserver. When hijacking is enabled, the DNS server name shown by a command may still be the original destination. Check the core logs to confirm what actually handled the request.
Step 3: Flush caches, then check the connection route
On Windows, run ipconfig /flushdns. On Linux with systemd-resolved, run resolvectl flush-caches. Then restart your browser or close existing connections, and check the client’s connections panel for the domain, matched rule, and egress route. Browser caches and reused connections may not be cleared when you flush the system cache.
For more clues, temporarily set log-level to debug, reproduce the issue once, then change it back to info. Before sharing logs, remove subscription URLs, credentials, and sensitive domain names. Logs can help identify upstream timeouts, listener failures, and routing issues, but don’t publish your complete active configuration.
Common DNS issues: narrow down the cause before making changes
| Symptom | Check first | Next step |
|---|---|---|
| Queries to local port 1053 time out | Whether DNS is enabled, the port is in use, and the configuration was reloaded | Check the startup logs, then run a configuration syntax check |
| Port 1053 works, but regular queries fail | System DNS path and TUN routing | Confirm the request reaches the core before changing fallback upstreams |
| Browser and terminal return different results | Browser secure DNS, separate caches, and proxy extensions | Temporarily use the same resolution path, then query the same domain |
| Internal sites are unreachable | Public DNS lacks internal records; virtual IP compatibility | Assign a corporate resolver to internal domains and add a fake-ip filter if needed |
| Queries slow down after enabling fallback | Fallback upstream connectivity and filter match scope | Return to a single-upstream baseline, then restore filter conditions one at a time |
| Settings revert after a subscription update | The client-generated configuration overwrote manual changes | Move changes to a supported override configuration and verify the final result |
To wrap up, ask three questions: Did the request reach the core? Did the upstream return the right answer? Did the subsequent connection match the expected rule? Change one condition at a time and keep the configurations and query results from before and after. That’s how to tell which setting actually fixed the issue when troubleshooting nameserver, fallback, or dns-hijack.