mihomo Advanced Configuration Guide

Advanced Clash Usage: Policies, Rules, and Traffic Interception

Starting with policy group design, this guide covers rule providers, DNS, TUN, Fake-IP, domain sniffing, subscription merging, and external controllers. Examples primarily use mihomo configuration syntax and apply to Clash Plus, Clash Verge Rev, FlClash, and other clients that support the relevant fields.

8 configuration chapters config.yaml examples Parameter limits and troubleshooting paths

How the Quick Guide and Reference Guide Fit Together

The User Guide covers the main workflow: importing a subscription, choosing a mode, starting the proxy, and verifying the connection. This page does not repeat the installation wizard; it explains how configuration options work together and why changes take effect. If Clash is new to you, complete the basic connection steps in the tutorial first. Return here by section when you need to control how different sites are routed, fix DNS problems, capture traffic from apps that ignore system proxy settings, or manage multiple subscriptions.

Available configuration features depend on the client’s kernel and interface implementation. This guide uses common mihomo fields as its baseline; a client may present the same field as a toggle, dropdown, or override rule. Before editing, keep a copy of the last working configuration. Change one category of parameters at a time and check the logs after saving. This keeps a problem tied to the latest change instead of forcing you to guess across a file where DNS, TUN, and rules were all changed at once.

How to Read the Configuration and Apply Changes

Start by Separating the Five Processing Layers

When a connection enters mihomo, it does not go straight to a proxy node. The kernel first obtains the destination address. If an app supplies only an IP address, domain sniffing may recover the hostname. The DNS module controls resolution and maintains the real-address or Fake-IP mapping. The rule engine checks rules from top to bottom and stops at the first match. That result points to a policy group, which selects a specific proxy, a direct connection, or a rejection. TUN sits closer to the system network and sends traffic that would normally bypass the system proxy into the kernel. Once this chain is clear, troubleshoot in order: was traffic captured, is a domain available, did resolution succeed, which rule matched, and which policy was ultimately selected?

A configuration file typically contains ports, the operating mode, DNS, TUN, proxy providers, policy groups, rule providers, and rules. Field position does not determine execution order, but YAML nesting and indentation determine whether a field belongs to the correct module. Two spaces are a common indentation style, and list items use a hyphen. Write Boolean values as true or false without quotes; use integers for ports; quote ordinary strings containing colons, hash signs, or other special characters. Before saving, use the client’s configuration checker to rule out syntax errors before investigating network behavior.

mixed-port: 7890
mode: rule
log-level: info
ipv6: false

profile:
  store-selected: true
  store-fake-ip: true

dns:
  enable: true
  enhanced-mode: fake-ip

rules:
  - DOMAIN-SUFFIX,example.com,DIRECT
  - MATCH,Select Node

The skeleton above shows hierarchy only; it is not a complete subscription. mixed-port accepts both HTTP and SOCKS connections, which is useful when local apps can share one port. mode: rule enables rule-based routing. store-selected remembers the selected policy group member. MATCH is the final fallback. If the client already generates proxies and policy groups from a subscription, do not delete existing sections just to copy the example. Add only the fields you need to change in the override section.

Build a Change Process You Can Roll Back

A reliable configuration workflow keeps three states: the original subscription configuration, the current working configuration, and the change under test. The original confirms what the upstream supplied; the working copy is your rollback point; the test configuration serves one clear goal, such as “keep development domains direct” or “use TUN to capture command-line tools.” When the client supports overrides, put local changes in an override file instead of editing the downloaded subscription directly. A refresh usually replaces the main configuration, so direct edits may disappear, while a separate override is easier to review and migrate.

After each change, start with low-cost checks: can the configuration load, do the logs show parse errors, did the system proxy or TUN start successfully, and do one direct target and one proxied target work independently? Then verify rule matches and DNS. Do not use “the webpage opened” as the only success criterion: browser cache, existing connections, and the system DNS cache can hide problems. For rule tests, try a new domain or restart the target app. For DNS tests, clear the app’s connections and watch the kernel logs for queries and matches.

Symptom Check First How to Confirm
An app produces no connection records at all System proxy or TUN capture Check the app’s proxy settings, TUN status, and routing logs
Logs show only a destination IP, not a domain DNS and domain sniffing Check the connection source, sniffed protocol, and DNS mode
A domain uses the wrong policy Rule order and rule provider contents Check the rule type and policy name that actually matched
The policy is correct but the connection fails Policy group selection and proxy availability Switch to another node in the group and compare direct and proxied results

Use info for routine logging. Temporarily switch to debug when tracing rules and DNS, then switch back to avoid excessive logs obscuring the issue. If the interface and kernel logs disagree, judge by whether the kernel loaded the configuration and whether the connection actually appears. If the cause is still unclear, use the FAQ to compare basic troubleshooting categories. For system proxy versus TUN questions, continue with How TUN Mode and System Proxy Work.

Policy Group Types and Practical Combinations

Selection, Health Checks, and Failover

