CHAPTER 01 / POLICY GROUPS
Proxy Group Types and Practical Use
Proxy groups sit between rules and nodes. The last field in a rule is usually a proxy group name rather than a specific node; the group then determines the actual egress based on user selection, health checks, or failure status. Binding a rule directly to one node is simple, but makes failover, traffic splitting, and subscription updates harder. A more stable configuration starts with business intent—such as “manual selection,” “automatic selection,” “failover,” “streaming,” and “direct downloads”—and points rules to those stable names. Subscription node names may change; as long as filtering places them back into the right group, the rule layer does not need to change.
select, url-test, fallback, and load-balance
select is an explicit selection group for users who need a stable exit region, manual confirmation of an account's login location, or temporary troubleshooting. It does not switch automatically, so an unavailable node usually requires user intervention; keep “automatic selection” available inside the group. url-test probes a fixed URL and selects the candidate with the lowest measured latency. Probe latency reflects only the target and test moment, not the speed of every website. Very short intervals also create extra connections, so desktop configurations typically probe every few minutes rather than continuously.
fallback selects the first available node in list order, making it suitable when a primary route has clearly defined backups. It prioritizes order and availability, not the lowest latency. load-balance distributes different connections across multiple nodes and suits concurrent tasks without login state or a fixed exit. Avoid using it casually for account logins, payments, long-lived connections, or services sensitive to source addresses, because one activity may originate from different exits. Consistent hashing can reduce frequent exit changes for the same destination, but confirm that the application tolerates this behavior first.
proxy-groups:
- Manual selection
type: select
proxies:
- Automatic selection
- Failover
- DIRECT
- name: Automatic selection
type: url-test
use:
- remote-nodes
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 80
lazy: true
- name: Failover
type: fallback
use:
- remote-nodes
url: https://www.gstatic.com/generate_204
interval: 300
lazy: true
use references proxy-providers, allowing nodes from remote subscriptions to enter a proxy group automatically; proxies lists fixed nodes or other proxy groups. They can be combined where supported by the core, but keep each source clear for maintainability. When there are many nodes, use a filter regular expression to select regions by name—for example, nodes containing “Hong Kong” or “HK”. Use inverse filters carefully: inconsistent naming can exclude every candidate. After changing a filter, verify the actual members in the client's proxy group details rather than checking only whether the YAML loads.
Avoiding Circular Proxy Group References
A practical design uses three layers: node providers at the bottom, automatic selection or failover in the middle, and user-facing business groups at the top. Rules reference only the top-level groups; those groups may reference middle-layer groups and a few fixed nodes. No proxy group may reference itself, directly or indirectly. For example, if “Manual selection” contains “Automatic selection,” while “Automatic selection” also lists “Manual selection” as a candidate, the configuration forms a cycle. Some clients report an error during loading; others show an empty group. Start with the reported group and expand references layer by layer until every leaf resolves to a real node or a built-in policy such as DIRECT or REJECT.
| Type | Selection Method | Best For | Key Limitation |
|---|---|---|---|
| select | User selection | Fixed region, account login, troubleshooting | Usually does not switch automatically after failure |
| url-test | Automatic selection from probe results | Everyday browsing with many candidates | Probe latency does not represent every workload's speed |
| fallback | Selects the first available item in order | Primary and backup routes, stable exits | List order directly affects the result |
| load-balance | Distributes connections across multiple nodes | Concurrent tasks that do not require a fixed exit | Not suitable for source-sensitive services |
CHAPTER 02 / RULE PROVIDERS
Managing Rule Sets as Subscriptions
Once a rule set grows from dozens to thousands of entries, putting everything in the main configuration hurts readability and allows subscription updates to overwrite local changes. rule-providers separates domains, networks, or classical rules into independent resources that the core fetches and caches periodically. Keep provider definitions, business policies, and rule-set references in the main configuration, while maintaining rule content by topic—such as ad blocking, private networks, work services, and streaming. This lets you update one category independently and disable a problematic reference quickly without rewriting the entire configuration.
How behavior and format Work Together
behavior describes the semantics of a rule set. domain is for domain-only collections, typically containing full domains, domain suffixes, or domain expressions supported by the core; ipcidr handles IPv4 and IPv6 networks; classical stores complete typed rules such as DOMAIN-SUFFIX,example.com and PROCESS-NAME,example.exe. With the wrong choice, a file may download successfully but fail to parse, producing payload or rule-type errors in the logs. format identifies whether the resource is YAML, plain text, or a binary rule format and must match the remote file's actual content rather than its extension.
rule-providers:
private-domain:
type: http
behavior: domain
format: yaml
path: ./rules/private-domain.yaml
url: https://rules.example.invalid/private-domain.yaml
interval: 86400
health-check:
enable: true
interval: 600
office-classical:
type: http
behavior: classical
format: text
path: ./rules/office.list
url: https://rules.example.invalid/office.list
interval: 43200
private-network:
type: file
behavior: ipcidr
format: yaml
path: ./rules/private-network.yaml
rules:
- RULE-SET,private-domain,DIRECT
- RULE-SET,office-classical,Work services
- RULE-SET,private-network,DIRECT,no-resolve
- MATCH,Manual selection
The example domain uses a reserved, non-resolving suffix and is for structure only; replace it in deployment with a reachable rule URL from a known source. path is the local cache location. Different providers in the same configuration must not reuse one file, or updates may overwrite one another. Relative paths usually resolve from the configuration working directory, not the graphical client's installation directory. In containers or system services, also verify that the runtime user can create and write to the directory. If logs show a successful download but a failed write, check directory permissions, read-only mounts, and path hierarchy instead of repeatedly changing the remote URL.
Rule Order Matters More Than Rule Count
Clash and mihomo generally evaluate rules from top to bottom and stop at the first match. Put specific domain rules before broad ones; private addresses and local services usually belong before public network ranges, with MATCH as the final catch-all. If a broad regional range or wildcard domain appears first, later specific rules never run. Rule sets also override one another: when a domain belongs to both “work services” and “direct domains,” the earlier reference determines the result. When debugging, do not merely confirm that an entry exists; inspect the connection details or logs for the matched rule type, payload, and target policy.
no-resolve is commonly used with IP rules to avoid resolving a domain just to obtain its destination IP during matching. It reduces unnecessary DNS queries and can keep the original domain-handling path intact, but it should not be added mechanically. Domain rules already depend on the domain and do not need it; when matching requires the resolved address or network, disabling resolution prevents a match. First identify whether the rule uses a domain, destination IP, or process information, then decide whether to skip resolution.
Update Failures and Cache Fallbacks
A failed remote rule update does not necessarily interrupt existing traffic immediately. If a valid local cache remains, the core can usually continue using the previous content; there is no fallback on the first load, after the cache is cleared, or when the path changes. Before maintenance, record the rule cache directory and last successful update time. During an incident, check the system clock, DNS resolution, remote response status, proxy egress, certificate errors, and file permissions in order. If the rule URL itself requires a proxy while the rule determines that proxy path, startup can form a dependency cycle. Use a known-working proxy for downloads, or prepare a local file for startup before restoring remote updates.
More rule sets are not always better. Multiple sources may duplicate domains or conflict in their maintenance policies. Record each provider's source, purpose, update frequency, and target policy, and regularly remove caches that are no longer referenced. Before changing a source, validate its behavior with a small local rule set, then move stable entries to a remote resource. For subscription structure and compatibility differences, read Understanding and Converting Clash Subscription Profiles to avoid treating node subscriptions, complete configurations, and rule-set subscriptions as the same thing.
CHAPTER 03 / DNS PIPELINE
Optimizing DNS Configuration
DNS configuration determines how domains obtain addresses. It also affects whether rules can see the original domain, whether connections bypass the proxy, and compatibility in TUN mode. A common mistake is to put every resolver into one list in the hope that more options mean greater stability. In practice, resolver protocol, access path, regional responses, and rule mode must work together. Break troubleshooting into four stages: whether the client sends the query to mihomo, which nameserver mihomo chooses, whether the query travels directly or through a proxy, and how the returned address participates in later rule matching. Identify the failing stage before changing anything.
Primary and Policy-Specific Resolvers
default-nameserver resolves the domains of encrypted DNS servers and other bootstrap targets. It should usually contain resolvers reachable by IP, avoiding a cycle where the resolver's own hostname must be resolved first. nameserver provides the main query sources and may include standard UDP/TCP DNS, DoT, or DoH. Encrypted protocols protect queries on the way to the resolver, but their connections still need correct routing. If a DoH endpoint is sent through a proxy while the proxy node's hostname waits for that same DoH resolver, startup can hang. Bootstrap paths for node and resolver hostnames must therefore be planned separately.
proxy-server-nameserver can handle proxy node hostname resolution separately, so node connections do not depend on business-domain Fake-IP results. nameserver-policy assigns resolvers by domain—for example, sending internal domains to LAN DNS and region-specific domains to an appropriate resolver. Match from specific to broad, and verify that the rule-set expression is supported by the current core. In enterprise networks, internal domains often return private addresses; sending them to a public resolver can fail and may expose queries through an inappropriate path.
dns:
enable: true
listen: 0.0.0.0:1053
ipv6: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
- "time.*.com"
- "ntp.*.com"
default-nameserver:
- 1.1.1.1
- 223.5.5.5
nameserver:
- https://dns.alidns.com/dns-query
- https://1.1.1.1/dns-query
proxy-server-nameserver:
- 223.5.5.5
- 1.1.1.1
nameserver-policy:
"*.corp.example.invalid":
- 192.168.1.1
The listen address determines which devices can use the DNS service. Bind to a loopback address for local-only use; bind to all interfaces only when LAN devices need access, and also check the firewall, LAN access permissions, and port conflicts. Exposing DNS on an interface reachable from outside networks increases abuse risk, so restrict sources with a firewall in server environments. Enable ipv6 according to the local network and the IPv6 capabilities of proxy nodes. Simply disabling IPv6 may hide routing problems and make AAAA-only services unreachable; enabling it without usable upstream or egress IPv6 may cause connections to try IPv6, wait for failure, and then fall back with added latency.
Choosing Between redir-host and Fake-IP
redir-host returns real addresses and offers straightforward traditional compatibility, but transparent interception may lose the domain when subsequent connections carry only a destination IP. Domain rules then need mapping or sniffing to restore it. fake-ip assigns reserved addresses to domains and uses a mapping table to recover the original domain when a connection arrives. This usually makes rule matching more consistent and reduces cases where an application bypasses the core with its own resolved address. The trade-off is that some services relying on real DNS responses, LAN discovery, time synchronization, games, or specialized devices may not work correctly and need fake-ip-filter.
Do not copy a huge filter template wholesale. Overly broad entries push many domains out of the Fake-IP flow and weaken rule consistency; overly narrow entries leave application-specific failures unresolved. Start with the default configuration, observe problematic domains in the logs, and add one explicit entry at a time. After changes, clear the OS DNS cache, application cache, and core mapping before reconnecting; otherwise old results can distort testing. Browsers may also use their own secure DNS, so confirm during troubleshooting that their resolver path matches the system path.
DNS Leaks and Misdiagnosis
An unusual DNS path is usually not caused by one switch. A system may simultaneously have browser DoH, system DNS, TUN DNS hijacking, container resolvers, and forwarding from a LAN router. First use logs to confirm whether the query enters mihomo, then inspect the resolver connection path. If the target domain never appears in the logs, the issue is at the application or system layer. If the query appears but times out, check upstream reachability and routing. If resolution succeeds but the connection fails, move to rules, proxy groups, and nodes instead of continuing to replace DNS. Change only one resolver or enhancement mode per comparison round and record timestamps for correlation with logs.
Caching can reduce DNS latency but also prolong the effects of stale records and mistakes. When a domain switches servers, rules have just changed, or Fake-IP mode has changed, consider application, system, and core caches together. Rebooting the whole device is not the only option: use the client's DNS cache-clearing function first, then close and reopen the target application. If the issue affects only one browser, container, or LAN device, compare their DNS settings instead of adding global complexity for every device.
CHAPTER 04 / TUN AND FAKE-IP
TUN and Fake-IP Interception Boundaries
The system proxy affects only applications that honor proxy settings; TUN uses a virtual network interface to capture a broader range of IP traffic. Command-line tools, some games, system services, and software that ignores proxy settings may connect directly under a system proxy, while TUN can send those connections through the core's rule chain. Broader interception also increases the chance of conflicts among routing, DNS, firewalls, virtual machines, and other network tools. Before enabling it, confirm that ordinary system-proxy mode works and that the subscription, nodes, and rules are valid, then test TUN separately. Otherwise node failures and routing failures become entangled.
Core Parameters and Platform Differences
stack selects the network-stack implementation used by TUN. system tends to use the system network stack and usually offers more intuitive compatibility; gvisor uses a user-space stack that may improve isolation or specific protocol behavior in some environments but can add overhead; mixed combines handling by traffic type. No choice works everywhere. When a specific application times out, UDP behaves abnormally, or throughput drops, test each option while keeping the rest of the configuration unchanged.
auto-route lets the core add routes automatically and direct target traffic to the virtual interface. auto-detect-interface identifies the real outbound network adapter and is especially useful when a laptop switches between Ethernet, Wi-Fi, hotspots, and VPNs. On Windows, also check the firewall, network profile, and other virtual adapters; macOS may require system authorization; Linux services involve runtime permissions, policy routing, and firewall frameworks. Graphical clients often handle some permissions, but a denied prompt, an unstarted service component, or stale routes can leave the interface switch enabled without actual interception.
tun:
enable: true
stack: mixed
dns-hijack:
- any:53
- tcp://any:53
auto-route: true
auto-redirect: true
auto-detect-interface: true
strict-route: true
mtu: 1500
dns-hijack sends DNS requests on specified ports into the core's resolver flow and is one of the key requirements for Fake-IP. Some applications use built-in DoH and never access traditional port 53, so hijacking alone cannot cover every query. strict-route can reduce traffic bypassing through other interfaces, but in virtual machines, LAN sharing, corporate VPNs, or multi-adapter environments it may also block paths that must remain available. If a local printer, NAS, or corporate network becomes unreachable, check route exclusions and private-network rules instead of sending every private address to the proxy.
MTU, Loopback, and Route Conflicts
An MTU mismatch often appears as some websites loading while larger requests stall, uploads fail, or connections inside a specific tunnel time out. Because small packets still work, the issue is easily mistaken for an unstable node. Keep the node fixed and gradually lower the TUN MTU for comparison, but do not reduce it excessively; a very low value increases fragmentation and processing overhead. If the problem occurs only through another VPN, a mobile hotspot, or PPPoE, first consider the effective MTU reduction caused by extra encapsulation on the underlying link.
Proxy connections generated by the core itself must leave through the real interface and must not be captured by TUN again, or a loop will form. Automatic routing and interface detection usually handle this, but custom routes, container networks, policy routing, or multiple transparent proxies can still cause failures. A typical symptom is every node timing out as soon as TUN is enabled and recovering immediately when it is disabled. Inspect the routing table and outbound interface, confirm that the proxy server address is excluded, verify default-route priority, and check whether a stale virtual interface from an old client is still active.
How Fake-IP Mappings Participate in Rules
When an application requests a domain through DNS, the core returns a Fake-IP and records the mapping between that address and the domain. The application then connects to the Fake-IP; TUN captures the connection, the core restores the domain and applies domain rules, and the selected policy reaches the real destination. Fake-IP exists only on the local interception path, not as the actual remote address. If an application caches an old Fake-IP while the core mapping was lost after a restart or configuration change, the domain may not be recoverable. Clearing the application's connections and DNS cache is usually more effective than adding more rules.
LAN services, broadcast discovery, and applications that require real addresses can be excluded with fake-ip-filter, but private-network rules must still be placed appropriately. Excluding a domain does not automatically make traffic direct; after resolving to a private address, later rules may still send it to a proxy group. Conversely, adding direct private-network rules cannot fix an application that depends on the contents of a real DNS response. Treat “what DNS returns” and “where the connection goes” as separate troubleshooting questions.
If enabling TUN cuts off all internet access, use a fixed sequence: disable TUN to verify the basic proxy; enable TUN without changing DNS; check that the virtual interface is created; confirm the default route and physical interface; inspect DNS query logs; then compare access by fixed IP and by domain. If a fixed IP works but a domain does not, focus on DNS. If neither works, focus on routing, permissions, and loops. For a broader connectivity workflow, see How to Read Clash Runtime Logs.
CHAPTER 05 / DOMAIN SNIFFING
Domain Sniffing and Destination Recovery
Connections received by a transparent proxy sometimes contain only a destination IP and no original domain. Domain sniffing examines protocol characteristics at the start of a connection and recovers the domain from the HTTP Host header, the server name in a TLS ClientHello, or supported QUIC information, allowing domain rules to participate. It mainly addresses cases where an application resolved the domain itself and the core sees only an IP. It is not a replacement for DNS and cannot recover destinations from every encrypted or nonstandard protocol. Define sniffing targets, port ranges, and override conditions carefully to avoid misidentifying unrelated traffic.
The Effect of override-destination
When the domain is identified without overriding the destination, the core can match rules using the recovered domain while still connecting to the IP originally resolved by the application. With override-destination enabled, the core may determine the destination again from the sniffed domain, which can fix mismatches between application resolution and the proxy-side access path. However, CDNs, private DNS, split DNS, and fixed-address services may expect the original IP. Re-resolving the domain can cause regional differences, certificate errors, or failures to reach internal services. Narrow the feature by protocol and port first, and add known-incompatible domains to a skip list.
sniffer:
enable: true
force-dns-mapping: true
parse-pure-ip: true
override-destination: false
sniff:
HTTP:
ports:
- 80
- 8080-8880
override-destination: true
TLS:
ports:
- 443
- 8443
QUIC:
ports:
- 443
skip-domain:
- "Mijia Cloud"
- "+.push.apple.com"
skip-src-address:
- 192.168.0.0/16
skip-dst-address:
- 10.0.0.0/8
parse-pure-ip allows sniffing attempts on connections whose destination is a bare IP, a common capability in transparent interception, but it expands the inspection scope. force-dns-mapping works with DNS mappings and is useful when a domain must be recovered from an existing mapping. Set protocol ports according to the actual service: HTTP is not limited to port 80, and TLS may use ports such as 8443. Conversely, sending every port to every sniffer increases false positives and processing cost. Start with common ports and add others only when logs show that an application uses them.
What Sniffing Cannot Resolve
Encrypted client handshakes, ECH, nonstandard encapsulation, certificate pinning, and protocols without a domain field may prevent sniffing from obtaining a useful hostname. UDP protocols often expose less information than HTTP. If logs show only a destination IP, that does not necessarily mean the feature failed; the connection may contain no readable domain. Use IP or process rules, or route the application's DNS into the core, instead of continually expanding the sniffing scope. Process rules depend on platform permissions and core capabilities, so availability may differ on servers and mobile systems; rely on the client's actual logs before deployment.
False positives from sniffing often appear as a LAN device, game, push service, or specialized client failing after the feature is enabled. First disable override-destination while keeping sniffing enabled to determine whether the issue is identification or destination replacement; then add exclusions by source address, destination address, or domain. LAN ranges generally do not need broad sniffing because internal DNS and fixed addresses should retain their original path. Do not make exclusions so broad that they cover all public networks, or sniffing becomes effectively disabled.
Coordinating Fake-IP and Rule Matching
Fake-IP mappings already recover most domains handled by the core's DNS, so sniffing mainly supplements applications that bypass system DNS, existing connections, or direct connections to real IPs. When both are enabled, inspect the logs to see whether the final domain came from a DNS mapping or from sniffing. If the same connection produces different results, destination overriding may change the access address. A conservative starting point is to let Fake-IP handle ordinary domains and have sniffing inspect only common HTTP/TLS ports with overriding disabled by default; enable overriding for specific applications only after the setup is stable.
Do not validate sniffing only by checking whether a webpage opens. Inspect the connection details for the target host, matched rule, and proxy group: record one run with sniffing disabled, then create a new connection with the same application and domain after enabling it. Compare whether the target changes from an IP to a domain and whether the rule changes from an IP rule to a domain rule. Existing long-lived connections are not rebuilt automatically after configuration changes; fully quit the application or wait for the connection to close. Browser connection reuse and QUIC can extend old sessions, so use a new private window and temporarily clear site connection state during testing.
Domain sniffing is a supplementary tool. If DNS queries already reach the core reliably and domain rules match correctly, there is no need to expand sniffing just for completeness. Every added protocol and port should have a specific problem behind it, with log differences recorded before and after. That makes it possible to decide whether old compatibility exceptions are still needed after an application update or network change.
CHAPTER 06 / PROFILE MERGE
Local Overrides and Merged Subscriptions
Subscription updates regenerate the remote configuration, so changes made directly in the subscription file are usually overwritten next time. A maintainable approach treats the remote subscription as read-only input and keeps long-term local settings in overrides, extension scripts, or a separate main configuration. Override formats and merge order differ among clients, so a client's extension syntax should not be mistaken for native mihomo YAML. Before migrating clients, separate fields belonging to the core from those managed by the graphical client.
Override, Append, and Delete Are Three Different Operations
Scalar fields such as mixed-port and mode can usually be overwritten directly. Mapping fields such as dns may merge by key or replace the entire section. Array fields such as rules and proxy-groups are more complex: a simple replacement can discard subscription content, while a simple append may place a catch-all rule before later entries. MATCH must be last; if local rules are appended after a remote MATCH, they can never match. A reliable merger should support prepending, appending, replacement by name, and explicit deletion, then verify the final order.
When proxy groups are associated by name, same-named groups may be replaced or duplicated. Duplicate names make rule references ambiguous, and a client may display only one of them. Establish a naming convention before merging: use clear names for local business groups and retain source prefixes for remote automatic groups. Node names can also collide—for example, two subscriptions may both contain “Hong Kong 01.” Add source prefixes at import time rather than renaming every node by hand, because the conflict will return at the next update.
# Locally maintained main configuration fragment
proxy-providers:
provider-a:
type: http
url: https://subscription.example.invalid/a
path: ./providers/a.yaml
interval: 3600
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 300
provider-b:
type: http
url: https://subscription.example.invalid/b
path: ./providers/b.yaml
interval: 3600
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 300
proxy-groups:
- name: All sources
type: select
use:
- provider-a
- provider-b
proxies:
- DIRECT
rules:
- DOMAIN-SUFFIX,corp.example.invalid,DIRECT
- RULE-SET,private-domain,DIRECT
- MATCH,All sources
Use proxy-providers to aggregate multiple node subscriptions; this is usually clearer than concatenating several complete configurations. Complete configurations may each contain ports, DNS, rules, and same-named proxy groups, so mechanical concatenation creates conflicts easily. Node providers supply only proxy entries, while the main configuration controls everything else. If an upstream returns a complete Clash configuration rather than provider format, confirm whether the client can extract its nodes or convert it through a trusted local workflow. Do not submit subscriptions containing access credentials to an unknown online converter.
Override Layers and Fallback Files
Keep four layers: the original subscription, local overrides, the merged final configuration, and the most recent known-good configuration. Use the original to inspect upstream content; remove subscription URLs and credentials before placing local overrides under version control; use the final configuration to locate merge results; use the known-good file for rollback. Change only the local override, run a syntax check, and then load it into the core. If the client cannot export the final configuration, locate the actual loaded file in its runtime directory, but remember that the client may rewrite it automatically, so it is not a suitable editing entry point.
Local overrides are best for stable intent: custom rules, a fixed proxy-group structure, DNS choices, and LAN exceptions. Let the subscription continue to provide node lists, authentication fields, and properties that change frequently. This delivers new nodes without overwriting local traffic splitting. If an upstream starts supplying an incompatible field, make the smallest deletion or conversion in the override layer and record the reason. Do not freeze a complete old configuration indefinitely, or node and protocol support will gradually fall behind.
Availability and Fault Isolation for Multiple Subscriptions
Providers should not share cache paths, and health checks should be independent. If one source fails to update, the others can still load; but if every group references the failed source, the configuration may appear to load successfully while groups have no usable members. Keep multiple automatic groups in a top-level manual group and label their sources clearly. If an automatic group mixes every node from different purposes and regions, probe results may change constantly. A better design groups nodes by source or region first, then selects those child groups at the business layer.
After merging, verify that proxy group names are unique, every reference exists, provider paths differ, only the intended catch-all remains at the end of the rules, DNS mappings are complete, and sensitive fields have not entered logs or exported files. Compare final configurations structurally before and after subscription updates, focusing on field changes rather than text lines. If an update prevents startup, restore the latest known-good configuration first, then compare newly added upstream fields instead of changing several overrides while the system is unavailable.
Graphical clients place override controls and saved files in different locations. Clash Plus suits desktop users who want graphical configuration and proxy-group management; Clash Verge Rev, FlClash, and Clash Nyanpasu may also offer extensions or scripts, but follow the current interface documentation for their syntax. For a new client choice, see the Client Selection Guide rather than choosing from a copyable script alone.
CHAPTER 07 / EXTERNAL CONTROLLER
External Controllers and API Boundaries
mihomo's external control API lets graphical interfaces and web panels read runtime status, switch policies, inspect connections, and update configuration. It is a management interface, not a proxy port. After external-controller is set to a listen address, clients connect to that port over HTTP and WebSocket. A control panel is usually only a static frontend; its data and operations come from the core API. Therefore, a page that fails to open, opens without data, or displays data but cannot perform actions points to different problems involving static resources, API connectivity, or authentication.
Listen Address and Access Scope
For local-only use, binding 127.0.0.1 is safest and prevents direct access from other devices. Bind to 0.0.0.0 or a specific LAN address only when managing a server or router from the LAN, and use a firewall to allow only trusted networks. Listening on every interface does not mean the port should be public. The control API can switch nodes, read connection targets, and reload configuration, so its exposure should be narrower than that of a normal proxy port. For remote maintenance, prefer an SSH tunnel or a controlled reverse proxy to the local API instead of exposing the control port directly.
external-controller: 127.0.0.1:9090
secret: "your-password"
external-ui: ./ui
external-ui-name: dashboard
# Temporarily forward the local interface over SSH from another device
ssh -L 9090:127.0.0.1:9090 [email protected]
secret authenticates the control API and should be an independent, unpredictable value. The string in the example is intentionally obvious for teaching and must be replaced in deployment. Control panels usually ask for the API address and key in their settings; the API address must point to the core's listen address, not the proxy's mixed-port. If the page loads over HTTPS but tries to call an HTTP control API, the browser may block the request as mixed content. Use a same-origin reverse proxy or secure tunnel instead of disabling browser security.
external-ui and Static Resource Directories
external-ui points to the directory containing the control panel's static files, including its entry HTML and supporting assets. It does not download the panel, and the path resolves relative to the core's working directory. A system service and a manually run command may use different working directories, so “visible from the terminal, blank as a service” usually indicates a relative-path difference. Use an explicit absolute path or verify the service working directory and file permissions. On a read-only filesystem, pre-deploy the panel files to a readable location.
Some configurations support maintaining static resources through a download URL for the external UI, but production environments should still record the source and pin the update process. Panel and core updates are independent: a new panel may call APIs unsupported by an old core, while an old panel may not display new fields. When a button does nothing, first inspect request status and API responses in browser developer tools, then compare the core logs. Do not delete the main configuration first; a panel problem usually does not affect whether the proxy core works.
CORS, Authentication, and Reverse Proxies
When the control panel and API have different origins, the browser performs cross-origin checks. mihomo can restrict permitted origins through its allow-origin settings. Allowing any origin for convenience broadens the browser-side attack surface; list only the actual control panel addresses instead. Origin restrictions do not replace a secret or network controls. Their roles differ: the firewall limits who can connect to the port, authentication determines whether a request can operate the API, and origin policy limits which webpages can issue browser calls.
When using a reverse proxy, forward WebSocket upgrade requests correctly; otherwise ordinary status endpoints may work while live logs and connection lists keep disconnecting. The proxy layer must also preserve authentication headers and restrict request body size and paths. Do not put the proxy port, control API, and static panel behind indistinguishable paths. For LAN-only access, binding to a LAN address with a firewall is often easier to maintain than a complex public reverse proxy.
Layered Checks for API Failures
First use system tools to confirm that the port is listening, then request a basic endpoint to verify authentication, and finally inspect the browser console. Connection refusal means the core is not listening, the address is wrong, or a firewall is blocking it. An unauthorized response means the API is reachable but the secret does not match. If ordinary requests work but live content fails, focus on WebSocket. If panel resources return not found, check the external-ui path. If the panel shows empty proxy groups, inspect the API response and core configuration directly to determine whether the issue is rendering or the groups truly have no members.
The external control API is also useful for automated health checks, but scripts should not poll every connection at high frequency or place secrets in public repositories, shell history, or frontend pages. Automation should read only the necessary endpoints and use timeouts with backoff. Reloading configuration is stateful: save the current known-good file first, confirm that the core reports success after reload, and recheck proxy groups. The panel is a convenient entry point, but final decisions should rely on the configuration file, API response, and core logs.
CHAPTER 08 / VALIDATION
Configuration Validation, Log Analysis, and Safe Rollback
The difficulty of advanced configuration is usually not a single field but the inability to identify causality after several subsystems change together. A sound maintenance process observes syntax validation, static reference checks, startup logs, live connections, and business results separately. A webpage opening proves only that one path works; it does not prove that DNS, rules, and TUN behave as expected. Conversely, one failed website does not prove that the node is unusable. Record a baseline before each change, then test fixed targets with a fixed policy afterward for comparable results.
Static Checks Before Loading
First check YAML indentation, colons, list levels, and duplicate keys. YAML uses spaces for indentation; tabs can cause parse errors. Quote names containing colons, hash signs, or special characters so they are not interpreted as structure or comments. After syntax passes, check semantic references: whether referenced proxy groups exist, whether their nodes or providers exist, whether rule-set names match, whether cache paths conflict, and whether the control API port duplicates the mixed-port or DNS listen port.
mihomo can accept a configuration directory on the command line and run checks, but executable names and argument entry points may be wrapped differently by distribution packages. When using the core directly, run configuration tests in the actual runtime environment so relative paths, permissions, and resource files match the service. Verifying only in a personal terminal while the service uses another account can hide path and permission issues.
# Run this after entering the actual configuration directory
mihomo -t -d /path/to/config-directory
# Start in the foreground to observe the complete log
mihomo -d /path/to/config-directory
# Linux: inspect routes and listening ports
ip route
ss -lntup
A successful configuration test does not guarantee that remote resources can download or that nodes can connect. It mainly confirms local structure and whether some resources are readable. During the first startup, continue watching logs for provider updates, DNS listeners, the TUN interface, the control port, and the proxy port. The first error is often closer to the root cause than later cascading errors. For example, a DNS listen-port conflict makes resolution unavailable, and the many node-hostname failures that follow are only consequences.
Build a Test Matrix Along the Execution Chain
Add functionality gradually, starting with the smallest path. In round one, disable TUN, use the system proxy and a fixed manual node, and verify basic TCP connectivity. In round two, keep the node unchanged and verify domain resolution and rule matches. In round three, switch to an automatic proxy group and confirm health checks. In round four, enable TUN. In round five, enable sniffing, overrides, or complex rule sets. Add only one variable per round. If round three fails, there is no need to investigate round-five sniffing parameters.
| Symptom | Check First | How to Verify | Do Not Change Yet |
|---|---|---|---|
| All nodes time out | Basic network, node hostname resolution, TUN loopback | Disable TUN and test one fixed node | Large-scale rule additions or removals |
| IP works, domain fails | DNS listener, hijacking, and upstream resolution | Inspect query logs and resolution results | Proxy group ordering |
| Only one category of websites uses the wrong policy | Rule order and rule-set content | Inspect the rule that actually matched | Replace every resolver |
| LAN becomes unreachable after enabling TUN | Private networks, strict routing, and interface selection | Compare the routing table with direct rules | Subscription node list |
| Panel opens but live logs are missing | WebSocket, authentication, and reverse proxy | Inspect browser network requests | DNS enhancement mode |
Distinguish stages when reading logs
During startup, focus on configuration parsing, port binding, resource loading, and virtual-interface creation. During subscription updates, check HTTP status, timeouts, format parsing, and cache writes. During DNS processing, check query source, upstream selection, and returned results. During connections, check the target, rule, proxy group, and actual node. During runtime, watch health checks and connection close reasons. Do not replace a node immediately when you see “timeout”: the same word may describe a rule download, DNS query, proxy handshake, or business server, and each requires a different response.
Connection details usually show the source address, target domain or IP, network type, matched rule, policy chain, and egress node. Read these fields in order to identify where the request diverged from expectations. If the target domain is correct but the match is MATCH, earlier rules did not cover it. If the rule is correct but the group selects an unexpected node, check group selection and automatic tests. If both policy and node are correct, inspect the node connection, target service, and MTU. This sequence converges faster than repeatedly switching modes.
Rollback Is More Than Restoring One File
A configuration failure may leave routes, virtual interfaces, DNS caches, and remote-resource caches behind. After restoring YAML, confirm that the core reloaded that file, the old process exited, TUN routes were removed, the system proxy was restored, and DNS caches were refreshed. A graphical client may keep one interface configuration and one actual runtime configuration; restoring the wrong file changes nothing in the core. After rollback, check the configuration path in the startup log again.
Make each stable change a rollback point and save at least the configuration file, relevant rule-set version, client's configuration directory, and a change note. The note should state “what problem it solves, which fields changed, how to verify it, and how to undo it,” rather than simply saying “optimized DNS.” Subscription URLs and control secrets should never enter a public repository. Use a separate private local file or inject them through the runtime environment, then reference them from the configuration. When sharing logs, remove subscription parameters, node credentials, control secrets, and internal domains.
Establish a Repeatable Maintenance Sequence
A complete adjustment can follow this order: copy the current known-good configuration; export or record the final merged result; change one topic only; run static checks; load in the foreground and observe the first error; verify the system proxy with a fixed node; check DNS queries and rule matches; enable TUN and sniffing last; then restore automatic policies and remote updates after the setup is stable. If any step fails, return to the previous known-good configuration and clear the runtime state created by that step. The process may seem slower, but it prevents multiple variables from stacking up and turning troubleshooting into guesswork.
In environments with heavy logs, filter by target domain, source process, or time range instead of keeping the most verbose level enabled indefinitely. Verbose logs are useful for short investigations but generate large files and expose more sensitive information. After resolving the issue, return to the normal level and keep a concise incident summary. To understand typical errors across startup, subscriptions, DNS, connections, and rules, follow the Runtime Log Troubleshooting Sequence. For LAN sharing involving mixed-port, listen addresses, and firewalls, read Mixed-Port and LAN Proxy Setup.
Related route
Move from Basic Configuration to Advanced Tuning
If subscription import, mode selection, and connection checks are not complete, establish a working baseline with the quick tutorial first. When switching clients, use the Download Center to compare platforms and maintenance status.