This configuration reference is designed for ongoing use, not as a replacement for the main path from installation to the first connection. When using Clash Plus, Clash Verge Rev, FlClash, or another graphical client for the first time, start with the quick start guide to verify subscription import, the system proxy, and basic traffic routing. Return here to check a specific field, investigate an unmatched rule, or prepare to run the mihomo core directly on a server or router.
Graphical clients often add interface settings, override scripts, or a subscription-conversion layer on top of the original configuration, so the options shown in the interface may not correspond word for word to the YAML. When troubleshooting, first inspect the final configuration passed to the core rather than only the raw remote subscription. To choose another client or download the core, visit the Clash download page. Clash Plus is the preferred choice for ordinary desktop and mobile devices; running mihomo directly is better suited to users comfortable with command lines, service management, and network routing.
01 / DOCUMENT SHAPE
YAML structure overview: understand the hierarchy before editing fields
How the top-level sections work together
A working Clash Meta configuration is not a collection of unrelated fields; it is a processing chain with clear reference directions. General fields define the listening ports, runtime mode, and LAN access boundary; dns controls domain resolution; proxies and proxy-providers supply usable proxies; proxy-groups organize proxies and other groups into selection, latency-testing, or failover relationships; rule-providers supply external rule sets; finally, rules pass connections to a policy group in written order. If a name fails to match at any layer, later sections may fail during loading or runtime even when their syntax is valid.
YAML expresses parent-child relationships through indentation, typically using two spaces without tabs. Add a space after each colon, start list items with a hyphen, and keep fields at the same level equally indented. Whether to quote a string depends on its contents: ordinary English names can be written as-is, while values containing colons, hash signs, braces, or text that could be interpreted as a Boolean are safer in quotes. Proxy group names may contain spaces and non-ASCII characters, but every reference must match exactly, including capitalization, spaces, and punctuation.
mixed-port: 7890
mode: rule
log-level: info
allow-lan: false
dns:
enable: true
listen: 0.0.0.0:1053
enhanced-mode: fake-ip
nameserver:
- https://1.1.1.1/dns-query
proxies:
- name: "Example Node"
type: socks5
server: 127.0.0.1
port: 1080
proxy-groups:
- name: "Node Selection"
type: select
proxies:
- "Example Node"
- DIRECT
rules:
- DOMAIN-SUFFIX,example.com,Node Selection
- MATCH,DIRECT
Mappings, sequences, and scalars
dns: is followed by a mapping—a set of key-value fields; nameserver: is followed by a sequence, with each upstream server as a list item; and rule in mode: rule is a scalar. The most common structural mistakes are moving fields that belong to a list item back to the top level, or leaving the second node's fields indented inside the first node. For complex nodes, use the layout “one hyphen starts one complete object,” with each object's fields vertically aligned. This makes indentation errors easier to spot.
YAML anchors and aliases can reuse configuration fragments, but subscription converters, client overrides, and some editors do not handle advanced YAML syntax consistently. For configurations that need long-term maintenance, prefer clear, explicit fields. Introduce &name and *name only when many nodes genuinely share parameters and the entire loading chain is known to support anchors. Repeating a few lines is usually easier to troubleshoot than hidden inheritance.
Minimal and complete configurations
A minimal configuration can contain only a listening port, one proxy, one group, and a final rule, but real-world use often also requires DNS, subscription providers, rule sets, TUN, and persistence settings. Get the minimal skeleton loading first, then add sections one at a time. Troubleshooting only after adding a large, complex configuration makes it difficult to identify whether the problem is DNS, proxy parameters, or a rule reference. Validate each new section in three stages—successful loading, successful connection, and correct rule matching—instead of treating every symptom as proof that the configuration is unusable.
Comments in a configuration file begin with #. They are useful for recording a field's purpose and the reason for a change, but avoid repeatedly changing critical names that other parts depend on. Subscription updates may rebuild the proxy and group sections, and local comments may be overwritten. Keep long-term explanations in separate documentation; leave only short notes that help with live troubleshooting, such as a direct rule for LAN devices or a DNS upstream reachable only through a proxy.
02 / GENERAL
General fields: ports, mode, listeners, and runtime state
Choosing port fields
port provides an HTTP proxy port, socks-port provides a SOCKS5 port, and mixed-port accepts both HTTP and SOCKS5 requests on one port. When a desktop client needs to expose one proxy address to other applications, mixed-port is the simplest option. Use separate ports when software explicitly requires one protocol or when you need separate connection records. Any unused port number works; it does not have to be a familiar default.
redir-port and tproxy-port are transparent-proxy entry points, normally used with Linux firewall rules rather than as system proxy ports. Defining these fields alone does not capture traffic automatically; routing tables, policy routing, and nftables or iptables rules must work together. A graphical client's TUN mode usually creates the virtual interface and routes itself. Do not copy router transparent-proxy rules into it at the same time, or you may create duplicate forwarding or a loop.
| Field | Traffic received | Common use |
|---|---|---|
mixed-port |
HTTP and SOCKS5 | Desktop system proxy, LAN sharing |
port |
HTTP | Software that supports HTTP proxies only |
socks-port |
SOCKS5 | Developer tools, terminal programs |
redir-port |
Redirected TCP | Transparent proxy on a Linux gateway |
tproxy-port |
Transparent TCP and UDP proxying | Gateways that must preserve the original destination address |
mode determines whether rules are applied
mode: rule checks rules from top to bottom and is the main mode for everyday traffic routing. global sends every connection through the global policy, which is useful for temporarily checking whether a proxy works, but bypasses the existing rule logic. direct connects to targets directly, helping determine whether a failure comes from the proxy chain. When troubleshooting an unmatched rule, first confirm that the current mode is still rule; a graphical client's mode switch may override the initial value in the configuration file.
log-level controls the amount of detail in logs. Use info for normal operation and temporarily switch to debug when investigating rule or connection problems, then switch back to prevent logs from growing continuously. Read rule matches, DNS queries, dial failures, and timeouts separately: a policy group match only confirms that routing has been decided; it does not prove that the group's selected proxy connected successfully.
mixed-port: 7890
allow-lan: false
bind-address: "*"
mode: rule
log-level: info
ipv6: false
unified-delay: true
tcp-concurrent: true
find-process-mode: strict
LAN access and listener boundaries
allow-lan determines whether other devices can access Clash listening ports. After setting it to true, allow the corresponding port through the operating system firewall and use the LAN address of the device running Clash as the proxy server. bind-address limits the listening address. Keep the loopback boundary when the proxy is for local use; expand it only when sharing with the LAN. Never expose a shared proxy directly on a public interface, especially on a cloud server or a network adapter with a public address.
external-controller provides the control API used by graphical clients and web panels to read connection, log, and policy state. It serves a different purpose from the proxy port and must not be used as a browser proxy address. If the control API is accessible beyond the local machine, set credentials and restrict its firewall sources. Control credentials are sensitive local data and should never be committed to a public repository or posted in a public issue.
ipv6 controls whether the core handles and returns IPv6 addresses, but it is not a simple network-acceleration switch. If the IPv6 path is incomplete anywhere between the upstream network, proxy, and target site, connections may stall before falling back. When no usable IPv6 network is available, disabling it generally keeps behavior more consistent. Enable it only in a complete dual-stack environment, then check DNS responses and the actual connection path separately.
03 / DNS PIPELINE
DNS configuration: resolution paths, Fake-IP, and traffic routing
The DNS section handles more than a single resolution task
Clash's DNS module resolves domains to addresses and also supports domain rules, Fake-IP mappings, and policy-based upstream selection. With built-in DNS disabled, applications usually use the system resolver directly, so the core may see only a destination IP and domain-based rules may stop matching reliably. After enabling DNS, make sure intercepted requests actually enter its listening address. Merely setting dns.enable: true while the system continues sending queries elsewhere does not create a complete resolution chain.
listen specifies where the DNS service listens and on which port. A desktop GUI's TUN implementation usually handles DNS hijacking automatically; when running directly on a router, forward LAN clients' queries to this port or redirect them with firewall rules. If the service listens on all interfaces, also check the firewall scope so a recursive resolver is not exposed to an uncontrolled network.
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
nameserver:
- https://1.1.1.1/dns-query
- https://8.8.8.8/dns-query
proxy-server-nameserver:
- https://223.5.5.5/dns-query
fake-ip-filter:
- "*.lan"
- "localhost.ptlogin2.qq.com"
- "+.local"
default-nameserver, nameserver, and proxy hostnames
nameserver contains the primary upstream resolvers and can use traditional UDP addresses or encrypted DNS endpoints. When an encrypted DNS endpoint is itself a hostname, the core must first resolve that hostname, so default-nameserver provides bootstrap resolution. Bootstrap servers should normally use directly reachable IP addresses to avoid a loop in which the upstream hostname must be resolved before the upstream can be reached, while resolution depends on that same upstream.
proxy-server-nameserver resolves the proxy servers' own hostnames. Prefer an upstream that is directly reachable and stable on the current network, because a proxy hostname must resolve before the proxy connection can be established. If hostname-based nodes time out while IP-based nodes work, check this layer first.
respect-rules makes DNS queries follow rules when choosing an egress. It suits configurations that route DNS traffic as well, but bootstrap resolution, proxy-host resolution, and primary resolution must not wait on one another. For a complex setup, disable rule awareness first and verify basic resolution, then enable it gradually. This is safer than adding every DNS option at once.
Fake-IP versus Redir-Host
In fake-ip mode, the resolver returns a mapped address from a reserved pool. When an application connects to it, the core uses the mapping table to recover the original domain and apply rules. This preserves domain information during connection handling and reduces routing errors that occur when an application receives a real address before connecting. The address pool is only a local or controlled-network mapping, not the target site's real address; a reserved-range result does not by itself indicate a DNS failure.
redir-host returns the real resolved address, which is more compatible with LAN services that require real IPs, some games, and specialized network checks, but it preserves the domain-to-connection link less effectively. For printer discovery, LAN hostnames, device casting, or login failures in a particular app, add the relevant domains to fake-ip-filter before switching the entire enhanced mode. Keep the filter precise; an overly broad list bypasses mapping for many domains and makes domain rules less consistent. For the mapping process and filter boundaries, read How Fake-IP mode works.
Targeted resolution with nameserver-policy
nameserver-policy routes selected domains to specified DNS upstreams. For example, internal domains can use the LAN resolver while a category of public domains uses another resolver. Policy keys can use domain rule sets or domain matching patterns, and values can be one upstream or a group of upstreams. This answers “where should this class of domain be resolved?” rather than “which proxy should carry the connection?” The connection egress is still determined by rules and policy groups.
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- https://1.1.1.1/dns-query
nameserver-policy:
"+.corp.example":
- 192.168.1.1
"rule-set:private-domain":
- 192.168.1.1
04 / PROXY OBJECTS
Proxy fields: connection targets, protocol parameters, and providers
The common structure of a proxy object
proxies is a list of proxy objects. Each object needs at least a name, type, server address, and port; authentication, transport, and encryption fields depend on the protocol. name is the unique identifier referenced by other sections, so duplicate names should be avoided. server may be an IP address or hostname. When it is a hostname, the DNS section must be able to resolve it before the proxy connection begins.
Protocol fields cannot be copied across types without checking. A field valid for one protocol may have no effect in another node; unknown fields may be ignored or may make validation fail. When cleaning up a subscription, keep the parameters required by the protocol and remove decorative fields left by a conversion chain that the core does not recognize. For a failed connection, verify type, server, port, and authentication first, then check TLS, transport, and server name—not the policy group or rules.
proxies:
- name: "Office SOCKS"
type: socks5
server: 192.168.1.10
port: 1080
username: "proxy-user"
password: "your-password"
udp: true
- name: "Example Shadowsocks"
type: ss
server: proxy.example.com
port: 443
cipher: aes-128-gcm
password: "your-password"
udp: true
TLS and server names
Protocols using TLS typically involve tls, a server name, and certificate verification. The server name selects the certificate and virtual host during the handshake. It may match the connection address or be specified separately by the server. When the connection address is an IP but the certificate was issued to a hostname, the server name becomes especially important. Do not hide certificate errors by permanently disabling verification; first check the system clock, node details, server name, and the intervening network. If a browser reports a certificate error with the proxy enabled, see Step-by-step HTTPS certificate troubleshooting.
Transports such as WebSocket and gRPC may also require a path, Host, or service name. These values are determined by the server deployment and cannot be guessed by the client. Slashes, capitalization, and empty values in a path can affect the handshake, and subscription conversion must not incorrectly flatten nested fields. If TCP reaches the server port but the connection closes quickly with a handshake failure in the logs, shift the investigation from network reachability to TLS and transport parameters.
proxy-providers manage dynamic proxy collections
When there are many proxies or the source must be refreshed regularly, use proxy-providers. A provider reads proxies from a file or remote URL and can run health checks; a policy group references the entire provider through use instead of listing every proxy manually in proxies. This reduces the chance that a group misses new proxies after a subscription update and makes it easier to keep sources in separate collections.
proxy-providers:
primary:
type: http
url: "https://example.com/subscription.yaml"
path: ./providers/primary.yaml
interval: 3600
health-check:
enable: true
interval: 600
url: https://www.gstatic.com/generate_204
proxy-groups:
- name: "Automatic Selection"
type: url-test
use:
- primary
url: https://www.gstatic.com/generate_204
interval: 300
path is the local cache location for provider content, and the runtime user must be able to write to its parent directory. In containers and system services, relative paths are based on the process working directory, which may not be the directory containing the configuration file. If a provider downloads successfully but cannot write its cache, check the actual working directory and mounted paths. Access parameters in remote URLs are sensitive; remove them before sharing logs or configuration snippets.
A health check only answers whether a request to the test address can complete through that proxy. It does not mean every target is reachable and is not a bandwidth test. The test address should be stable, return a small response, and resemble the protocol needs of everyday traffic. Checks that run too often keep opening connections and consume extra resources when many proxies are present; checks that run too rarely delay status updates. Balance the interval against proxy count and failover needs rather than simply choosing the shortest interval.
05 / POLICY LAYER
Policy group fields: selection, testing, failover, and nesting
Policy groups are the scheduling layer between rules and proxies
Rules usually point to a policy group rather than a fixed proxy. When proxies change, you can update the group's members or current selection without rewriting the entire rule set. A select group is chosen manually; url-test selects automatically from test results; fallback searches members in order for an available option; and load-balance distributes connections across available members. Each type solves a different problem, so interface latency alone is not enough to decide which is appropriate.
The proxies list may contain proxies, another policy group, or built-in policies such as DIRECT and REJECT. Nesting separates business categories from proxy selection—for example, streaming rules can point to “Media Services,” which then references “Node Selection.” Too much nesting increases cognitive load and can create circular references. Keep dependencies flowing in one direction; no group should contain itself directly or indirectly.
proxy-groups:
- name: "Node Selection"
type: select
proxies:
- "Automatic Selection"
- "Failover"
- "Example Node"
- DIRECT
- name: "Automatic Selection"
type: url-test
proxies:
- "Example Node"
- "Backup Node"
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 80
- name: "Failover"
type: fallback
proxies:
- "Example Node"
- "Backup Node"
url: https://www.gstatic.com/generate_204
interval: 300
- name: "Media Services"
type: select
proxies:
- "Node Selection"
- DIRECT
How to interpret latency-test results
url-test measures the time for a request to a specified test URL to complete through a proxy, including connection setup and the response. It is not a universal latency score for every website. The test network, the proxy's route to that URL, and local DNS all affect the result. A proxy with a low test time may still download slowly because of bandwidth, congestion, destination routing, or connection reuse—not because the policy group calculated incorrectly. Test speed issues layer by layer with proxies, routes, and local settings.
tolerance prevents frequent switching between proxies with similar results. When a new result is only slightly better, keeping the current proxy is usually more stable than repeatedly selecting another. interval controls periodic checks, while lazy can reduce testing for inactive groups. Tune these settings around the usage pattern: an occasional desktop connection and an always-on router have different resource budgets, and the number of proxies directly increases health-check traffic.
The boundary between fallback and load balancing
fallback prioritizes order and availability: it stays with the first available member and suits clearly defined primary and backup routes. Lowest latency is not its only goal, so a backup with lower latency may still not be selected. load-balance distributes multiple connections; it does not split one download across several proxies. A single TCP or UDP session usually keeps one fixed egress so that changing source addresses does not break the session.
Load balancing also requires considering whether a target needs a consistent egress. Services involving logins, payments, verification codes, or source-address checks may trigger reauthentication when adjacent requests land on different proxies. Use a strategy that preserves target mapping, or place those domains in a fixed proxy group. For most users, a clear manual selection group paired with one automatic test group is easier to maintain than several layers of load balancing.
Naming affects long-term maintenance
Policy group names appear both at the end of rules and in the client interface. Name them by purpose—for example, “Node Selection,” “Failover,” “Media Services,” or “Messaging”—rather than packing region, protocol, and business purpose into one long name. Rule providers and policy groups can have one-to-many or many-to-one relationships, but names should remain stable. Frequent renaming can break old overrides, scripts, and local rules at the same time.
Subscription-provided policy groups may be rebuilt during updates. Groups that must persist locally should be placed in the client-supported override layer with an explicit insertion point. If a rule points to a local group but the override runs after rule merging, the final configuration may temporarily contain an undefined reference. Do not check only whether a fragment exists; confirm that the final file defines the group within the same configuration scope loaded by the core.
06 / RULE ENGINE
Rule syntax: top-to-bottom matching, first match wins
Rule order is the effective priority
rules is an ordered list. A connection is checked from the first entry, and the first matching rule immediately determines its policy; later rules are ignored. Put exact domains and special-case traffic first, broader domain suffixes, IP ranges, and regional sets in the middle, and MATCH last to catch everything else. Moving a broad rule upward is one of the main reasons a rule appears to be configured but never takes effect.
Rules generally consist of a type, a match value, and a policy name separated by English commas. The policy name must refer to a defined group, proxy, or built-in policy. Some rules accept options such as no-resolve for IP rules, which prevents an extra lookup solely to obtain an address for matching. Commas in a rule are structural separators; when special content is involved, YAML quoting does not change how Clash parses the rule.
rules:
- DOMAIN,api.example.com,Node Selection
- DOMAIN-SUFFIX,example.com,Node Selection
- DOMAIN-KEYWORD,example,Node Selection
- PROCESS-NAME,example.exe,DIRECT
- DST-PORT,22,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- GEOIP,CN,DIRECT
- MATCH,Node Selection
How broadly domain rules match
DOMAIN matches one exact hostname, making it suitable for a single API or host. DOMAIN-SUFFIX matches a domain and its subdomains, which suits an entire site. DOMAIN-KEYWORD can match any hostname containing the specified fragment, giving it the broadest scope and the highest risk of false positives. Use a suffix rule when possible rather than a keyword rule just to save a few lines; a short keyword may match unrelated domains.
Domain matching depends on the core knowing the original hostname during connection handling. HTTP hostnames, TLS server names, Fake-IP mappings, and sniffing can provide that information; when an application connects directly to an IP, domain rules cannot match. Determine how the application behaves instead of adding multiple spellings of the same domain. Traffic sniffing can identify domains for some connections, but it has protocol and port limits and should not replace correct DNS interception.
IP, port, and process rules
IP-CIDR and IP-CIDR6 match destination address ranges and suit LANs, reserved addresses, and clearly defined service networks. Public service addresses may change or be shared by multiple services, so maintaining large lists of public IPs is often less stable than using domains or rule sets. GEOIP classifies addresses using a local database; stale data can place newly allocated addresses in unexpected categories, making database updates part of rule maintenance.
DST-PORT matches the destination port but cannot distinguish different websites sharing that port. Modern web traffic heavily uses port 443, so assigning the entire port to one policy is usually too broad. Process rules can match a program name or path, but support depends on the operating system, permissions, and capture method: a gateway cannot see processes on an endpoint, and some sandboxed apps cannot provide complete process information. Cross-platform configurations should not rely on process rules for all important routing.
Use rule-providers to split large rule sets
rule-providers stores rules in a local file or remote resource, while the main rule list references them with RULE-SET. A provider must declare its behavior type, format, cache path, and update interval. Use domain for domain collections, ipcidr for address ranges, and classical for several classic rule types. The behavior type must match the file contents; a successful download does not guarantee correct parsing.
rule-providers:
private-domain:
type: http
behavior: domain
format: yaml
path: ./rules/private-domain.yaml
url: "https://example.com/rules/private-domain.yaml"
interval: 86400
private-ip:
type: file
behavior: ipcidr
format: yaml
path: ./rules/private-ip.yaml
rules:
- RULE-SET,private-domain,DIRECT
- RULE-SET,private-ip,DIRECT,no-resolve
- MATCH,Node Selection
A rule-provider update failure does not necessarily stop the core immediately; an existing cache may continue to be used. “Configuration loaded successfully” and “rules are up to date” are separate facts. When a new domain does not match, check provider status, the cache modification time, the download response, and the behavior type. A remote resource may return an HTML error page instead of a rule file, making the request appear successful while parsing still fails.
The final policy expresses the configuration's default stance. Ending with MATCH,Node Selection sends uncategorized traffic to proxy selection; ending with MATCH,DIRECT means only explicitly listed targets use a proxy. Either approach can work if rule coverage matches expectations. Changing the final policy affects every unmatched connection, so test it separately rather than treating it as a temporary switch for fixing one website.
07 / MERGE LAYERS
Overrides and merging: preserve local settings after subscription updates
Identify the configuration layers first
The final configuration in a graphical client usually combines several sources: the remote subscription supplies proxies and baseline policies, local overrides change general fields or add rules, and the client itself determines runtime parameters such as the system proxy, TUN, and control port. The “subscription content” shown in the interface is often only one layer. To understand why a field changed, determine the merge order and whether conflicts between same-named fields use replacement, appending, or deep merging.
Clients differ in how they name and implement overrides. Some support YAML fragments, some scripts, and some distinguish pre-rules from post-rules. When migrating clients, do not assume an old override will run unchanged. Clash Plus is a strong default graphical entry point for ordinary users; to choose another client, compare Clash Verge Rev, FlClash, Clash Nyanpasu, Clash Meta for Android, Surfboard, and archived clients on the download page.
Replacing a mapping is not the same as appending to a list
For scalar fields such as mode, log-level, and dns.enable, an override usually replaces the old value. For lists such as rules, proxies, and proxy-groups, simple replacement deletes subscription content, while simple appending may put a new rule after MATCH, where it can never match. List edits therefore need an explicit insertion point: custom exact rules generally go before broad rules, and the catch-all rule must remain last.
Deep-merging mappings also has limits. If you only want to add one fake-ip-filter entry but the merger replaces the entire dns object, the existing nameserver and listener fields disappear. Conversely, if you expect to replace DNS completely but the tool merges key by key, leftover subscription policy fields remain. Before using an override, read how the client handles objects and arrays, then verify the final configuration rather than checking only that the override fragment is syntactically valid.
# Local override fragment example
mode: rule
log-level: info
dns:
enable: true
fake-ip-filter:
- "*.lan"
- "+.local"
rules:
- DOMAIN,internal.example,DIRECT
- DOMAIN-SUFFIX,example.com,Node Selection
Insertion position determines whether an override works
Suppose the subscription already ends with MATCH,Node Selection. If a local rule is simply appended to the end, it will never run. Insert it before the catch-all rule, or use an override tool that supports pre-rules. If the subscription contains broad DOMAIN-SUFFIX, GEOIP, or rule-set entries, local exact exceptions must also come before them. Rules have no explicit numeric priority; their position is their priority.
Policy-group overrides must also handle member references. Adding a group named “Developer Services” is not enough: rules must point to it, and its referenced “Node Selection” group must exist in the final configuration. If the subscription renames a policy group, a local override may merge successfully but fail at load time with an undefined policy. Reduce reliance on subscription-defined names, or inspect the final reference graph after every structural subscription change.
Use script overrides for conditional edits, but keep them simple
Scripts can iterate over proxies, rebuild policy groups, or insert rules by name, which is useful when subscription lists change on every update. They also add another failure layer: fields may be absent, proxy names may contain special characters, and client upgrades may change the input structure. Check object types and array existence before operating; do not assume every subscription has the same skeleton. On failure, preserve the original configuration and write a clear log instead of returning a partial result.
Complex scripts need version control and testing just like ordinary code. Make each change solve one class of problem, keep input samples, and handle empty proxy lists, missing groups, and duplicate rules. If the requirement is only to change a port or add two rules, a YAML override is usually more transparent than a script. Use scripts only when repeated operations genuinely cannot be expressed declaratively.
Merging strategy when running the core directly
When running mihomo directly, use templates or a configuration generator in the deployment process, but make sure the generated result remains an independently inspectable YAML file. Generate it to a temporary file before starting the service, validate it, and then atomically replace the active configuration to avoid leaving a partial file after an interrupted merge. Directory permissions, persistent partitions, and boot order also affect rule downloads and cache restoration on routers and bypass gateways. For the architecture, see Router and bypass-gateway deployment overview.
08 / VALIDATION
Validation and troubleshooting: from load failures to routing problems
Run static checks first, then inspect runtime logs
Handle configuration failures by layer. First verify that YAML parses, including indentation, colons, lists, and quotes. Next verify Clash semantics: proxy types, required fields, policy references, and rule formats. Only then investigate runtime network problems such as unreachable DNS, failed proxy handshakes, a disabled system proxy, or missing transparent-proxy routes. If the first layer has not passed, there is no reason to test proxy latency or change firewall rules.
When running the core directly, use its configuration-check option against the directory containing the configuration. Adjust the executable path and configuration directory in the actual command to match the deployment. Graphical clients usually also provide configuration checks, reload controls, or a log view; if the interface only says “load failed,” open detailed logs and locate the specific field. Save the file first and make sure the editor has not inserted tabs or invisible characters.
mihomo -t -d /path/to/config-directory
mihomo -d /path/to/config-directory
Passing the configuration check only means the kernel accepts its structure; it does not mean every remote node, DNS upstream, or rule provider is reachable. After startup, also monitor provider updates, DNS requests, connection attempts, and rule matches. Temporarily setting the log level to debug provides more context, but analyze one clearly defined request at a time instead of searching through a flood of background connections.
Common branches of a load failure
When an error points to one line, the actual cause may be on the previous line—for example, a missing quote can make later content parse incorrectly, or an earlier indentation level may have shifted. Check upward from the reported line to the nearest top-level field. For an error such as “policy not found,” search the name at the end of the rule and then the policy-group definition, comparing spaces and punctuation exactly. For duplicate names, inspect not only manually written proxies but also whether provider expansion created a name collision with a static proxy.
A configuration that works in one client but fails in another usually differs in supported fields, core capabilities, or override format. Export a minimal configuration containing one basic proxy, one selection group, and two rules, then confirm that the target client can load it before restoring sections one by one. Do not randomly delete fields and hope; change one section per iteration and record whether the difference appears during validation, startup, or the actual connection.
| Symptom | Check first | Next step |
|---|---|---|
| Configuration will not load | Indentation, lists, required fields, name references | Run a static check and inspect the surrounding error context |
| Every proxy hostname times out | Proxy hostname resolution, bootstrap DNS | Compare with an IP-based proxy and inspect DNS logs |
| The browser connects directly, but the terminal works | System proxy, browser-specific proxy settings | Use one proxy entry point and test again |
| A specific rule does not match | Runtime mode, rule order, domain visibility | Add an exact pre-rule and inspect the logs |
| The LAN breaks after enabling TUN | Routes, DNS hijacking, private-network rules | Confirm private ranges use DIRECT and check interface scope |
| Local rules disappear after a subscription update | Edit location, override persistence method | Move them to the client's official override layer |
The connection succeeds, but the page does not open
When a proxy test succeeds but a webpage does not open, validate DNS, rules, and application capture separately. First use a command that explicitly specifies mixed-port to visit a simple address and confirm the proxy port works. Then check that the browser or system proxy points to the same address, and observe which rule matches the target hostname. If the application produces no connection log at all, the problem is in the capture layer. If a connection appears but matches the wrong rule, check rules or hostname detection. If the policy is correct but dialing fails, return to the proxy and transport layers.
When some websites work but others wait indefinitely, check IPv6, UDP, HTTP/3, and MTU. An application may try IPv6 or QUIC first and fall back only after failure. An oversized MTU in a TUN setup can also let small requests work while larger responses stall. Temporarily disable one capability at a time for comparison, then fix the underlying network conditions or protocol support instead of keeping contradictory temporary switches enabled.
Additional checks for TUN and transparent proxying
TUN capture depends on a virtual interface, routes, and permissions. On desktop systems, the client may need authorization to create the interface; on Linux, kernel capabilities, forwarding settings, and policy routing also matter. If TUN appears enabled but application traffic never reaches the logs, inspect the default route and excluded ranges instead of repeatedly restarting the core. LAN ranges, virtual-machine networks, container networks, and corporate intranets often need explicit direct access, or local services may be sent through the proxy by mistake.
A gateway transparent proxy must also prevent the core's own traffic from being redirected again. Proxy connections, DNS upstream requests, and rule downloads can re-enter the same transparent chain and create a loop. Common solutions exclude traffic by runtime user, process mark, or routing mark, but the exact method depends on the nftables, iptables, and system-routing design. The configuration file can define listening ports and TUN parameters, but it cannot replace complete loop prevention at the operating-system layer.
tun:
enable: true
stack: mixed
dns-hijack:
- any:53
auto-route: true
auto-detect-interface: true
strict-route: true
Keep troubleshooting records reproducible
A useful troubleshooting record should include at least the current client or core runtime method, configuration sources, the step where the failure occurs, logs for one request, verified working components, and recent changes. Before sharing a configuration fragment, remove subscription URLs, authentication data, control credentials, and proxy passwords, while retaining field structure, policy names, and rule order. “It does not work” or an entire block of unrelated logs rarely reveals which layer failed.
After fixing the issue, remove temporary debug logging, test rules, and bypasses, then reload and test again. For routers or servers running continuously, restart the service to verify the boot path, working directory, and cache permissions; a configuration that works in the current terminal session may still fail as a system service. For LAN sharing, see the mixed-port and allow-lan setup guide to confirm that the listener address, firewall, and device proxy settings form one consistent path.