A policy group sits between a rule result and a specific proxy. Rules should point to groups with clear business meaning, such as “Node Selection,” “Streaming,” or “Development Services,” rather than to a node that may change when the subscription updates. This way, refreshing a subscription, removing a node, or temporarily changing routes requires only a policy group adjustment, not edits to many rules. The most common select group lets the user choose a member explicitly. Its behavior is predictable, making it suitable for the main entry point and services that require a fixed egress. A group can contain concrete proxies and reference other policy groups, forming a hierarchy such as “service group → region group → latency-test group.”

url-test periodically tests group members against the configured URL and selects the one with the better result. It works well for everyday automatic selection, but the result reflects connectivity to the test target and does not guarantee the same path to the site you actually need. fallback prioritizes availability, usually choosing the first available member in order, making it suitable for primary and backup routes. load-balance distributes connections across multiple members and is useful when connections genuinely need to be spread out. It may give the same service different egress IPs within a short period, so use it cautiously for logins, payments, or services that require session consistency.

proxy-groups:
  - name: Node Selection
    type: select
    proxies:
      - Automatic Selection
      - Failover
      - DIRECT

  - name: Automatic Selection
    type: url-test
    use:
      - provider-main
    url: https://www.example.com/
    interval: 600
    tolerance: 80
    lazy: true

  - name: Failover
    type: fallback
    use:
      - provider-main
    url: https://www.example.com/
    interval: 600
    lazy: true

use references proxy providers, which is useful when subscription nodes change dynamically; proxies lists fixed members or other group names. interval sets the test interval. A value that is too short increases network requests and battery usage on mobile devices, while a value that is too long delays detection of unavailable routes. tolerance reduces frequent switching caused by minor score fluctuations: the new result must differ by enough before the selection changes. When lazy is enabled, groups that have not been used for a long time can reduce unnecessary active tests.

Build Groups Around Services, Not Rule Counts

Policy group names should describe the decision, not where the rule came from. A group called “Video Rule Set” couples rules to routing; “Streaming” keeps the egress meaning clear whether the match came from a domain rule or a rule provider. A basic structure usually needs only a main entry point, automatic selection, failover, and direct access, with extra groups added only for genuinely different services. More groups mean more selections to check after a subscription refresh and increase the risk of circular references. mihomo cannot resolve a final proxy from a circular policy, such as A referencing B while B references only A; avoid this structure during design.

Region groups can filter proxy providers, but filtering depends on node names. Names come from the subscription and may contain Chinese region names, English abbreviations, or symbols. An expression that is too narrow will miss nodes; one that is too broad may include the wrong ones. After configuration, open the group in the client and verify its member list instead of checking only whether the syntax passes. For services that require a preferred fixed egress, use select and lock the choice manually. For general browsing, the main entry point can default to automatic selection.

proxy-groups:
  - name: Development Services
    type: select
    proxies:
      - Node Selection
      - Failover
      - DIRECT

  - name: Local Direct
    type: select
    proxies:
      - DIRECT
      - Node Selection

rules:
  - DOMAIN-SUFFIX,internal.example,DIRECT
  - RULE-SET,development,Development Services
  - GEOIP,LAN,DIRECT,no-resolve
  - MATCH,Select Node

DIRECT and REJECT are built-in policies that can also be rule targets. Direct access does not mean bypassing the kernel: in rule mode, the connection may still enter Clash before the kernel opens it directly. If local network devices behave unexpectedly, check together whether the rule is direct, whether TUN created conflicting routes, and whether the operating system firewall allows the traffic. A reject policy suits domains that are clearly unwanted, but an overly broad rule provider can remove page resources. After editing, test the main page, login, images, and API requests—not just whether the homepage opens.

Automatic Latency Tests Do Not Fully Measure Service Availability

A reachable test URL only shows that the proxy can reach that test target. A particular service may still depend on egress region, session consistency, or policies on the destination side. Keep a manual selection entry point for important services.

When troubleshooting a policy group, first confirm that it has members, then confirm that the current member can establish a connection, and finally check that the rule really points to the group. If the group becomes empty after a subscription update, common causes include a failed proxy provider or a filter that no longer matches the new names. If the group works but resets after every restart, check whether profile.store-selected is enabled and whether the client is using a temporary configuration over its persistent directory. Compare clients by platform on the downloads page. GUI users should start with Clash Plus, then choose Clash Verge Rev or FlClash based on system requirements.

Rule Provider Subscriptions Management

Rule Order Determines the Final Result

Clash processes rules from top to bottom and stops at the first match. The number of rules matters less than their priority. Put the most specific custom rules first, such as individual domains, exact suffixes, and local network addresses. Follow them with service rule providers, then handle regional IP ranges, ordinary direct access, and the final fallback near the end. If MATCH appears in the middle, later rules will never run. A broad domain suffix placed before an exact rule also prevents the exact rule from taking effect.

DOMAIN matches a complete domain and suits a single host; DOMAIN-SUFFIX matches a domain and its subdomains and suits an entire site family; DOMAIN-KEYWORD is broader and can produce false matches, so use it only when the domain structure is genuinely inconsistent. IP-CIDR and IP-CIDR6 handle address ranges. IP rules may trigger resolution. If the decision was already made by domain or the rule only concerns the existing destination IP, add no-resolve where appropriate to avoid an extra lookup.

