Chapter 01 / Baseline
Configuration skeleton and debugging baseline
A Clash configuration is not a list of independent settings; it is an ordered processing chain. The client first reads basics such as listening ports, operating mode, and DNS, then loads proxy nodes and proxy groups, followed by rules and rule providers. Finally, the system proxy or TUN sends traffic into the core. A reference to a name that does not exist at any layer can affect everything that follows. A common example is a rule pointing to a proxy group that has been renamed: the configuration may still parse, but matching traffic cannot select the intended exit. The first step in advanced tuning is therefore not adding more parameters, but creating a baseline that can be explained, verified, and rolled back.
Separate client settings from core configuration
Graphical clients such as Clash Plus, Clash Verge Rev, FlClash, and Clash Nyanpasu typically divide settings into two layers. The first belongs to the application itself: launch at startup, the system proxy toggle, profile update intervals, themes, and service installation status. The second is the YAML passed to the mihomo core. The system proxy button usually does not rewrite the subscription file; it changes the operating system's proxy entry point. The TUN toggle may generate a runtime override, so the exact same fields may not appear in the original subscription. When troubleshooting, inspect both the active configuration and the subscription source instead of focusing only on the downloaded YAML.
Keep the baseline section deliberately small for debugging. Start with the info log level, which is enough to show connections, rule matches, and DNS errors; switch to debug only when tracing a specific request. Whether ports need to be specified explicitly depends on how the client manages them—desktop clients may inject their own ports at startup. If you maintain a raw configuration by hand, you can use the structure below, but confirm that the port is not already occupied by another proxy program.
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false
unified-delay: true
profile:
store-selected: true
store-fake-ip: true
mode: rule selects direct, proxied, or rejected traffic according to the rules; unified-delay makes latency measurements closer to the full connection process, but it does not improve actual network quality; store-selected saves proxy-group selections so you do not have to choose them again after restarting; store-fake-ip preserves Fake-IP mappings and reduces short-lived connection fluctuations after a restart. Persistence is especially important on mobile when the system may reclaim the app process, but the client must still be allowed to run normally in the background.
Build the shortest verification loop
After each change, first confirm that the core can load the configuration, then verify that a proxy node can establish a connection. Next, check which rule matched one test request, and only then inspect the target application. If parsing already fails, switching nodes will not help. If the node handshake fails, investigate the subscription and network before changing DNS. If the browser works but one application does not, check whether that app bypasses the system proxy, uses its own DNS, or uses QUIC. This sequence keeps the problem within a single layer.
| Layer to check | Expected result | First priority when it fails |
|---|---|---|
| Configuration parsing | The configuration loads successfully with no missing fields or indentation errors | YAML indentation, duplicate keys, and invalid references |
| Node connection | The proxy group has an available proxy and can establish a session | Subscription validity, network permissions, and protocol parameters |
| Rule matching | The log shows the request matching the expected rule and policy | Rule order, proxy-group names, and rule-provider loading |
| System interception | The target application's traffic enters the system proxy or TUN | System proxy settings, VPN permissions, and routing conflicts |
Use spaces only for indentation in configuration files; do not mix in tabs. Text containing colons, hash signs, or special characters can be quoted, and proxy-group names should remain stable once referenced by rules. If you need to change clients, start from the download page and choose the appropriate platform; Clash Plus is the first choice for cross-platform use, followed by other clients based on your system and workflow. During migration, import the same subscription first and verify the basic connection, then move over local overrides. Do not copy runtime fields generated by the old client as if they were universal configuration.
Chapter 02 / Policy
Proxy-group types and composition
Proxy groups sit between nodes and rules. Rules usually do not bind directly to a node; they send requests to a stable policy name, and the group decides which exit to use. This keeps rules unchanged when nodes change and lets you separate manual selection, latency testing, failover, and load distribution into different layers. The key design principles are clear names, limited depth, and a single purpose per group. A group that handles region selection, service categories, and automatic switching may seem convenient at first, but it makes the final path difficult to identify during troubleshooting.
select, url-test, fallback, and load-balance
select is a manual selection group, suitable for the main entry point and services that need a fixed exit. It does not actively assess node quality, so it may keep the selected node even after that node fails. url-test tests connectivity to a specified URL and selects a node with suitable results, making it useful for everyday automatic selection. fallback prefers the first available node in list order, which suits scenarios that require a stable exit and a clear primary-backup relationship. load-balance distributes connections across multiple nodes, making it suitable for parallel requests that can tolerate changing exits. Login sessions, risk-sensitive services, and workloads that depend on a fixed source address are usually poor candidates.
proxy-groups:
- name: Main Selection
type: select
proxies:
- Automatic Selection
- Failover
- DIRECT
- name: Automatic Selection
type: url-test
use:
- main-provider
url: https://www.gstatic.com/generate_204
interval: 600
tolerance: 80
lazy: true
- name: Failover
type: fallback
use:
- main-provider
url: https://www.gstatic.com/generate_204
interval: 600
lazy: true
interval is the health-check interval. Setting it too low increases wake-ups on nodes and devices and may use more battery on mobile; setting it too high delays failure detection. tolerance reduces frequent switching between similar results. It is not a speed boost, but a stability threshold. lazy: true postpones testing until the group is actually used, reducing idle overhead. Test URLs should return a lightweight, stable response. Do not use a file download URL as a health-check target, and do not treat one test result as a substitute for long-term stability.
Name proxy groups around service semantics
Keep one “Main Selection” group as the unified exit, then create service-specific groups such as “Streaming,” “Developer Services,” and “Messaging.” A service group can reference “Main Selection,” a regional group, or DIRECT; rules should reference the service group. When node sources change, only the lower-level groups need adjustment while the rule layer stays stable. Group names may contain non-ASCII text, but renaming one requires checking rules, the behavior fields of rule-providers, and references from other proxy groups. Case and spaces are part of the identifier, so even one extra space creates a different name.
- name: Developer Services
type: select
proxies:
- Main Selection
- Automatic Selection
- DIRECT
- name: Streaming
type: select
proxies:
- Main Selection
- Automatic Selection
rules:
- DOMAIN-SUFFIX,github.com,Developer Services
- DOMAIN-SUFFIX,githubusercontent.com,Developer Services
- MATCH,Main Selection
When there are many nodes, you do not need to list every name in proxies. Use use to import a proxy provider, then narrow the pool with a filter expression. Filtering depends on consistent node naming in the subscription; when providers use different naming conventions, region keywords alone can select the wrong nodes. Check the actual node names in the client before writing filters, and check again after updating the subscription. When excluding test nodes, expired notices, or multiplier labels, avoid expressions so broad that valid nodes disappear too.
| Group type | Best suited for | Main limitation |
|---|---|---|
| select | Fixed manual exit, main entry point, and service selection | Does not automatically avoid failed nodes |
| url-test | Everyday automatic selection and subscriptions with many nodes | Test results do not equal real-world service experience |
| fallback | An explicit primary-backup order and a stable exit | The list order requires ongoing maintenance |
| load-balance | Parallel connections that do not depend on a fixed exit | May change sessions or source addresses |
Troubleshoot proxy groups by starting with their references. First confirm the group name matched by the rule, then open that group to see the current selection, and continue down to the actual node. If an automatic group appears not to switch, check whether the test URL is reachable, whether the interval has expired, and whether the client has paused background activity. If a service repeatedly asks you to sign in again, move it from a load-balance group to a fixed-exit group for testing. The goal is not to stack on more automation, but to make every choice explainable through the logs and group structure.
Chapter 03 / Rules
Manage rules as subscriptions
Once a rule list grows from a dozen entries to several hundred, keeping everything in the main configuration quickly becomes unmanageable. rule-providers separates themed rules into independent resources and lets the main configuration declare their URLs, formats, update intervals, and matching behavior. The main file keeps only the invocation order while each provider maintains its own content. This allows ad-blocking, LAN, developer-service, or streaming rules to be updated independently and disabled quickly when one provider fails, without rewriting the entire subscription.
Provider definitions and RULE-SET calls
A rule provider's name is only a local reference identifier; parsing depends on behavior, format, and the resource content. behavior: domain suits collections containing only domain entries; ipcidr is for IP networks; classical can hold classic rules with type prefixes. The format must match the remote file. Common text rules can use text, while YAML rules use yaml. Do not declare classical content as domain: successful loading does not mean the matching semantics are correct.
rule-providers:
private-domain:
type: http
behavior: domain
format: yaml
path: ./ruleset/private-domain.yaml
url: https://example.com/rules/private-domain.yaml
interval: 86400
developer:
type: http
behavior: classical
format: text
path: ./ruleset/developer.list
url: https://example.com/rules/developer.list
interval: 86400
rules:
- RULE-SET,private-domain,DIRECT
- RULE-SET,developer,Developer Services
- GEOIP,LAN,DIRECT,no-resolve
- MATCH,Main Selection
The example domain only shows the field structure. In practice, replace it with a confirmed, reachable, and trusted rule source. path is the local cache location; different providers should not share the same path. interval is measured in seconds, and public rules usually do not need updates every few minutes. Excessive frequency only adds requests and writes. When an update fails, the core generally continues using the existing cache, so distinguish an initial download failure from an update failure where the old rules remain active. Deleting the cache and retrying removes this fallback and should not be the first step.
Rule order is priority
Clash searches rules from top to bottom and stops at the first match. Specific rules should come before broad ones: private domains and LAN traffic usually go direct first, service domains then enter their designated policies, IP rules belong where address resolution is required, and MATCH catches everything else at the end. If a broad proxy rule is placed at the top, later direct exceptions will never run. When troubleshooting incorrect routing, the log entry showing which rule matched is more reliable than guessing which category a domain belongs to.
no-resolve tells IP-based rules not to trigger DNS resolution just to obtain an IP address. It can avoid unnecessary lookups, but should not be added mechanically to every rule. If a domain request matches no domain rule and a later GEOIP decision depends on resolution, blocking resolution entirely may leave that rule without the address it needs. Decide whether to add it based on the rule type and DNS mode. Connections that already provide a destination IP can still match IP rules normally.
A small number of local exceptions can be written directly at the top of rules; there is no need to create a remote provider for three or five entries. For example, if a work domain must go direct or an application endpoint must always use “Developer Services,” place those rules before subscribed providers. If the exception list keeps growing, move it to a local provider. This keeps the main configuration readable without requiring a remote file release for every small adjustment.
rules:
- DOMAIN,router.local,DIRECT
- DOMAIN-SUFFIX,corp.example,DIRECT
- DOMAIN-SUFFIX,github.com,Developer Services
- RULE-SET,private-domain,DIRECT
- RULE-SET,developer,Developer Services
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- MATCH,Main Selection
How to locate rule-provider failures
First check whether the provider has finished loading, then confirm that the remote response matches the declared format. Next verify that the provider name matches the RULE-SET reference, and finally inspect its position in the rule list. If the status is normal but nothing matches, common causes include the wrong behavior type, a broad earlier rule capturing the request, or a target connection exposing only an IP while the provider contains only domains. If an update suddenly causes widespread misrouting, restore the previous local cache or temporarily comment out the provider to confirm whether the problem came from an upstream content change.
The more rule sources you add, the harder it becomes to standardize update schedules and naming. A more reliable structure uses a small number of providers selected by purpose, with one primary source per service and local exceptions at the highest priority. Do not import multiple broad providers with nearly identical coverage and expect ordering to resolve every conflict. For multi-device management, see the multi-device configuration sync guide and keep the main configuration, subscription links, and local rules separate.
Chapter 04 / DNS
DNS optimization and leak troubleshooting
DNS determines how domains become addresses and directly affects whether domain rules can match accurately. Once Clash's DNS module is enabled, application queries can enter a local listener first, after which the core selects an upstream resolver according to the configuration. Three questions matter: whether queries truly enter Clash, which upstream should handle each domain, and whether the result remains associated with the subsequent connection. Simply adding many public DNS addresses does not automatically improve stability; it can make the source of results and the boundary of failures harder to identify.
nameserver, default-nameserver, and proxy-server-nameserver
nameserver contains the primary upstream resolvers. default-nameserver resolves the domains of DoH servers or proxy servers themselves, so it usually should contain resolvers reachable by IP address, avoiding a dependency on domain resolution to reach the resolver. proxy-server-nameserver can handle proxy-node domains separately, preventing business DNS rules from affecting node resolution. If subscription nodes use domain names and this layer fails, the interface may show every node as unavailable even though the root cause is not the node protocol.
dns:
enable: true
listen: 0.0.0.0:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
use-hosts: true
respect-rules: true
default-nameserver:
- 223.5.5.5
- 1.1.1.1
nameserver:
- https://dns.alidns.com/dns-query
- https://1.1.1.1/dns-query
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
fake-ip-filter:
- "*.lan"
- "*.local"
- "time.*.com"
- "ntp.*.com"
respect-rules makes DNS requests follow proxy rules, but the proxy resolution chain must already work or this can create a circular dependency. If an upstream is unreachable during initial setup, disable this option temporarily to verify basic resolution, then enable it step by step. listen must match the client's DNS interception method. When desktop traffic is handled by TUN, LAN devices usually do not need access to this port. If you listen on an external interface, also check the firewall and the permitted LAN scope.
Resolver count and fallback logic
Two or three stable primary resolvers are usually enough. Different resolvers may return different addresses based on network location, CDN routing, and cache state, so a longer list does not guarantee more accurate results. If you use fallback, understand its filters as well; otherwise every query may be sent through multiple resolution paths, increasing wait time and network traffic. For a clearly structured configuration, nameserver-policy provides more predictable domain-based resolver selection than broad fallback conditions.
nameserver-policy:
"geosite:private":
- system
"+.corp.example":
- 10.0.0.53
"geosite:cn":
- https://dns.alidns.com/dns-query
Domain matching in policies should reflect what the rule providers can actually handle. If an internal domain can only be resolved by corporate DNS, ensure the route to that resolver is direct or can reach the office network. Putting the internal resolver in a general nameserver list causes requests to time out whenever you leave the office network; a better approach is to use it only for specific suffixes. If another VPN, network filter, or security product is running, confirm that it is not rewriting DNS before Clash does.
Define the observation scope before checking for DNS leaks
A DNS leak generally means that queries which should be handled by a designated path are still sent directly to another resolver by the system or application. Do not rely on a single website's reported resolver name; compare system network settings, Clash logs, and packet captures. Browsers may enable their own secure DNS, and mobile apps may embed DoH. Such requests look like ordinary HTTPS traffic and may not use the system's port 53. To route them through Clash consistently, disable in-app DNS or explicitly handle its DoH domains with rules.
| Symptom | Possible breaking point | What to check |
|---|---|---|
| All proxy-node domains fail to resolve | default or proxy-server-nameserver is unreachable | Build a minimal startup chain with IP-based resolvers |
| The browser works, but one application fails | The app uses built-in DNS, QUIC, or bypasses the system proxy | Check TUN interception and the app's network settings |
| An internal domain cannot be resolved | Internal DNS is not routed by domain | Add nameserver-policy and check routing |
| Resolution succeeds, but the connection reaches the wrong address | Cache, CDN routing, or a Fake-IP mapping problem | Check the logs, then clear the relevant cache |
After changing DNS, reload the configuration and confirm in the logs that the DNS module is listening successfully. Test a normal domain, an internal domain, and a node domain separately. Do not clear every cache at the first sign of an inaccessible page; that changes the system cache, browser cache, and Fake-IP mappings at once, making before-and-after results hard to compare. If the client says it is connected but nothing can access the internet, follow the connected but no internet checklist and check the node, subscription, DNS, system proxy, and TUN in order.
Chapter 05 / Network stack
Coordinating TUN mode and Fake-IP
The system proxy covers only applications that actively follow proxy settings. Command-line tools, some games, apps with independent network stacks, and programs that send UDP directly may bypass it completely. TUN mode uses a virtual network interface to take over system routes and send this traffic into the Clash core, providing broader coverage. Fake-IP returns a mapped address during DNS resolution so that, when the application connects to it, the core can restore the original domain and apply domain rules. They are often used together, but serve different roles: TUN brings traffic in, while Fake-IP preserves domain semantics.
TUN fields and system permissions
tun:
enable: true
stack: mixed
dns-hijack:
- any:53
- tcp://any:53
auto-route: true
auto-detect-interface: true
strict-route: true
mtu: 1500
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
stack selects the network-stack implementation used by TUN. mixed balances compatibility and performance in supported cores; if a particular platform behaves unexpectedly, test system or gvisor separately instead of switching repeatedly without a comparison. auto-route writes routes automatically, while auto-detect-interface attempts to identify the current egress interface. This reduces manual interface maintenance when a device switches between Wi-Fi, mobile data, and Ethernet. strict-route more aggressively prevents traffic bypasses, but may expose routing conflicts with other VPNs, virtual machines, and container networks.
TUN startup requires system-level VPN or network-extension permission. A Windows client may use service mode to elevate network-operation permissions; macOS requires approval for the network extension; Android and iOS show a system VPN authorization prompt. When permission is denied, the interface toggle may turn on briefly and then revert, while logs show device-creation or route-writing errors. Reimporting the subscription repeatedly will not help; handle system authorization first. For macOS-specific prompts and recovery steps, see the network extension and Keychain guide.
How Fake-IP mappings work
When Fake-IP mode receives a domain query, it does not immediately give the real address to the application. Instead, it assigns a mapped address from a reserved range. When the app connects to that address, the core restores the domain from the mapping table and matches DOMAIN, DOMAIN-SUFFIX, or a rule provider. This allows Clash to retain the original domain even when an application passes only the destination address to the network layer. A mapped address is not the address of a remote server and should not be used for public-network routing tests. Results in the 198.18.0.0/16 range usually indicate that Fake-IP is participating normally in resolution.
Some LAN discovery, time-sync, printer, gaming-platform, or real-DNS-dependent applications do not work well with Fake-IP and need to be added to fake-ip-filter. Keep exclusions as specific as possible. Excluding an overly broad domain set sends many requests back to real-address mode, weakens domain restoration, and may force rules to depend on IP matching. When compatibility fails, identify the domain in the logs, add one suffix at a time, and retest instead of copying an unexplained, oversized filter list.
MTU, UDP, and network switching
If pages load but some images, uploads, or a particular app stall, the path MTU may be unsuitable. TUN encapsulation adds overhead, and an underlying VPN, PPPoE link, or mobile network may already impose limits, so 1500 bytes can cause fragmentation or packet loss. Keep the rest of the configuration unchanged and lower the MTU gradually—for example, test around 1400 first—while watching whether the issue consistently disappears. Smaller is not always safer: an MTU that is too low increases packet count and processing overhead. Once confirmed, choose the largest value that remains stable.
Separate UDP problems into three layers: whether the application sends UDP, whether TUN intercepts it, and whether the node protocol and network support that transport. DNS queries, QUIC, games, and voice traffic may all use UDP. If disabling QUIC restores browser access, that only localizes the fault to the UDP path; it does not mean DNS or the node is generally unavailable. After a mobile device switches between Wi-Fi and cellular data, an old session may still be bound to the previous interface. Reconnect TUN when necessary instead of immediately clearing the entire configuration.
| Interception method | Coverage | Best suited for |
|---|---|---|
| System proxy only | Applications that follow HTTP or SOCKS proxy settings | Browsers, ordinary desktop apps, and low-privilege environments |
| TUN + redir-host | Broader TCP/UDP traffic, with DNS returning real addresses | Environments requiring compatibility with real addresses |
| TUN + Fake-IP | Broad interception while preserving domain-matching capability | Devices with complex routing rules or apps that bypass the system proxy |
The recommended order is: use the system proxy first to confirm that nodes and rules work; enable TUN separately and verify routing and permissions; then enable Fake-IP and handle a small number of compatibility exceptions. If enabling TUN cuts off the entire device, turn it off to restore connectivity, then check the default route, DNS hijacking, and other VPNs. For Windows service mode, port conflicts, and system-proxy steps, see the complete Windows installation and configuration guide.
Chapter 06 / Sniffer
Domain sniffing and rule restoration
Some connections enter Clash with only a destination IP and no hostname that domain rules can use directly. Domain sniffing examines identifiable information near the start of a connection, such as SNI in a TLS ClientHello or Host in an HTTP request, then uses the recovered domain for rule matching. It does not read the full application payload and cannot recover a domain from every connection. Encrypted client handshakes, non-standard protocols, direct-IP requests, and some UDP traffic may not expose suitable fields for sniffing.
Basic configuration and protocol scope
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:
- "+.push.apple.com"
- "Mijia Cloud"
parse-pure-ip allows protocol characteristics to be inferred from targets shown only as IP addresses; force-dns-mapping works with Fake-IP mappings to help associate connections with DNS queries. override-destination determines whether the sniffed domain rewrites the destination. Enabling rewrites globally may improve domain-rule matches but can also break connections that depend on the original address. A safer approach is to keep it disabled globally and enable it only for confirmed-compatible protocols such as HTTP.
Port ranges should not be expanded without limit. HTTP sniffing usually covers known web ports, TLS mainly targets 443 and the encrypted ports used by the service, and QUIC is concentrated on UDP 443. Giving every protocol parser every port creates unnecessary checks and may misidentify non-standard binary protocols. For a service on an unusual port, confirm the protocol and port in the logs before adding a range. A broad port range does not reveal more useful information; it only expands the number of sniffing attempts.
How sniffing relates to Fake-IP
Fake-IP already preserves domains for most connections initiated through DNS, while sniffing serves as a supplementary path. It may recover a domain when an app bypasses system DNS, connects directly to a cached IP, or cannot associate the connection with a mapping. Enabling both does not mean the same task runs twice. Fake-IP creates mappings during resolution; sniffing observes protocol metadata during connection setup. When troubleshooting a rule match, check whether the log ultimately uses a mapped domain, a sniffed domain, or the original IP.
If a service always falls through to MATCH with sniffing disabled but matches a domain rule when sniffing is enabled, the original connection lacked usable domain context. Conversely, if enabling sniffing sends the connection to the wrong policy, check whether the sniffed domain belongs to a shared CDN, a redirect, or a third-party endpoint. One app often contacts multiple domains, so do not infer every connection from the main site alone. Temporarily raise the log level, run one short test, then restore info to avoid recording excessive connection detail.
Skip lists and compatibility boundaries
skip-domain excludes known domains that should not be rewritten or sniffed. Entries should come from verified failures, not from adding a broad list all at once. Some device-discovery and push services use mechanisms where certificate domains, connection addresses, and service identifiers do not align exactly; an incorrect rewrite can cause repeated connections. After adding a skip entry, reconnect the affected app because existing connections will not be rebuilt automatically under the new rules.
| Log output | Interpretation | Next step |
|---|---|---|
| Only the destination IP is visible | No domain was recovered, or the protocol cannot be sniffed | Check DNS interception, the protocol, and the port range |
| A domain is recovered but still matches MATCH | The rule does not include the domain, or an earlier rule captured it | Verify the actual domain and adjust rule order |
| Connections fail after destination rewriting is enabled | The target depends on the original address, or the identified domain is unsuitable for rewriting | Disable global rewriting or add a precise skip entry |
| The browser works, but QUIC fails | A UDP-path, node-capability, or QUIC-sniffing problem | Disable QUIC for comparison and check TUN UDP handling |
To verify sniffing, choose a domain with clear rules. Record the match with sniffing disabled, then enable it and establish a new connection for comparison. Do not change DNS, rule providers, and the target policy at the same time, or you will not know which layer caused the difference. When testing a browser in system-proxy mode, the browser usually already provides the domain to the proxy, so sniffing may make little difference. It is more useful with TUN interception, direct-IP connections, and apps that bypass system DNS.
Domain sniffing cannot replace rule design. After recovering a domain, you still need a specific rule before broad rules and an existing proxy group for the target. If an app accesses many dynamic subdomains, prefer a verified suffix rule or rule provider instead of continually adding complete domain names. See the terminology guide for the relationship between SNI, Fake-IP, TUN, and rule mode.
Chapter 07 / Merge
Local overrides and merging multiple subscriptions
A subscription supplies remotely maintained nodes and a baseline configuration; local overrides preserve adjustments specific to a device or personal environment. Editing both directly in one file means the next subscription update may overwrite local changes, while copying everything into a static configuration loses node updates. A better structure treats the subscription as upstream input and puts ports, DNS, added proxy groups, rule ordering, and TUN settings into a repeatable override layer. Clients use different names for this mechanism—Merge, Mixin, Script, or global extensions—but the goal is the same: regenerate the active configuration after updates.
Distinguish replacement, appending, and deep merging
YAML objects can be merged by key, but arrays have different semantics. Changing dns.enable usually replaces one field; handling rules requires deciding whether to prepend rules, append them, or replace the entire array. If a merger directly overwrites the old array, an override containing only three local rules may remove every rule from the subscription. Before using a client's built-in merge function, inspect the final active configuration rather than checking only whether the override fragment was saved.
prepend-rules:
- DOMAIN,router.local,DIRECT
- DOMAIN-SUFFIX,corp.example,DIRECT
append-rules:
- MATCH,Main Selection
override:
mode: rule
log-level: info
ipv6: false
The structure above illustrates three intentions—prepend, append, and replace. The exact keys depend on the client's merge implementation and must not be loaded directly as native mihomo configuration without confirmation. mihomo still receives one complete configuration in the end. To verify it, open the runtime configuration generated by the client and confirm that local rules appear in the expected position, proxy groups are not duplicated, and only one MATCH remains. If the client provides a configuration checker, run it after every update.
Merge multiple subscriptions at the node layer
When using several subscriptions, the most stable approach is usually to declare them as separate proxy-providers and import them into local proxy groups with use, rather than concatenating multiple complete configuration files. Complete profiles often contain their own ports, DNS, proxy groups, and rules; identical keys overwrite one another, identical groups conflict, and the outcome depends on the merger. Providers should handle node collections, while the local main configuration handles unified policies and rules. The responsibilities remain clear.
proxy-providers:
primary:
type: http
url: https://example.com/subscription/primary
path: ./providers/primary.yaml
interval: 86400
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 600
backup:
type: http
url: https://example.com/subscription/backup
path: ./providers/backup.yaml
interval: 86400
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 900
proxy-groups:
- name: Main Selection
type: select
use:
- primary
- backup
proxies:
- DIRECT
The subscription URLs in the example show structure only. Replace them with your own valid URLs, and never expose links containing access credentials in documents, screenshots, or shared repositories. The two providers must use different cache paths. Adjust health-check intervals according to the device and node count; mobile devices should not poll large node lists too frequently. If upstream node names collide, the interface may make their sources difficult to distinguish. Use a client-supported prefix feature at the merge layer or place each provider in a separate regional group instead of mixing everything into one long list.
Update failures and configuration drift
In multi-subscription setups, the common problem is not a configuration that fails to load once, but one that gradually drifts from expectations. An upstream provider may rename nodes and invalidate filters; removing a region may leave a proxy group empty; adding a duplicate node name may make manual selection point to another source. After an update, check provider status, whether group member counts are reasonable, and whether key service rules still point to existing groups. Do not monitor fictional fixed node counts. Watch whether groups are empty, references exist, and important requests still match as expected.
When syncing across devices, do not sync the entire client data directory. Desktop and mobile systems differ in permissions, paths, TUN interface names, and cache locations. Sync subscription sources, a local main-configuration template, rule providers, and override logic instead, while keeping device-specific settings in each client. For differences between WebDAV, subscription distribution, and manual imports, continue with the Clash multi-device configuration sync guide.
| Content | Best maintained remotely | Best kept locally |
|---|---|---|
| Node collection | Subscription or proxy-provider | Temporary test nodes |
| Public rule providers | rule-provider | A small number of device and intranet exceptions |
| Proxy-group structure | Controlled main configuration | Manual selections and device-specific differences |
| TUN, ports, and permission-related settings | Usually not synced directly across platforms | Maintained per device and operating system |
Chapter 08 / Controller
External controller and operational maintenance
mihomo provides an external control interface that client UIs and browser-based dashboards can use to read proxy groups, switch nodes, view connections, refresh providers, and inspect logs. The controller manages the running core; it does not replace the configuration file. A temporary policy switch in the dashboard can take effect immediately, but adding rules, changing DNS, or modifying TUN parameters still requires editing and reloading the configuration. Treat the controller as an entry point to runtime state, not as a configuration editor.
Listen address, secret, and access scope
external-controller: 127.0.0.1:9090
secret: "your-password"
external-ui: ./ui
external-ui-name: dashboard
For local-only use, the controller should listen on 127.0.0.1. Setting it to 0.0.0.0 accepts connections from other network interfaces and should be used only when LAN administration is explicitly needed and a firewall is configured. secret authenticates the interface; use a separate value generated for this purpose and do not share it with subscription credentials or other accounts. The dashboard and controller can be hosted in different places, but the browser must still reach the controller address and satisfy protocol, secure-context, and cross-origin requirements.
Do not expose the controller port directly to the public internet for remote management. A safer approach is to access it from a trusted LAN or enter the device network through a controlled secure tunnel. If you only need to view Clash status on a home router, restrict source addresses and keep the firewall rules in place. The controller can switch exits, terminate connections, and read runtime information, so its access scope deserves the same caution as the router's administration page.
Using the connections view with logs
The connections list usually shows the source, destination, protocol, rule, policy chain, and traffic state. When troubleshooting an app, first narrow the view or clear existing entries, then trigger one request again. The policy chain shows which service group received the request and which node it ultimately used; the rule field shows which rule matched. If a page fails to open but the connections list has no entry at all, the problem usually occurred before traffic entered the core. Return to the system proxy, TUN routing, or the app's own proxy settings.
Keep the info log level for everyday use. When you need DNS, handshake, or sniffing details, switch briefly to debug, reproduce the issue once, and restore it immediately. Long-term verbose logging increases output and can bury real errors under normal entries. Before sharing logs, check for subscription URLs, internal domains, destination addresses, and authentication fields, and share only the portion around the failure time.
Refreshing providers and checking policy state
Dashboards usually allow manual refreshes for proxy and rule providers. The refresh button updates the selected resource; it does not reload the entire configuration. After a proxy provider update, new nodes enter the groups that reference it, but existing connections do not all migrate automatically. After a rule-provider update, new requests use the new rules while existing long-lived connections may keep their original policies. To verify an update, establish a new test connection and inspect the provider's latest error status instead of checking only whether the button finished spinning.
Persisting proxy selections depends on profile.store-selected and the client's data-directory permissions. If every restart returns to the default node, first confirm that the field exists in the final configuration, then check whether the client can write to its runtime directory. With multiple profiles using the same group name, persisted state can also make the result differ from the apparent default configuration. For testing, create a clearly named group, confirm that persistence works, and then deal with old state.
| Dashboard capability | Best suited for | Does not replace |
|---|---|---|
| Policy switching | Immediate exit selection and comparison tests | Proxy-group design |
| Connection inspection | Confirming rules, policy chains, and protocols | System-level packet capture and routing checks |
| Provider refresh | Updating node collections or rule resources | Full configuration reload |
| Log monitoring | Locating resolution, connection, and rule errors | Long-term performance conclusions |
A repeatable maintenance sequence
A practical maintenance routine has four steps: update subscriptions and providers, then confirm that every resource has loaded; verify that “Main Selection” and key service groups still have available members; use one domain request and one TUN-dependent app to check the rule chain; finally restore the usual log level and export the current working configuration. If something breaks after an update, compare the scope of the change first: node-only changes point to providers and proxy groups, rule-only changes point to match order, while client upgrades or system-network changes call for permission and routing checks.
When the dashboard cannot connect, first confirm that the core is still running, then check the controller address, port usage, and secret. If a browser opens a local dashboard that is meant to connect to a remote device, make sure the address is not set to 127.0.0.1 on the device running the browser. If the client already includes a built-in dashboard, use that entry point first; it usually handles the current port and authentication automatically. To choose another client, see the platform guide, and use the download page for installation packages.
Next step
Change one configuration variable at a time
Choose one change from the chapter that matches the current problem, reload, and verify it through the logs and connections view. For basic operations, see the quick-start tutorial; for technical terminology, open the terminology guide; if the client is connected but the network is down, use the step-by-step troubleshooting checklist to locate the break.