Linux Clash DNS Issues: Fix systemd-resolved Conflicts (2026 Guide)

You installed Clash or Mihomo on a Linux desktop, flipped on system proxy or TUN, and now pages stall, name resolution errors appear in the terminal, or domestic and foreign sites behave as if they follow different rulebooks. On modern distributions, systemd-resolved is often the first actor in the chain: it runs a stub resolver on 127.0.0.53, manages /etc/resolv.conf (frequently as a symlink), and competes for UDP and TCP port 53 on the loopback address when your proxy core also wants a local DNS listener. Separately, a fake-ip profile can look perfect in the UI yet fail in applications that still query systemd-resolved directly, because two different resolvers are answering the same name with different data. This guide is a stepwise checklist for that class of failure—stub resolver and resolv.conf first, then Clash DNS mode and fake-ip behavior, then port 53 and service logs—so you can reproduce, narrow, and fix without reinstalling the distribution.

How this differs from “GEOIP China” and split-routing tutorials

Other articles on this site cover GEOIP bypass lists, WSL2 shared proxies, and Docker-aligned exit paths. Those matter after DNS and local listeners agree on a single story. This page is narrower: the Linux stub resolver stack, /etc/resolv.conf indirection, and the interaction between systemd-resolved and a Clash-side DNS port—often the reason “everything worked until I turned the client on.” If you are still choosing capture mode, the TUN mode deep dive explains when transparent capture helps; if you are on Ubuntu and need install context first, see Clash Verge on Ubuntu 24.04: subscription and systemd before you tune DNS. For the broader rules vocabulary, the Clash tutorial on this site is still the right baseline.

Symptom map: what “DNS broke after Clash” usually means

Users describe overlapping experiences: some sites only load in the browser after a long pause; curl reports “Could not resolve host” while a GUI app still works; domestic CDNs are fast and international hostnames time out, or the opposite; reboot makes the issue disappear until the client starts. Those patterns rarely come from a single “bad node.” They more often come from two resolvers in play, a listener bind failure you never saw in the main window, or a fake-ip mapping that the OS stub layer never uses. The checklist below is ordered so the most evidence-rich checks run first: what the OS is configured to use, what is listening where, and only then which YAML knobs move.

Step 1 — Read the real resolver: systemd-resolved and resolv.conf

On Fedora, recent Ubuntu, Debian with resolved enabled, and many Arch installs with the standard systemd stack, the OS does not read arbitrary upstreams from a hand-edited /etc/resolv.conf the way a static server might. systemd-resolved listens on 127.0.0.53 and exposes a “stub” to applications through /etc/resolv.conf—commonly a symlink to /run/systemd/resolve/stub-resolv.conf with nameserver 127.0.0.53. That design is healthy for laptops moving between coffee-shop Wi-Fi and home Ethernet; it is also a common friction point for proxy DNS because every libc resolver query hits the stub first.

Run a quick orientation (no Clash change required yet):

# Shows whether resolved is the active path and the DNS servers it knows
resolvectl status

# If your distro provides it, also check per-link DNS
resolvectl dns

# See where resolv.conf actually points
readlink -f /etc/resolv.conf

Write down: per-interface DNS servers, DNS domain routing (split DNS) if your workplace uses it, and whether LLMNR or Multicast DNS show up. Corporate VPNs sometimes push internal domains through resolved; a proxy that bypasses the VPN for “foreign” names can still look broken if the OS prefers a corporate internal suffix for short hostnames. You are not fixing that policy here—you are making the visibility visible so you do not spend an evening toggling outbounds for a search path problem.

What you want to notice in resolvectl status

Look for link-specific DNS versus Global. A laptop on Wi-Fi may show a different upstream than Ethernet. If Clash is supposed to be the only path for some names, the stub must ultimately forward into the core’s DNS or the application must talk to the core; half-configured “just set nameserver 127.0.0.1 in resolv.conf” blog posts can leave resolved still authoritative on 127.0.0.53 with your edit ignored. That mismatch is a prime cause of “it works in one app, not in another”: some stacks query glibc through the stub; others (containers, some language runtimes) follow different code paths or cache differently.

Step 2 — Inventory listeners: who owns UDP/TCP 53 and the Clash DNS port

Port 53 is special-cased in many minds because only one process typically binds a given address:port. If systemd-resolved already uses 127.0.0.53:53, your Clash or Mihomo DNS inbound must not try to take the same combination unless you have intentionally layered them. Conversely, a profile that sets dns.listen: 0.0.0.0:53 can fail to start, fall back, or on some systems require elevated privileges—leaving the UI green while the DNS hop never materializes.

Inspect listening sockets. Examples you can adapt to your tool preferences:

# iproute2 ss — common on systemd desktops
ss -ulpne | head
ss -tlpne | head

# If you use lsof
sudo lsof -iUDP:53 -P -n
sudo lsof -iTCP:53 -P -n

Interpret the output calmly: you are matching process names to ports. If you see systemd-resolve on 127.0.0.53:53 and clash or mihomo on 127.0.0.1:1053, that is not automatically wrong—it means you must point the operating system to 127.0.0.1:1053 (or whatever your client exposes) in a supported way, or enable the client’s integration path that rewrites resolved’s upstreams, rather than assuming both can “share” 53 on the same address without a bridge.

💡 Privilege and containers Binding 0.0.0.0:53 or inserting redirect rules in the root network namespace may require CAP_NET_BIND_SERVICE or a helper. Docker and rootless setups add a second network namespace: the host can look perfect while a container still uses the embedded DNS in its own resolv.conf. When symptoms isolate to containers, check that story separately; it is the same class of stub resolver confusion in miniature.