rule-providers Behavior Types

Rule providers keep external rule files separate from the main configuration. behavior: domain suits collections containing only domain entries; behavior: ipcidr is for address ranges; behavior: classical supports complete entries with rule types and parameters and offers the most expressive format. The behavior must match the file contents. Putting DOMAIN-SUFFIX,example.com in a file that accepts only domain payloads, or using a plain address range as classical, can cause loading failures or rules that never match.

rule-providers:
  development:
    type: http
    behavior: classical
    format: yaml
    path: ./ruleset/development.yaml
    url: https://rules.example.com/development.yaml
    interval: 86400

  local-network:
    type: file
    behavior: ipcidr
    format: yaml
    path: ./ruleset/local-network.yaml

rules:
  - DOMAIN,build.internal.example,DIRECT
  - RULE-SET,development,Development Services
  - RULE-SET,local-network,DIRECT,no-resolve
  - MATCH,Select Node

type: http updates from a URL, while type: file reads only a local file. path is the cache or local file location. Give each provider its own filename so rule sources do not overwrite one another. interval uses seconds as the update period. When rules change infrequently, there is no need for a short interval; a daily update is easier to control. Use a stable HTTPS source for remote URLs. Keep internal rules on a controlled service rather than relying on temporary links.

payload:
  - DOMAIN,api.example.com
  - DOMAIN-SUFFIX,developer.example
  - PROCESS-NAME,git
  - IP-CIDR,192.0.2.0/24,no-resolve

This is a common structure for a classical YAML rule file. A provider file contains match conditions only, not the final policy; the policy is assigned in the main configuration with RULE-SET,development,Development Services. The same rule set can therefore point to different policies on different devices—for example, “Development Services” on a desktop and a fixed egress on a server. To change the policy, edit the main configuration instead of copying and maintaining a second set of rule data.

Boundaries for Maintaining Subscribed Rules

Do not split rule sets indefinitely. Each provider adds download, parsing, caching, and troubleshooting overhead. A set is a good candidate for separation when it has a clear ownership boundary: it is maintained by different people, updates at a different rate, is reused across configurations, or needs to be enabled and disabled independently. Three or four small, stable local rules are clearer at the top of the main rules list. Name providers by purpose, such as work-services or private-network, rather than using opaque names like rules1.

When an update fails, first distinguish a remote download failure from a file parsing failure. For the former, check whether the URL is reachable, DNS works, and whether the proxy provider must update through a proxy. For the latter, inspect the behavior type, format, indentation, and payload structure. Some clients continue using an existing cache, so a page remaining accessible does not prove that the update succeeded. Check the provider name and update time in the logs, then update manually and look for new errors. For GeoIP or GeoSite rule issues, continue with How to Update GeoIP and GeoSite Databases.

behavior Best For Typical Payload
domain Domain collections example.com+.example.com
ipcidr IPv4 and IPv6 address ranges 192.0.2.0/24
classical Mixed rule types and additional parameters DOMAIN-SUFFIX,example.com

After rule maintenance, establish a fixed test set: one clearly direct domain, one clearly proxied domain, one local network address, one IP-only connection, and one final fallback target. Run the same tests after each rule source update to quickly detect order changes, failed providers, and false matches. Evaluate the matched rule and policy name rather than substituting the visual result in a webpage. This keeps rule sets explainable even as they grow.

DNS Configuration Optimization and Split Routing

Start by Defining mihomo DNS's Role

With mihomo DNS enabled, the kernel can process domain queries according to rules and associate the results with subsequent connections. This is not simply about “switching to another DNS address”; it keeps name resolution and proxy decisions on the same path. If an app uses encrypted DNS on its own, connects directly to a hard-coded address, or reads a separate hosts file, the query may bypass the kernel. In that case, changing only nameserver may not change the app’s behavior; also check TUN DNS hijacking, browser settings, and domain sniffing.

default-nameserver is mainly used to resolve the hostnames of other DNS servers. It commonly uses directly reachable IP addresses to avoid a startup loop: “to reach encrypted DNS, resolve its hostname first, but no usable DNS is available yet.” nameserver handles ordinary queries. proxy-server-nameserver can resolve proxy server hostnames separately, reducing dependence on ordinary split routing. nameserver-policy assigns DNS servers by domain and suits internal domains, local network names, or services with genuinely different resolution requirements.

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.example.com/dns-query
  proxy-server-nameserver:
    - 223.5.5.5
  nameserver-policy:
    "+.internal.example":
      - 192.168.1.1
  fake-ip-filter:
    - "*.lan"
    - "+.internal.example"
    - "time.*"

Replace the example addresses according to your network. Set listen only when other local programs actually need to query the resolver. If it binds to all interfaces, also verify the system firewall and the local network boundary. Desktop clients usually manage the listening address automatically, so do not expose it merely to copy a configuration. ipv6: false prevents the DNS module from returning IPv6 results and suits networks without a stable IPv6 path. If both the network and proxy fully support IPv6, enable it and test direct and proxied targets separately.

