Mihomo DNS Configuration: nameserver, fallback, and DNS Hijacking
Configure Mihomo DNS with nameserver, fallback, fallback-filter, and dns-hijack. Compare fake-ip with redir-host and use ready-to-adapt YAML examples.
How DNS configuration fits together: interception, resolution, and connections
When troubleshooting DNS issues with Clash Meta (mihomo), separate three steps: which resolver the application sends queries to, which upstream the core queries, and which rules handle the connection after an address is returned. Any of these can cause a site to fail to load. Changing only nameserver won't fix a system that isn't sending DNS requests to the core.
- Interception:
dns.listenopens a DNS listening port on the core; under TUN,dns-hijackcaptures matching DNS traffic. - Resolution:
nameserver,fallback, andnameserver-policydetermine which upstreams are queried and how results are selected. - Connection: Once an application gets an address, it connects to it. The core then handles the traffic according to the proxy mode, rules, and policy groups.
A system HTTP proxy usually doesn't capture DNS requests from every application. A browser's Secure DNS, Android Private DNS, or an app's built-in DoH may use a separate route. So “the system proxy is enabled” does not mean “all DNS lookups go through Mihomo.”
nameserver and default-nameserver: upstreams and bootstrap resolution
nameserver is the list of upstreams used for regular DNS queries. A plain IP address usually indicates standard DNS; https:// indicates DoH, and tls:// indicates DoT. Standard DNS commonly uses port 53, DoT defaults to 853, and DoH generally uses HTTPS on port 443.
If an upstream is specified as https://dns.alidns.com/dns-query, the core first needs to resolve dns.alidns.com. default-nameserver resolves hostnames used by DNS servers themselves. It's for bootstrap resolution, not “the default server for all queries.” Using an IP address here avoids relying at the outset on a hostname that hasn't been resolved yet.
| Field | Purpose | Common misconception |
|---|---|---|
listen | Set the local DNS listening address and port | The system will use it automatically once configured |
default-nameserver | Resolve hostnames used by DNS upstreams | It's the preferred resolver for every domain |
nameserver | Handle regular DNS queries | Multiple addresses are always tried one at a time in list order |
proxy-server-nameserver | Resolve hostnames for proxy servers | It handles every site accessed through a proxy |
nameserver-policy | Choose an upstream for matching domains | It directly determines which proxy a site connection uses |
Proxy servers may themselves use hostnames, which need to be resolved. Use proxy-server-nameserver to specify a reachable upstream and avoid the loop of needing a proxy connection to resolve the proxy's own address. This is separate from routing website connections and cannot replace connection rules.
fallback and fallback-filter: choosing results after parallel queries
Don't think of fallback as a traditional backup server that's only used after the primary DNS times out. In regular resolution paths that use fallback to select results, the core queries the relevant upstreams in parallel, then applies the filter conditions to decide whether to use the fallback result. Adding fallback can therefore send the same domain query to both sets of resolvers.
Three useful filter conditions
geoip: Enables location-based checks on returned addresses. Set the location code withgeoip-code. For example, withCN, a regular result that doesn't meet the location criteria triggers fallback selection. This check depends on GeoIP data.ipcidr: Uses the fallback result when a regular result falls within one of the listed address ranges. This matches IP ranges, not domain names.domain: Uses the fallback result directly for matching domains. In this example,+.github.commatches the root domain and its subdomains.
The complete DNS snippet below explicitly sets geoip: false and demonstrates only address-range and domain conditions, so GeoIP data updates aren't a factor in the initial setup. 0.0.0.0/8 and 240.0.0.0/4 are examples of filtering anomalous results. They aren't a complete list of poisoned addresses and can't detect every bad resolution.
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter-mode: blacklist
fake-ip-filter:
- localhost
- "+.lan"
- "+.local"
default-nameserver:
- 223.5.5.5
- 119.29.29.29
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
nameserver:
- https://dns.alidns.com/dns-query
fallback:
- https://cloudflare-dns.com/dns-query
fallback-filter:
geoip: false
ipcidr:
- 0.0.0.0/8
- 240.0.0.0/4
domain:
- "+.github.com"
This example assumes the listed upstreams are reachable from your network and routing setup. DoH encrypts DNS traffic, but encryption doesn't automatically route it through a proxy; the upstream connection's actual route depends on your configuration. If an upstream is unreachable, switch to a service you've confirmed works rather than adding several unknown addresses at once.
fake-ip and redir-host: different addresses returned to applications
enhanced-mode: fake-ip returns a mapped address for applicable DNS queries. When an application connects to that address, the core uses the mapping to recover the domain and apply the rules. The 198.18.0.1/16 range in the example is reserved for benchmarking; seeing a response from this range doesn't mean DNS has been poisoned.
redir-host returns the actual resolved address to the application, then uses the association between the domain and address to help handle the connection. This is closer to traditional DNS behavior, but domain association may be less direct than with fake-ip when IPs are shared, multiple domains point to the same address, or an application uses cached results.
| Aspect | fake-ip | redir-host |
|---|---|---|
| Address seen by the application | Usually a mapped address, except for filtered domains | The actual address returned by the upstream |
| Best for initial testing | TUN interception and domain-based routing rules | Compatibility cases where an application needs the actual address |
| What to check | Whether the connection returns to the core holding the mapping | Whether DNS and the connection can still be correlated |
Filters only change which address is returned
In this example, fake-ip-filter-mode: blacklist means matching entries won't receive fake-IP addresses. Adding local network suffixes to the filter prevents mapped addresses from being returned for those names, but doesn't guarantee they can be resolved. .local is commonly associated with mDNS; local devices may also be registered only with the router's DNS, where public DNS can't find them.
If a NAS name still won't resolve, first check whether it relies on mDNS or the router's DNS, then decide whether to add a local DNS policy. Don't work around the problem by filtering every domain. After switching modes, clear old DNS caches and reconnect so applications don't keep using addresses from the previous mode.
TUN dns-hijack: intercepting queries on port 53
dns-hijack belongs in the top-level tun section, not the dns section. The snippet below is for desktop clients that support the relevant TUN settings. TUN requires permission to create a network interface; a client may also manage these settings through service mode or a privileged helper.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
any:53intercepts matching UDP DNS requests on port 53 that enter the TUN.tcp://any:53adds TCP port 53 to cover standard DNS queries that use TCP.auto-routesets up the relevant routes automatically, but whether it captures traffic from a particular application depends on the system routes and client implementation.auto-detect-interfacedetects the outbound interface automatically. On systems with multiple network adapters or unusual routing, verify which interface is actually used.
“any” doesn't mean every DNS request on the network can be intercepted. Only traffic that enters the interception path can be handled. It also won't automatically convert browser DoH sent over HTTPS port 443 into standard DNS. DoT on port 853 isn't covered by either of the match entries above.
In the example, DNS listens on 127.0.0.1:1053, which is suitable for local testing. Standard system DNS settings often accept an address but not a custom port, so entering 127.0.0.1 sends queries to port 53, not 1053. TUN DNS hijacking and manually setting the system DNS are separate entry points.
Verify in order: listener, upstream, interception, and rules
Step 1: Check the effective configuration and listening port
After reloading the configuration, check the client logs for YAML parsing errors, unsupported fields, or port binding failures. Verify dns.enable, listen, and enhanced-mode in the effective configuration. Menu names vary between clients, so look for the runtime configuration or configuration preview—not just the original subscription.
On macOS, Linux, or any system with dig installed, send queries directly to port 1053. The first command tests UDP; the second tests TCP. These are verification commands, not claimed test results.
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp
In fake-ip mode, an unfiltered A query usually returns an address from the mapping range. This only confirms that the current DNS entry point returned an answer; it doesn't prove the remote website is accessible. Also check that the connection reaches the same core and that the proxy node can establish a connection.
Step 2: Distinguish an unreachable upstream from traffic that isn't being intercepted
- Queries sent directly to port 1053 also time out: First check that the listener started successfully, then look for upstream connection errors. If needed, temporarily keep just one nameserver that you've confirmed is reachable to narrow down the cause.
- Port 1053 returns an answer, but the application still uses another DNS server: Check that TUN is enabled and its routes are active, and see whether the browser's Secure DNS is using a separate path.
- The domain resolves, but the website still won't load: Check the connection logs for the matched rule, selected policy group, and node errors. Don't keep changing DNS at random.
- Only local network names fail: Check the router DNS or mDNS resolution path and whether a dedicated local network policy is needed.
Step 3: Clear caches and test again
On Windows, run ipconfig /flushdns in a terminal. On macOS, run the two commands below in order; the second requires administrator authorization. Browsers and apps may have their own caches. After flushing the system cache, close existing connections and try again.
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
To check whether DNS queries are still going to an unexpected server, observe what the system, browser, and core actually do. Seeing a DoH address or visiting a DNS leak test site once isn't enough to explain how every process resolves names. Assess fallback's parallel queries, browser DoH, and background system requests separately.
Merging and updating the configuration
Don't define two top-level dns: sections or two tun: sections in the same YAML file. Duplicate keys may be rejected by the parser or cause one section to overwrite the other. Merge the example fields into the existing sections and check the client's override order. After a subscription update, verify that the runtime configuration still includes your changes.
- Start with a working baseline: Confirm that one upstream is reachable and local queries to port 1053 work before adding fallback and TUN interception.
- Then handle specific domains: Use nameserver-policy when you need domain-specific DNS resolution; edit rules when you need connection routing. Test each separately.
- Handle IPv6 last: The example's
dns.ipv6: falsedisables AAAA answers from DNS. It doesn't disable IPv6 across the operating system or prevent applications from using IPv6 addresses they already have. - Keep a rollback plan: If all connectivity is lost, first disable TUN and restore the original system DNS and proxy settings, then load your backup. Don't keep layering on unknown settings.
For more on how rules and TUN settings work together, see the DNS configuration guide and TUN configuration guide. The key to troubleshooting is to change one layer at a time: first confirm the request reaches the core, then confirm the upstream responds, and finally check the connection rules. This makes it clear which problem each change actually fixes.