Step 3 — Align Clash DNS with how Linux asks questions

Clash family cores can accept DNS in several shapes: a dedicated DNS module with upstreams and optional doq/dot, redir-host versus fake-ip modes, and (depending on the client) per-platform hooks that push traffic into the core. The failure mode to avoid is a profile that looks internally consistent but never receives the same queries your browser issues, because the browser (or the OS) still queries 127.0.0.53 and bypasses the core’s matchers for domain-based rules on the first hop.

Concrete alignment strategies—pick one and document it on your machine:

  • OS stub stays, core handles upstream policy: teach systemd-resolved to use 127.0.0.1 (or the client’s DNS port) as a forwarder for specific domains, or as the system default, when your distribution’s docs support that pattern. resolvectl can set per-link or global DNS; some users disable the stub in controlled environments—know the trade-off (other packages may expect it).
  • TUN and DNS hijack: in TUN mode, the core can capture DNS to the fake-ip pool or redirect queries into its listener so application-level rules and DNS agree more often. This trades complexity for higher capture. Read TUN mode explained for coupling between capture and fake-ip expectations.
  • Client GUI integration: maintained Linux GUIs such as Clash Verge Rev may offer toggles that apply desktop-specific DNS behavior; prefer those code paths on desktop Linux over a random iptables one-liner that survives reboots poorly.

A non-goal for this page is pasting a universal YAML fragment: your provider template already defines dns: sections; the debugging skill is to ensure the queries you care about traverse the path you think they do. For rule-authoring context once DNS paths are honest, the custom rules tutorial is the next stop.

Step 4 — Fake-IP and why sites “half load” on Linux

In fake-ip mode, the core can assign synthetic addresses for domain lookups so rules can make decisions early. That is powerful for split routing, but the mental model has to include every consumer of the answer: if the OS stub cached a non-fake A record from another resolver, or a browser’s secure DNS (DoH) feature bypasses your local path, the connection that reaches the core may be IP-first and miss DOMAIN matchers in ways that look random. Linux users often hit this when toggling a browser’s “use secure DNS” switch without correlating to Clash logs.

Methodical approach:

  1. Disable or align DoH/DoT in the browser for a controlled test—not forever, but for ten minutes of signal.
  2. Flush local caches you can: resolvectl flush-caches (older releases sometimes used systemd-resolve --flush-caches), then retry.
  3. Compare a getent hosts example.com result with what the Mihomo log shows for a simultaneous lookup.

When the three disagree, the bug is not “pick another exit in Singapore”; it is unify the resolver path or accept IP-based classification in your rules: with eyes open. For a China-focused domestic/foreign split, once DNS is coherent, the China sites and GEOIP CN checklist remains the policy-oriented companion to this DNS plumbing page.

Step 5 — Logs and journalctl: prove the failure, don’t story-tell it

When listeners and profiles look plausible, service logs disambiguate. For systemd-resolved:

journalctl -u systemd-resolved -b -p warning..err --no-pager

For a user-level Clash client that runs under systemd --user (a pattern we document for several Linux distros), also scan the user unit:

journalctl --user -b --no-pager | rg -i 'clash|mihomo|verge' 

Your target is a line with a concrete reason: bind failure, permission denied, upstream timeout, or loop detection. Community threads that jump straight to “disable IPv6” or “use Google DNS” as incantation rarely age well; follow the first error on your machine, then re-run the ss/resolvectl triad to confirm the state change.

Common misfits and the least risky mitigations

Double DNS on the same address: if two programs fight for 127.0.0.53:53 or a chosen 127.0.0.1:53, change the Clash listener to a high port and forward to it, or follow distribution guidance to stop the stub—do not random-kill systemd-resolved on a machine that depends on it for VPN split-DNS at work. VPN + Clash together: two layers can both install routes; pause one product for a controlled A/B. IPv6 AAAA answers when your path filters v6: watch for services that get an AAAA from one resolver, try v6, and fail, while a v4-only path would have worked; match your rules to reality, not the fantasy diagram.

Security and policy note: reconfiguring systemd-resolved or installing polkit rules for TUN is a system administration act. This article assumes you own the machine or have permission to change resolver policy; on corporate-issued hardware, the right answer is often a ticket, not a blog workaround.

Verification loop you can run in one sitting

One pass that closes the story: (1) resolvectl status and readlink -f /etc/resolv.conf; (2) ss for port 53 and your Clash DNS port; (3) a browser test with secure DNS off for debugging; (4) a terminal test (curl -v to a name-heavy URL) while core logging shows which rule and resolver path fired; (5) only then adjust outbound selection. Reboot once if you changed resolved’s configuration—stale bus properties happen.

Compared to opaque “global VPN” products, a maintained Clash Meta stack rewards this discipline: the logs tell you the truth, and the policy layer stops being a black box. When you are ready to standardize a client, use the site’s download page as the first-class distribution path; upstream forges are great for source and issues, while installers benefit from a single, curated entry—see the Clash setup tutorial if you need a refresher. For a finished desktop story on Debian-family systems, Clash Verge on Debian 12: subscription and systemd lines up with the autostart and service model this DNS guide assumes. When routing is coherent end to end, Clash tends to feel boring in a good way; compared with all-or-nothing clients, that stability is worth a careful afternoon on the Linux stub resolver stack. Download Clash for free and experience the difference.