Choosing Between Fake-IP and redir-host

In fake-ip mode, the app first receives a mapped address. When it connects to that address, the kernel restores the original domain and applies domain rules. This makes rule matching more direct and avoids losing the information that would otherwise be reduced to “resolved to an IP, so judge by address.” The mapped address has meaning only inside the local kernel and must not be treated as the destination’s real address. If packet captures, logs, or an app diagnostic screen show addresses such as 198.18.0.0/16, first determine whether they come from a Fake-IP mapping instead of treating them as abnormal DNS results.

Some local network services, device discovery, connectivity checks, time synchronization, and apps that require real addresses are not suitable for Fake-IP and should be added to fake-ip-filter. These domains then receive real resolution results. Keep the filter narrow at first; excluding large numbers of top-level domains weakens Fake-IP’s domain association. When compatibility issues arise, start with a specific domain, confirm it in the logs, and then add a suffix if needed. redir-host returns real IP addresses and follows a more traditional resolution model, but the relationship between domains and connections differs. Switch globally only when a confirmed Fake-IP compatibility issue cannot be solved with filtering.

nameserver-policy and the Resolution Path

Internal services often require resolution through a router or corporate DNS server because public DNS has no record of them. Use nameserver-policy to send selected suffixes to internal servers, and put a direct rule for those domains near the top of the rules list. DNS routing and connection routing must agree: if internal DNS returns a private address but the rule sends the connection through an external proxy, access will usually fail. If public DNS returns a public address but the connection is expected to reach an internal service, that can fail too. Review “who resolves the name” and “which policy carries the connection” as one unit.

When respect-rules makes DNS connections follow rules, ensure the path used to resolve proxy node hostnames does not depend on a proxy that has not been established. Configure a directly working proxy-server-nameserver and avoid DNS rules that form a loop. If every connection stalls during resolution after startup, temporarily use a directly reachable base DNS, confirm that proxy server hostnames resolve, then gradually restore encrypted DNS and rule-based split resolution.

Clear Existing Connections Before Retesting DNS

Apps, operating systems, and browsers may all cache resolution results. After changing the configuration, close existing connections in the target app and restart it if necessary, then watch for new DNS queries and rule matches.

During troubleshooting, first use the logs to confirm that queries reach mihomo. If there are no query records at all, check whether system DNS points to the kernel, whether TUN DNS hijacking is active, and whether the app has its own DNS enabled. If queries exist but fail, check upstream reachability and whether domain-based DNS addresses can be resolved by default-nameserver. If resolution succeeds but the connection still fails, continue with the policy and actual destination instead of stopping at the DNS layer. If only local device names fail, check search domains, router DNS, and Fake-IP filtering rather than making every domain direct.

Field Primary Role Common Mistake
default-nameserver Resolve the hostnames of DNS services Fill in only hostnames and create a startup resolution loop
nameserver Handle ordinary domain queries The upstream is unreachable, but the issue is treated as a rule failure
proxy-server-nameserver Resolve proxy server hostnames Depend on a proxy channel that has not been established
fake-ip-filter Return real addresses for compatibility targets The filter is too broad and domain association is lost

There is no single universal answer for DNS optimization. A stable setup usually has three traits: its base resolution path can start independently; internal domain resolution matches the connection policy; and Fake-IP exceptions have specific reasons and clear boundaries. After configuring, test an ordinary webpage, a local network domain, a proxy server hostname, and an IPv6-only target separately. Record the expected DNS server and policy for each class so that when you change networks, you can quickly tell whether the cause is a local network change or configuration drift.

TUN and Fake-IP Cooperative Configuration

When Do You Need TUN?

The system proxy works only for apps that actively read the operating system’s proxy settings. Command-line tools, some games, virtual machines, and software that always uses direct sockets may bypass it. TUN creates a virtual interface at the operating-system network layer and uses routes to send more TCP and UDP traffic into the kernel, making it suitable when broader capture is required. It is not inherently faster than the system proxy and should not be the default fix for every problem. When browsers and ordinary desktop apps already work reliably with the system proxy, a simpler configuration is usually easier to maintain.

Starting TUN involves a virtual network adapter, routing tables, DNS, and system permissions. Desktop clients may request a service installation or network extension authorization; mobile platforms use the system VPN interface. A switch showing “enabled” does not prove that all traffic entered the kernel. Check the logs for successful TUN interface creation, routes, and DNS hijacking, then verify that the target connection appears. On macOS, if network extension or Keychain authorization is an issue, see macOS Network Extension and Keychain Fixes.

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

auto-route makes the kernel add the required routes automatically; auto-detect-interface chooses the egress interface for the current network and suits devices moving between wired, wireless, and mobile hotspots; strict-route reduces the chance of traffic bypassing the tunnel but may conflict with routes from virtual machines, containers, or other VPNs. If a local or corporate network becomes unreachable after enabling it, check for route conflicts first. Decide whether to disable strict routing or add an explicit exclusion instead of changing the proxy node.

stack, MTU, and UDP Behavior

The TUN stack depends on the kernel version and platform capabilities. Common options include system, gvisor, and mixed. The system stack uses the operating system’s network implementation, so compatibility and performance vary by platform. The gVisor userspace stack provides an alternative path and can help compare results when the system stack has a specific issue. mixed combines handling for different traffic types and is a practical starting point for many desktop scenarios. Do not judge by the names alone; test TCP, UDP, local network traffic, and sleep/wake recovery on the same network and targets.

An MTU that is too large may cause fragmentation or path-discovery problems that look like “small pages load, but large files or certain requests stall.” An MTU that is too small increases packet count and overhead. Leave the default unchanged when it works. If MTU is suspected, first confirm that the problem occurs only with TUN, switch to the system proxy for comparison, and lower the value gradually. Do not change the stack and DNS at the same time. For UDP issues, also confirm that the selected proxy supports the required transport. TUN captures traffic; it cannot add UDP support to a proxy that lacks it.

Why Fake-IP Is Often Paired with TUN

TUN receives many connections that would otherwise bypass the system proxy. If the DNS query made before connection setup is also redirected to mihomo, Fake-IP preserves the domain information so those connections can continue using domain rules. If DNS completes outside the kernel, TUN sees only the real IP and routing may fall back to IP matching or the final rule. Check TUN, DNS hijacking, and Fake-IP as one chain: did the app’s query enter the kernel, was the mapping saved, was the domain restored when the app connected to the mapped address, and did the expected rule match?

Some apps connect to hard-coded IP addresses and have no domain information from the start. Fake-IP cannot create a domain in that case. You may need IP rules, process rules, or domain sniffing that can identify the destination from protocol contents. Process rules vary in availability across platforms, with more restrictions on mobile. Keep a final fallback and choose rule types based on what the logs actually show; do not assume every connection can recover a domain.

Common sources of conflict include other VPNs, virtual machine bridges, container networks, local proxy tools, and security software. When several programs modify the default route or DNS, the one started later may overwrite the earlier settings. Record startup order, temporarily disable other network tools, and run Clash alone. If TUN stops working after sleep or wake, restart the TUN interface first. If it fails after switching Wi-Fi, check automatic egress interface detection. Analyze rules and proxies only after confirming that routes were created correctly.

Keeping TUN enabled continuously on a mobile device keeps the kernel resident, while frequent latency tests, complex rules, and repeated DNS queries increase battery use. Reduce automatic test frequency, remove unused rule providers, and allow the client to run reliably under the system’s background policy so it is not repeatedly stopped and forced to rebuild connections. For Android, see the Android Background Policy and Battery Drain Checklist.

Domain Sniffing and Rule Completion

Sniffing Fills in Missing Information

When a connection enters mihomo, the destination is sometimes only an IP address. Domain sniffing examines protocol information at the start of the connection and recovers a domain from locations such as the HTTP Host header or the server name in a TLS ClientHello, allowing domain rules to participate in the decision. It does not read all app content and is not a replacement for DNS. On an encrypted connection, the visible name is the target exposed during the handshake. If the protocol contains no domain, the handshake is further encrypted, or the connection uses an IP directly, sniffing cannot recover one.

Sniffing is useful when DNS completes outside the kernel but the connection still carries domain information. For example, an app may use its own DNS to obtain a real address and then start a TLS connection; the kernel may recover the server name from the handshake. The recovered name still goes through rule ordering. If its relationship to the original destination IP is unusual, blindly overriding the destination can break the connection. Start with common HTTP and TLS ports instead of covering every port and protocol.

sniffer:
  enable: true
  parse-pure-ip: true
  force-dns-mapping: true
  override-destination: false
  sniff:
    HTTP:
      ports:
        - 80
        - 8080-8880
    TLS:
      ports:
        - 443
        - 8443
    QUIC:
      ports:
        - 443
  force-domain:
    - "+.example.com"
  skip-domain:
    - "Mijia Cloud"
    - "+.push.example"
  skip-src-address:
    - 192.168.0.0/16

parse-pure-ip allows mihomo to try extracting a protocol domain from connections whose target is only an IP; force-dns-mapping uses DNS mapping information; override-destination controls whether the sniffed result replaces the original destination. When enabling sniffing for the first time, leave destination rewriting off and observe recovered domains in the logs. If a service clearly needs sniffed-domain routing, then evaluate whether to enable overriding. Field support varies by client kernel, so check the logs after loading the configuration to confirm that these parameters were accepted.

The Boundaries of force-domain and skip-domain

force-domain suits domains that clearly require sniffing, while skip-domain is for known compatibility problems or targets that must not be rewritten. Maintain both from logs and reproducible results instead of copying a large exclusion list of unknown origin. Device discovery, local services, persistent push connections, and apps with unusual certificate validation may need to be skipped. But when a connection fails, first rule out DNS, routing rules, and the proxy itself; do not attribute every failure to sniffing.

Exclude source addresses when local network devices are forwarded through the local machine but should not undergo domain identification. Confirm the actual local network ranges before setting them; an overly broad range removes domain rules from many connections. Be equally conservative with ports: use typical cleartext ports for HTTP sniffing, common encrypted ports for TLS, and UDP for QUIC. Sending every port to every protocol parser adds unnecessary checks and makes logs harder to read.

Determine Whether Sniffing Is Actually Working

For verification, choose a known domain. First confirm in the logs that the initial destination is an IP, then check whether a domain appears after sniffing and whether the final match uses a domain rule or an IP rule. If the connection already contained a domain, a successful match does not prove that sniffing was involved. Compare behavior with sniffing disabled if needed, but clear existing connections first. Browsers use connection pools, so a simple page refresh may not create a new connection.

If the logs show no sniffing result, confirm that traffic enters mihomo, the port is within the configured range, and the protocol is HTTP, TLS, or QUIC. If a domain is recovered but routing is wrong, check rule order and domain syntax. If enabling override-destination breaks the connection, disable overriding while keeping domain extraction enabled to confirm that destination rewriting is the cause, then add the target to the skip list. Record a specific domain or suffix and the reason for every exclusion so it can be reviewed later.

Log State Meaning Next Step
The connection never entered the kernel There was nothing for sniffing to process Check the system proxy or TUN
The connection entered the kernel but contains only an IP The protocol, port, or handshake contains no usable domain Review the sniffing scope; use IP or process rules if needed
A domain was recovered but the policy is wrong The rule priority or contents do not match the intent Check the first rule that actually matched
The connection failed after destination rewriting The target is not suitable for rewriting Disable overriding or add a precise skip entry

For long-term maintenance, record each sniffing exception together with the affected app, protocol, and observed failure. Keeping only the domain without the reason makes it difficult to tell months later whether the exclusion is still necessary. After migrating clients or kernels, re-test with a smaller scope instead of copying every historical exclusion unchanged. Follow this order—observe missing information, enable limited protocols, verify domain recovery, then decide whether to override—so sniffing remains a controlled tool rather than another source of uncertainty.

Local Overrides and Multiple Subscription Merging

Treat Subscriptions as Inputs, Not the Final Configuration

Remote subscriptions usually provide proxy nodes, basic policies, and some rules, but they may not know about your local network, internal domains, app habits, or platform permissions. Treat subscription content as input and use local overrides to form the final configuration for long-term maintenance. A refresh can replace the node list while the local override preserves DNS, TUN, custom rules, and policy group changes. Clients that support overrides may offer YAML overrides, script processing, or a merge interface. The entry point varies, but the goal is the same: avoid editing a main configuration that a refresh will overwrite.

Keep overrides limited to the keys you need to change. Copying the entire main configuration may seem clear, but it blocks new upstream fields and can preserve obsolete node names. Map fields can often be merged by key; array fields require special care because clients may replace, prepend, append, or process them with scripts. rules is the classic ordered array: simple replacement loses subscription rules, while simple appending may place your rules after MATCH, where they never run. Use the client’s “prepend rules” feature or insert them explicitly before the final fallback in a merge script.

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-filter:
    - "+.internal.example"

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true

profile:
  store-selected: true
  store-fake-ip: true

This local override contains no subscription proxies, making node updates independent from local network settings. After saving, inspect the final effective configuration rather than checking only the override file. If the client offers “preview merged result” or “open running configuration,” confirm that DNS and TUN fields appear only once, indentation is correct, and rules were inserted where intended. When duplicate keys exist, determine which layer wins instead of guessing through trial and error.

Designing the Structure for Multiple Subscriptions

Multiple subscriptions do not mean concatenating all node text. A more reliable approach is to create a separate proxy-providers entry for each source, give each one a different cache path, and have policy groups reference them through use. If one source fails to update, its cache will not affect another, and it is easier to identify where members came from. Keep provider names stable. Have policy groups reference providers rather than enumerating node names that may change.

proxy-providers:
  provider-main:
    type: http
    url: https://subscription.example.com/main.yaml
    path: ./providers/main.yaml
    interval: 21600
    health-check:
      enable: true
      url: https://www.example.com/
      interval: 900

  provider-backup:
    type: http
    url: https://subscription.example.com/backup.yaml
    path: ./providers/backup.yaml
    interval: 21600
    health-check:
      enable: true
      url: https://www.example.com/
      interval: 900

proxy-groups:
  - name: Node Selection
    type: select
    use:
      - provider-main
      - provider-backup
    proxies:
      - Automatic Selection
      - DIRECT

  - name: Automatic Selection
    type: url-test
    use:
      - provider-main
      - provider-backup
    url: https://www.example.com/
    interval: 600
    tolerance: 80

The example URL shows structure only. Use your own subscription address in practice and treat it as sensitive information. Each provider must use a different path; if paths are shared, a later update may overwrite an earlier cache. Provider health checks and policy-group latency tests are separate layers: provider checks mark member availability, while url-test selects within the group. Setting both intervals too short creates duplicate testing, so mobile devices should use especially generous intervals.

Different sources may contain nodes with the same name. When the interface shows names only, it is difficult to know which one you selected. Add a source prefix during merging, or split providers into intermediate groups such as “Primary Subscription” and “Backup Subscription,” then reference them from the main entry point. Do not rely on node order, which can change after a refresh. Validate filters per source so a naming change does not suddenly empty a region group.

Updates, Failures, and Rollback

Before updating a subscription, confirm that the current cache works. If the update fails, the client may continue using the old cache; do not delete it and retry repeatedly. First check subscription URL resolution, the network path, and the response format. If remote content downloads but cannot load, determine whether it is a complete Clash configuration or only a proxy provider file; their structures differ. A complete configuration cannot be used directly as a provider file unless the client supports conversion.

When upgrading a local override, migrate in small steps: merge the base profile and DNS first and confirm loading; then add rule prepending; finally enable TUN and sniffing. Copying an entire configuration from an old device at once may introduce incompatible platform-specific fields, paths, and interface names. Windows, macOS, Android, and Linux differ in permissions and network stacks. Keep the logic, but recheck listening addresses, TUN permissions, and local paths for each platform.

When migrating clients, first export subscription URLs and custom overrides, then record the current policy group selections. Do not treat a client’s internal cache directory as a long-term backup because its structure may change between platforms. For migration after the original client’s maintenance ends, see FlClash vs. Clash Verge Rev Migration Options. For a fresh installation, choose Clash Plus from the Clash client downloads page, install the build for your system and processor architecture, and import the configuration layer by layer.

External Controller and Security Boundaries

What the Control Interface Can Do

mihomo’s external control API reads runtime status, switches policy groups, updates providers, and shows connections and logs. A graphical client may also use this API to communicate with the kernel. An independent control panel is only a frontend for the API; it does not replace the kernel or change configuration-file permissions. Accessibility depends jointly on the external-controller listen address, the system firewall, and the authentication secret.

For local-only use, listen on a loopback address such as 127.0.0.1:9090. Other devices on the local network then cannot connect directly. If you need to manage it from another device, listen on a LAN address only with strong authentication, restricted firewall sources, and a trusted network. Binding the interface to every network adapter expands access. Do not judge security by whether a control-panel page appears to request a secret; protection must exist at the API connection layer.

external-controller: 127.0.0.1:9090
secret: "your-control-secret"
external-ui: ./ui

log-level: info
allow-lan: false

Replace the secret example with a unique value for this device, and never reuse a subscription URL or other account credential. If the client generates the control interface configuration automatically, change it in the client settings first to avoid manual overrides conflicting with the interface. external-ui points to a local static panel directory. Some clients download and manage panel assets automatically; others provide only the API and require a compatible frontend. Keep the path inside a configuration directory the client can read.

Connection Panel Troubleshooting Order

When the panel does not open, first distinguish the static page from the API. If the browser cannot open the panel files, check the external-ui path and the client’s resource management. If the page opens but reports that it cannot connect, check the controller address, port, secret, and browser origin. When the controller listens on loopback, entering the machine’s LAN IP from another device will still fail; that is the intended boundary. If you switch to a LAN listener, ensure the operating system firewall permits the specified sources rather than opening it to the whole network.

Whether the control panel uses HTTP or HTTPS depends on how it is deployed. Local use through a loopback address has a different risk profile from remote management over a LAN. For cross-device access, use a controlled local network or an existing secure tunnel instead of exposing the control port directly to the public internet. The API can switch policies, read connection destinations, and change runtime state, so treat it as an administrative interface rather than an ordinary status page.

curl -H "Authorization: Bearer your-control-secret" \
  http://127.0.0.1:9090/version

curl -H "Authorization: Bearer your-control-secret" \
  http://127.0.0.1:9090/proxies

These commands verify whether the local API responds. The first confirms that the interface and authentication work; the second reads the policy and proxy structure. If the response is unauthorized, check that the secrets match. If the connection is refused, check whether the kernel is running and the port is listening. If it connects but the path does not respond, confirm compatibility with the current kernel API. After debugging, do not save commands containing authentication information in shared scripts or public logs.

Using Connection Details and Logs Correctly

The connection list in a control panel answers three useful questions: did traffic enter the kernel, is the target a domain or an IP, and which rule and policy were used? A large number of connections is not automatically abnormal; modern webpages request many resources concurrently. During troubleshooting, filter by target app or domain, close old connections, and make one new request. This is more effective than watching an endlessly scrolling list.

After switching a policy group, existing TCP connections usually do not move to the new proxy automatically. If the result does not change, close the relevant connection or restart the target app, then observe the policy used by the new connection. After updating a rule provider, also confirm that a new connection matches the updated rules rather than relying on the completed update indicator. The panel shows runtime state, while the configuration file determines the next loaded state. Whether a temporary switch survives a restart depends on profile.store-selected and the client’s persistence mechanism.

Deployment Scope Recommended Listener Required Controls
Local-only management 127.0.0.1:9090 Use a dedicated authentication secret
Management on a trusted LAN A specific LAN interface address Authentication secret, source restrictions, and system firewall
Cross-network management Do not expose the control port directly Access the local interface through an existing secure channel

When the control panel and client interface show different states, first confirm that they connect to the same kernel instance and port. A device may be running an old client service, a command-line kernel, and a new client simultaneously. If the panel connects to another instance, it can look as though a policy switch had no effect. Check processes, listening ports, and configuration directories, close unnecessary instances, and reconnect. Record the controller address, panel path, and configuration-file location in the device notes so future migration is straightforward.

Configuration Validation, Troubleshooting, and Long-Term Maintenance

Verify the Full Chain in a Fixed Order

After completing a complex configuration, do not test several apps at once. First confirm that the kernel loaded the configuration without YAML or field errors. Then confirm that the system proxy or TUN captures traffic. Next verify DNS queries, domain sniffing, rule matches, policy group selection, and proxy connectivity. Each layer should answer one question. If the first layer has already failed, later webpage errors are not useful evidence. A fixed order prevents you from switching nodes in a policy group when the real issue is a missing TUN route.

Prepare a local test table with the target, expected rule, expected policy, and observed result. Cover at least a LAN direct connection, an ordinary direct domain, a domain that requires a proxy, an IP-only connection, a UDP app, and the final fallback. Record actual matches in the control panel or logs. Repeat the same tests after updating subscriptions, rule providers, DNS, or the client so results remain comparable and you can quickly identify whether a change came from content or the client environment.

# Check that the local mixed proxy port is listening
curl -x http://127.0.0.1:7890 https://www.example.com/

# Check the external control API
curl -H "Authorization: Bearer your-control-secret" \
  http://127.0.0.1:9090/version

These commands verify only the port and request path; they do not prove that every rule is correct. Success on the first command shows that an app can send a request through the local proxy. If the browser still fails, check its proxy source and existing connections. When a command fails, distinguish connection refusal, DNS failure, authentication failure, and request timeout. Do not reduce every error to “the node is unavailable”: an unlistening local port and a remote proxy failure require completely different fixes.

Create Troubleshooting Branches from the Symptoms

If every target fails, first check the kernel, port, permissions, basic DNS path, and current policy member. If only one domain fails, inspect domain resolution, the matched rule, and that service’s egress requirements. If only one app fails, check whether it uses the system proxy, has its own DNS, or sends only UDP. If the problem starts after changing networks, check the egress interface, routes, and LAN DNS. If it starts after a subscription update, check provider format, policy group members, and rule order.

The first error in the logs is usually more valuable than the cascade that follows. A DNS initialization failure can lead to proxy node resolution failures, provider update failures, and timeouts for every proxy. Looking only at the last message can make it seem as though multiple subscriptions failed simultaneously. Temporarily enable debug logging and read from kernel startup to find the first error related to the current change. Fix it, restart, confirm that it is gone, and then move to the next issue.

Control Variables During Upgrades and Migration

Do not upgrade the client, replace the kernel, and migrate the configuration at the same time. Export the working configuration and local overrides from the existing client first. After installing the new client, import only the subscription and establish a basic connection. Then add policy groups, rule providers, and DNS, and enable TUN, sniffing, and the external controller last. This makes it clear whether a failure comes from field support, platform permissions, or configuration content. Cross-platform migration also requires rechecking path separators, service permissions, network extensions, and firewalls.

Do not rely on an interface label staying unchanged forever. Long-term notes should focus on configuration fields and behavior, such as “enable profile.store-selected to save group selections,” rather than “open the second toggle on page three.” Button locations can change after an interface update, while field meanings are more stable. For system permissions that must be granted through the interface, add the platform path and the observable verification result.

Change Type Minimum Test Set Rollback Method
Policy Groups and Rules Check members, rule matches, and the final policy Restore the previous rule order and group definitions
DNS and Fake-IP Ordinary domains, internal domains, and node hostnames Restore a directly reachable base DNS and the original filter list
TUN and Routing TCP, UDP, LAN, and sleep/wake recovery Disable TUN and return to the system proxy
Subscriptions and Providers Update status, cache, and policy group members Use the pre-update cache and local overrides

When a problem occurs, preserve the logs, current configuration, and reproduction steps before rolling back. A single error screenshot is rarely enough to determine which layers the connection passed through. Reproduction steps should include the client, capture method, target app, expected policy, actual match, and network environment. If the basics are still unclear, use the FAQ under “Basics,” “Installation and Configuration,” “Usage Tips,” and “Troubleshooting.” To repeat subscription import and mode selection, return to The User Guide.

A stable long-term Clash configuration is usually not complicated: subscriptions provide proxies, policy groups express egress choices, rule providers supply reusable matches, DNS preserves domain information, TUN captures additional traffic only when needed, sniffing fills in missing domains, and the external controller stays within a defined boundary. Change one layer at a time and verify it with a fixed test set to keep the configuration readable, reversible, and portable as features grow.

Download the Latest Clash Version