Mihomo · YAML Fields and Runtime Configuration
Clash Configuration File Guide
From the structure of config.yaml to DNS, proxy groups, rules, and subscription overrides.
This guide explains configuration fields and how they relate, in a practical reference order. It’s intended for users who have already installed a client and need to maintain a custom configuration. If you’re new to Clash, start with the Getting Started guide to import a subscription, choose a mode, and verify your connection, then return to the relevant section to adjust fields. Examples are based on Mihomo semantics; clients may override some settings, so check the runtime configuration to see what actually takes effect.
YAML Structure and Configuration Boundaries
A Clash configuration isn’t a sequence of commands. It’s a structured document describing listeners, DNS resolution, outbound connections, and routing. Top-level fields such as dns, proxies, proxy-groups, and rules each serve a different purpose. The core can connect them only when names and data types are valid. When reading an unfamiliar config, start with the top-level fields, follow rule targets to their proxy groups, then check which nodes those groups reference. Reading every line in order can make these dependencies easy to miss.
Mappings, Lists, and Indentation
YAML uses indentation to show parent-child relationships. Use two spaces consistently and avoid tabs. A space after a colon usually separates a key from its value; a space after a hyphen usually marks a list item. The same key, such as name, means different things under a proxy node and a proxy group. An editor’s auto-formatting can help with alignment, but it can’t verify that references make sense. When copying a snippet, check its parent level too, so a field meant to go under dns doesn’t end up at the root.
# Structure example: each list item is a separate proxy group
proxy-groups:
- name: Manual Select
type: select
proxies:
- DIRECT
rules:
- MATCH,Manual Select
Keep strings, numbers, and Boolean values distinct. Ports are usually numbers; switches should be true or false. Quoting a value that should be a number or Boolean may cause some parsers to reject it and others to convert it, so don’t rely on inconsistent behavior. Quotes are safer for special characters, leading zeros, or text that could be misread. Quote passwords; escape any single or double quotes in them according to YAML rules. Plain comments start with #, but whether a hash is part of a string depends on the quoting and its position.
Distinguish Subscription Sources, Edited Files, and Runtime Config
Desktop clients often keep several versions of a configuration: the original text from a remote subscription, local edits or overrides, and the final configuration passed to the core. Settings in the interface, such as ports, system proxy, and TUN, may also be injected into the final result. Editing subscription text doesn’t necessarily change the active runtime config; changes may take effect only after reloading, switching subscriptions, or applying overrides. When troubleshooting, note the selected configuration and when it was loaded. Otherwise, you may edit an old file while checking connections from a different one.
Top-level field order usually doesn’t change the meaning of a mapping, but list order can directly affect behavior. Rules are checked in order, and the first item in a manual selection group may also determine what’s selected initially. Don’t apply an alphabetical sort to every list. Duplicate keys are especially risky: if dns or rules appears twice at the same level, some tools report an error while others keep only the later entry. To merge content, add it under the existing key instead of pasting an entire block at the end of the file.
Minimal Structure and Configuration Compatibility
When creating a new config, start with the smallest structure that loads, then add nodes, groups, and rules one at a time. A subscription accepted by one client isn’t necessarily compatible with another. Older cores may not recognize newer protocols or DNS fields, and clients may filter out some options. If you encounter an unknown field, check the current core documentation and logs before removing it; it may be essential for DNS resolution or outbound selection.
YAML anchors and aliases reduce repetition, but make overrides, subscription converters, and manual reviews more complex. For a small, individually maintained config, a little repetition is often worth keeping each section easy to understand on its own. When sharing a configuration for troubleshooting, preserve its structure, field types, and references, and replace only server addresses, passwords, and subscription URLs. Removing entire nodes or group names can destroy the context needed to distinguish syntax errors, unsupported fields, and connection failures.
Ports, Proxy Mode, and Traffic Capture
General settings determine where the core accepts connections, how it routes traffic, and which devices can connect. A common mistake is confusing the listening port with a server port: mixed-port is the local entry point apps use to connect to the proxy, while a node’s port is where the remote server provides its service. They can be different and don’t need to match. After changing a local listening port, check that the system proxy and in-app proxy addresses are updated too. Otherwise, the core may be running normally while apps still connect to the old port.
What Each Listener Setting Does
| Field | Example | Purpose |
|---|---|---|
port | 7890 | HTTP proxy listener |
socks-port | 7891 | SOCKS proxy listener |
mixed-port | 7897 | Accepts both HTTP and SOCKS proxy connections on one port |
allow-lan | false | Controls LAN access; also check the bind address and firewall |
bind-address | 127.0.0.1 | Restricts the proxy listening address |
If only local apps need the proxy, one mixed port is usually enough. There’s no need to enable HTTP, SOCKS, and mixed ports all at once, and two listeners shouldn’t use the same address and port. If you see an address-in-use error, check whether another proxy instance or background service is still running. Enabling LAN access takes more than switching a Boolean value on: check the bind address, system firewall, and access controls. Don’t expose a proxy port to an untrusted network.
mixed-port: 7897
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
ipv6: false
Rule, Global, and Direct Modes
With mode: rule, traffic is evaluated against the rules list and routed according to the match. Global mode typically delegates routing to the global selection group, while Direct mode bypasses proxy-node selection by custom rules. The mode controls routing; it doesn’t determine which traffic is captured. Even in Global mode, traffic that hasn’t been routed through the system proxy, an app’s settings, or TUN won’t reach the core. Conversely, when a rule in Rule mode matches DIRECT, the core still receives the connection; it simply sends it out directly.
The system proxy setting changes the proxy configuration provided by the operating system; whether an app follows it is up to that app. TUN captures traffic through a virtual network interface and routes, covering more traffic but involving permissions, route conflicts, and DNS interception. Don’t treat TUN as a “stronger global mode” or assume it will fix every network issue. Games, virtual machines, containers, and corporate VPNs can all use different traffic paths. Before enabling TUN, record the current settings and make sure you can restore the original routes and DNS configuration.
How TUN and Client Settings Work Together
# TUN snippet: check client permissions and routing before enabling
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
This example shows an intent to enable automatic routing and capture traditional DNS requests. It doesn’t guarantee coverage for an app’s built-in encrypted DNS or every platform’s network stack. Virtual interfaces, service permissions, and firewalls vary by operating system, and clients may manage these fields centrally. If interface toggles and file settings override one another, decide which should be the source of truth. For setup steps, see the Getting Started guide. This page explains how the fields relate; don’t replace an entire network configuration without understanding how your client implements them.
For everyday use, info is usually an appropriate log level; increase detail temporarily when reproducing an issue. Debug logs may include target domains, connection details, and config paths, so redact them before sharing. The root-level ipv6 field and the DNS section’s field with the same name affect different parts of the connection. Changing only one doesn’t fully configure the IPv6 path. For remote control interfaces, understand the difference between the control plane and the proxy plane: the management interface changes state and shouldn’t be used as an app’s proxy endpoint.
Autostart, silent launch, themes, and tray behavior are generally GUI client preferences, not YAML fields supported by every core. When migrating a configuration, document network behavior separately from interface behavior. To choose a client, see the downloads page. Most users can start with the recommended Clash Plus, then consider clients such as Clash Verge Rev based on their OS and configuration compatibility needs. Similar-looking interfaces don’t mean their config files are interchangeable.
DNS Settings and Domain Resolution
DNS translates domain names into addresses, but proxy setups can involve several stages of resolution. An app may resolve a name itself, the core may look up a destination address for rule matching, and the proxy server’s hostname may need to be resolved when connecting. Distinguish these cases to understand why a domain works in a browser but fails in the command line, or why a node using a hostname can’t connect. Configuring encrypted DNS doesn’t mean every app will use it, or that traffic has been routed through a proxy.
Listeners, Upstream Servers, and Bootstrap DNS
dns.enable enables the core’s DNS features, listen sets the DNS listening address, and nameserver specifies the regular upstream resolvers. If you use a DoH URL with a hostname, the core first needs to resolve the address of that upstream server—the bootstrap DNS problem. default-nameserver can handle this initial lookup; use explicit IP addresses where possible. If a proxy node uses a hostname, proxy-server-nameserver can specify how to resolve it, keeping proxy-server lookups separate from destination-domain routing.
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
default-nameserver:
- 1.1.1.1
nameserver:
- https://dns.google/dns-query
proxy-server-nameserver:
- https://dns.google/dns-query
fake-ip-filter:
- "*.lan"
- "*.local"
This example illustrates how the fields relate; it isn’t a DNS solution for every network. Upstream connectivity depends on your network, so test access before choosing a resolver. Having the core listen on port 1053 won’t automatically send system DNS requests there; a client or system network setting must route them to the listener. With TUN, verify that DNS interception and routing are actually working. Apps with their own secure DNS may bypass interception on traditional ports, so track that as a separate factor when troubleshooting.
Fake-IP and Real-Address Resolution
In fake-IP mode, the core returns a mapped address from a reserved range, then uses the mapping to recover the domain and route the connection. This helps preserve domain information, but depends on traffic continuing through the same core. If an app receives a mapped address and bypasses the proxy path, it may be unable to connect. Some LAN services, discovery protocols, and apps that make assumptions about addresses don’t work well with these responses; exclude them with filters as needed. Don’t exclude every domain to fix one app, or you’ll lose the main benefit of this mode.
redir-host usually returns the resolved address rather than a fake IP, but that doesn’t make it more reliable in every environment. Multiple domains may share a real address, and some connections may reach the core without domain information, changing rule matches. After switching modes, clear relevant app caches or reconnect; old addresses can affect what you observe. A reserved address isn’t proof of a network problem, and shouldn’t be treated as the actual server address for geolocation.
Choose a Resolver by Domain
nameserver-policy assigns resolvers to specific domains. It’s useful for internal business domains, home devices, and services with explicit DNS requirements. It controls which resolver receives a query, not which outbound route a connection takes; use routing rules to change the traffic path. Internal resolvers may be accessible only on a particular LAN or VPN, and will time out if forced when you’re off that network. Document where this configuration applies, and don’t send internal domains to unrelated public DNS services.
# Merge into the existing dns mapping; don't declare top-level dns again
dns:
nameserver-policy:
"+.home.arpa":
- 192.168.1.1
fallback and its filters are another resolver-selection mechanism; they aren’t simply a backup list used only when the primary server fails. Whether a response is accepted may also depend on address ranges and related filter settings. Unless you have a specific need, there’s no reason to add multiple resolvers just to make the config look complete. More complexity makes it harder to tell whether a result came from a cache, policy, or fallback path. Start with one working upstream, verify the DNS interception path, then add policies one at a time.
Before checking for DNS leaks, define what should happen: which requests should use the system resolver, which should go to the core, and which should be handled by the proxy server. Then verify with actual connections and DNS records. A leak-test site shows the result of one test; it can’t replace checking app behavior. If DNS works but HTTPS fails, don’t immediately change certificate verification. Use the proxy certificate error troubleshooting guide to check system time, the trust chain, and network conditions, treating DNS and certificate issues separately.
Proxy Node Fields and Connection Parameters
proxies is a list of static outbound definitions, each describing a specific connection method. Group and rule references use node names; the server address, port, protocol, and authentication fields determine whether a connection can be established. A region in a node’s name is just a label chosen by whoever maintains it, not proof of server location or connection quality. When troubleshooting, verify the actual protocol and server parameters before changing the display name. Renaming only affects references; it won’t fix the remote service.
Common Fields and Protocol-Specific Fields
Most nodes have name, type, server, and port, but authentication and transport fields aren’t interchangeable between protocols. Shadowsocks uses a cipher and password; other protocols may use a username, an identifier, or different TLS settings. Support for similarly named fields can also vary between implementations. Follow the parameters provided by your server and the current core’s supported features. Don’t map each part of a share link into YAML by guesswork—encoding, escaping, and optional parameters all have specific rules.
# Structure example: the address and password are fictional
proxies:
- name: Example Node
type: ss
server: proxy.example.com
port: 443
cipher: aes-128-gcm
password: "your-password"
udp: true
This example shows the basic structure of a static node, but it won’t work for a real connection. udp: true allows the outbound to use the relevant capability; it doesn’t guarantee UDP support across the entire path. The server, protocol, routing, and how the app connects can all impose limits. A working TCP connection to a web page doesn’t prove that voice calls, games, or other UDP traffic will work. Test using the same transport path as the app, and check whether the connection reaches the core, selects the intended outbound, and is accepted by the server.
TLS, Server Names, and Transport
Protocols that use TLS often have a server-name field such as servername. It’s used for the handshake and certificate name check, not as the local display name, and it may differ from the IP used for the underlying connection. If the server requires a specific name, enter it exactly; don’t substitute another domain to work around an error. For certificate errors, first check system time, the certificate chain, and whether the parameters match. Disabling certificate verification changes the security boundary and shouldn’t be a routine troubleshooting step—or part of a shared configuration for all devices.
Transport type, path, and headers are negotiated at another layer. With a WebSocket transport, for example, a reverse proxy may define the path and Host. Establishing a TCP connection to the port doesn’t mean the transport handshake will succeed. If logs show a reset or handshake failure, compare each setting with the server’s instructions. Changing one variable at a time and keeping the failure logs is more useful than changing the domain, port, and transport all at once, and helps avoid mistaking a temporary network issue for a configuration fix.
Proxy Providers and Subscription Formats
For large node lists, proxy-providers can keep node data separate from the main configuration. A provider usually returns YAML containing a proxies list, not an arbitrary collection of share links, and it isn’t necessarily a complete Clash configuration. Provider type, path, and update interval describe how to retrieve the data; groups reference it with use. If import fails, check that the response has the expected format. A login page, error message, or HTML page isn’t a valid node payload, even if the download succeeded.
# Local provider; set paths for the core's working directory and client restrictions
proxy-providers:
Local nodes:
type: file
path: ./providers/local.yaml
proxy-groups:
- name: Provider Selection
type: select
use:
- Local Nodes
The local provider example requires a payload file to be in place first. Paths are usually relative to the core’s working directory and may also be subject to client path restrictions. Don’t assume they’re relative to the folder open in your editor. Remote providers also involve update failures, caching, and access credentials; treat subscription URLs as sensitive because they often grant access. Before sharing screenshots, logs, or error messages, hide passwords and remove the full subscription URL and query parameters so others can’t access the same service data.
Keep node names unique throughout the configuration, and avoid conflicts with group names or built-in outbound names. After bulk renaming, update all static references; with providers, check that filters still match. Some services may rename or remove nodes when updating, so avoid tying long-lived rules to specific nodes whose names change often. A more resilient approach is to have rules target stable proxy group names, with the groups adapting to node changes. This keeps routing logic separate from the server list.
Proxy Group Types and References
Proxy groups separate the question “which outbound should this type of traffic use?” from “which nodes are available now?” Rules can reference a stable group name while its nodes change with subscription updates. To understand a group, check its type, candidates, and where it’s referenced. An automatic group works only when traffic is actually routed to it; seeing test results in the UI doesn’t mean every connection uses that group. If a top-level manual group still selects Direct, a nested automatic group won’t change the route for that traffic, even if it’s working normally.
Manual Selection, Automatic Testing, and Failover
| Type | Selection basis | Use case |
|---|---|---|
select | User selects from the candidates | Fixed outbound with manual switching |
url-test | Results from tests to a specified URL | Allows the outbound to change based on test results |
fallback | Candidate order and availability | Prefer a fixed primary outbound and fail over when it fails |
load-balance | Specified allocation strategy | Applications that explicitly support distributing traffic across multiple outbounds |
select is the most predictable option and suits login or work apps where the outbound shouldn’t change unexpectedly. url-test compares candidates using a test URL, but measures how one kind of request performs—not the real app’s throughput. fallback prioritizes candidate order and suits primary-and-backup setups. Load balancing doesn’t combine multiple nodes to speed up a single download, and different strategies can affect session stability. Choose based on what the app can tolerate, not on how automated the group is.
Nested Groups and Traceable Routes
# Use after merging with existing node definitions; the example node must exist
proxy-groups:
- name: Service Outbound
type: select
proxies:
- Example Node
- Auto Select
- DIRECT
- name: Auto Select
type: url-test
proxies:
- Example Node
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 50
rules:
- MATCH,Service Outbound
In this example, the rule targets “Service Outbound,” and the user then chooses a static node, an automatic group, or Direct. Nesting makes groups reusable, but the deeper the structure, the harder it is to trace the final outbound. Use group names that describe their purpose, and avoid vague names such as “Default” or “Other” appearing in multiple places. Don’t create circular references—for example, a group that includes another group that points back to it. A cycle isn’t a failover path; it’s an invalid dependency that may prevent the core or client from loading the configuration.
Set the url, interval, and tolerance parameters for automatic tests based on how the service behaves. If the test URL is unreachable, several healthy nodes may all appear to fail; don’t remove nodes based on a single test. Testing too often increases connection activity and background battery use on mobile devices; testing too infrequently delays status updates. Choose a test URL with a simple, predictable response, but remember its network path may differ from that of real services. It can’t predict how every site will perform.
Providers, Filters, and Persistent Selection
When a group uses use to reference a proxy provider, its candidate list changes with the provider’s contents. If you also filter by name, make sure the expression matches real names and account for the possibility of an empty result after an update. Don’t make every routing group depend on the same fragile naming convention; a server-side label change could leave the entire config without candidates. Check filter results in a test configuration before applying them to live groups. Keeping a clear manual selection available makes recovery easier.
A client may remember a manual selection, or revert to its default after a configuration switch, name change, or cache rebuild. Don’t rely on the first item in a group as an undocumented security measure. If an app requires a fixed outbound, verify the selection after every update rather than just checking that the config loaded. Existing connections may not migrate immediately when you change a group selection; connection reuse, long-lived sessions, and client behavior all affect what you observe. To verify the new route, create a fresh request and check its actual path.
When maintaining configs for mobile devices, avoid unnecessary duplicate health checks and give provider checks and group tests distinct purposes. Testing the same nodes in every service group can noticeably increase background requests. For battery and background settings, see Mobile proxy battery use and background settings. The goal of proxy groups is to make outbound selection clearer, not to use every available group type. If two levels explain the routing, there’s no need to build a deeper selection tree.
Rule Syntax, Order, and Rule Providers
The rules list is the routing decision chain for connections that reach the core. Rules are typically checked from top to bottom, and the first match determines the outbound. The core doesn’t score all matching rules or automatically move more specific rules to the top. When maintaining rules, check what comes before each one as well as the rule itself. A rule that “doesn’t work” often lost to a broader rule earlier in the list, or the client is still running a different configuration. Find the matched rule in the connection log before editing; it’s more reliable than guessing from a site’s location.
Domains, Addresses, and the Final Catch-All
# Service Outbound must be an existing proxy group
rules:
- DOMAIN,service.example.com,Service Outbound
- DOMAIN-SUFFIX,example.net,Service Outbound
- DOMAIN-SUFFIX,home.arpa,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
- MATCH,Service Outbound
DOMAIN matches an exact domain; DOMAIN-SUFFIX matches a domain and its subdomains. These rules don’t match full URLs, so don’t include a scheme, path, or query string. DOMAIN-KEYWORD matches a substring and can catch unrelated domains that contain the same text. If you know the service’s domain, prefer an exact or suffix match. A website may load resources from multiple domains, so routing its main page correctly doesn’t guarantee that images, login, and API requests use the same outbound.
IP-CIDR and IP-CIDR6 match address ranges. no-resolve prevents this kind of rule from triggering a lookup for the target domain; it doesn’t force a direct connection or block DNS. If the connection already has a destination address, address rules may still match. Placing a broad address range before domain rules may stop a connection early, before it can be routed by service name. Order rules by priority, not by type.
Rules Depend on Visible Connection Data
Whether a domain rule matches depends on whether the core knows the destination domain. Results may differ from a browser’s proxy request if an app connects directly to an IP, uses its own DNS result, or follows a capture path that loses domain information. Sniffing can recover some details in supported cases, but it can’t recover the original domain from every protocol or bypass encryption. When troubleshooting, first check whether the connection log shows a domain or an IP. Then decide whether to use a domain rule, an address rule, or change DNS and traffic capture settings.
MATCH is the final catch-all and usually belongs at the end of the list. Ordinary rules after it won’t get a chance to match. The built-in outbound DIRECT means connect directly; REJECT blocks the connection. Custom targets must match a node or group name exactly. Incorrect capitalization, invisible spaces, or references left behind after a rename can prevent the configuration from loading. Scope reject rules carefully and test them against specific targets before applying broad keyword matches across an entire subscription.
Rule Providers and Payload Formats
rule-providers:
Internal domains:
type: file
behavior: domain
path: ./rules/internal.yaml
rules:
- RULE-SET,Internal Domains,DIRECT
- MATCH,Service Outbound
# Contents of ./rules/internal.yaml
payload:
- "+.home.arpa"
- "+.lan"
Rule sets keep large lists out of the main file, making them easier to update and reuse. A behavior: domain payload contains domain rules; IP-based and classical rule payloads use different formats. Changing the behavior field alone doesn’t make an existing file compatible. Classical payloads typically contain match conditions, while a RULE-SET rule in the main config specifies the outbound. Check the format you selected instead of treating every payload as a full configuration rule.
Remote rule updates introduce maintenance considerations: upstream changes may add or remove coverage, caches can keep old results active, and a failed download may leave the previous file in place. Record each rule set’s source and purpose. Avoid using overlapping sets with conflicting targets unless their priority is intentional. As with node subscriptions, a successful download proves only that the file was retrieved—not that routing behaves as expected. After an update, check at least one request that should match and one that shouldn’t.
Process rules depend on the operating system and its ability to identify processes, so they shouldn’t be the only basis for cross-platform routing. App names may also differ due to launchers, child processes, or containers. If a Windows Store app has no connection records at all, first check whether its requests can reach the proxy entry point. See the UWP loopback exemption settings guide; adding more routing rules won’t help if no traffic reaches the core. Rules can route captured connections, but can’t fix isolation at the entry point.
Subscription Overrides, Merging, and Update Order
Subscription updates are a common source of conflicts with local customizations. A remote subscription provides nodes, groups, or rules; locally, you may want to pin a port, add direct routing for internal domains, or change the outbound for specific services. Editing the downloaded subscription directly is risky because the next update may replace your changes. Keep the remote source intact, put local changes in an override mechanism supported by your client, and check where those changes appear in the final runtime configuration. Don’t rely solely on the editor showing that the file was saved.
First, Decide Which Layer Takes Precedence
Clients don’t all process configurations the same way. Their pipeline may include subscription downloads, parsing and conversion, per-config overrides, global overrides, GUI settings injection, and core loading. There’s no single processing order that applies to every client. Check the preview or runtime configuration in your client, and use an observable field to verify the result. For example, change only the log level and check its final value after applying the override. Once you confirm that the override is part of the current subscription flow, move on to more complex DNS and routing changes.
An override isn’t a standard YAML feature; it’s a transformation implemented by a client or tool. Scalar values may be replaced, mappings may be merged recursively, and lists may be replaced, appended to, or prepended to—the exact behavior depends on the implementation. “Deep merge” doesn’t resolve rule priority automatically, because rule lists are ordered. Don’t assume that two rules snippets will be joined automatically, or copy a client-specific prepend key into another client as if it were a core field.
Check Mappings and Lists Separately
# Desired final structure; this is not override syntax for every client
dns:
enable: true
nameserver:
- https://dns.google/dns-query
nameserver-policy:
"+.home.arpa":
- 192.168.1.1
rules:
- DOMAIN-SUFFIX,home.arpa,DIRECT
- MATCH,Service Outbound
This example shows the intended final structure. If an override tool replaces dns wholesale, it may remove existing listeners, bootstrap resolvers, and filters. If it appends to nameserver, upstreams you meant to remove may remain. Rule insertion position matters too: put custom internal-domain rules before any catch-all that would match first, not after an existing MATCH. When reviewing the final configuration, check both field values and list order. Finding a string with search isn’t enough.
Stable References and Conflict Handling
If a custom rule points to a group name generated by a subscription, an upstream rename can break the reference. One option is to create a stable local group for business rules and have it reference nodes or providers that can change—provided your override mechanism can create and preserve that group reliably. Don’t create a group with the same name as a subscription group just to “override” it; some merge methods create a duplicate instead of replacing the original. To replace an object, explicitly remove the old one or use the tool’s object transformation features, then verify that the final list contains only one.
A subscription may provide different defaults for different platforms, so account for local differences when syncing overrides across devices. DNS listener addresses, LAN subnets, TUN permissions, and local file paths are usually specific to a device and shouldn’t be shared unchanged. Separate customizations into common routing rules and device-specific settings, with comments explaining their purpose and dependencies. This lets you carry the routing intent to another computer or client and adapt its entry points and permissions, rather than treating an old runtime config as a new subscription source.
Treat script-based overrides as code that can modify the entire configuration, not as another kind of comment. A script error can interrupt generation; incorrect object access can remove fields or change their types. Keep the transformation small, and define what happens when input is empty, a list is missing, or a name doesn’t match. Don’t rebuild the entire node list just to add one rule. Every unnecessary rewrite increases the risk of problems after a subscription update. Back up scripts separately from YAML to help identify which layer caused an issue.
Regression Checks and Migration After Updates
After setting up overrides, test an update at least once: make a backup, refresh the subscription, then inspect the runtime config and connection route to confirm that custom rules, group selections, and DNS fields remain. Success after manual application doesn’t prove that automatic updates work too. If something breaks after an update, temporarily disable local overrides to check whether the original subscription still works, then restore changes one layer at a time. For options when migrating from a discontinued client, see the Clash Verge Rev migration options guide. Preserve the intent of your configuration, not stale state cached by the old interface.
Configuration Validation and Troubleshooting
Validate a configuration in stages: first check that the text parses, then that the core accepts its fields and references, then confirm the listening endpoint, and finally test DNS, routing, and app behavior. Passing a config test means only that the current core can understand the file; it doesn’t prove that a server is reachable, a password is correct, or the destination service allows access. A working web page proves only that one request succeeded—it doesn’t replace checks for LAN access, UDP, background apps, or subscription updates. Record each test’s input, expected outcome, and observed result rather than simply marking it “working.”
From Offline Checks to Runtime Tests
# Run this from the config directory if Mihomo is installed and available on PATH
mihomo -t -f ./config.yaml
# In Windows PowerShell, if the executable is in the current directory
.\mihomo.exe -t -f .\config.yaml
These commands apply only where the core executable is actually installed. A GUI client may use its own working directory, managed paths, and generated files; don’t use an external core to overwrite a running instance. When testing a local provider, confirm that its relative path is based on the expected working directory. Otherwise, the main file may be valid but still fail because the payload file is missing. Error messages often identify a field, name, or line number. Start with the first meaningful error; later messages may be cascading effects of the same structural issue.
After the test passes, check that the client has actually selected and loaded this configuration. Look at the logs for the load result, listening address, and permission errors. A port conflict, TUN device creation failure, and subscription fetch error happen at different stages; don’t lump them all together as an unavailable node. If a config fails to load, some clients may keep the previous runtime state. So “the network still works” doesn’t mean the new config took effect. Check a field you just changed to avoid mistaking the old state for the new result.
Verify a Request End to End
# Specify the HTTP proxy explicitly to rule out whether the app follows system proxy settings
curl -I --proxy http://127.0.0.1:7897 https://example.com/
# SOCKS endpoint; h sends the target domain to the proxy for resolution
curl -I --proxy socks5h://127.0.0.1:7897 https://example.com/
These commands test a specific proxy endpoint, and the example service isn’t guaranteed to return a particular status code. An HTTP error response and a failed proxy connection are different outcomes: the former means the request reached an HTTP service, while the latter calls for checking the listener, protocol, and route. If another command alias shadows curl in Windows, check whether you should run curl.exe instead. A successful command doesn’t prove that a browser will work too; it may use extensions, built-in DNS, or an existing connection pool.
| Observed result | Check first | Don’t change yet |
|---|---|---|
| Configuration won’t load | Indentation, data types, duplicate names, and references | Remote server location |
| Connection refused locally | Listening port, address, and instance status | Service domain rules |
| No request in the connection log | App entry point, system proxy, and TUN routes | Proxy group test interval |
| Wrong outbound matched | Mode, rule order, and group selection | Node authentication parameters |
| Outbound handshake failed | Protocol, authentication, TLS, and server status | The entire rule set structure |
Build a Change Process You Can Roll Back
Change one layer at a time, and keep the previous file with a short note about what changed. Back up more than the main config: include local providers, rule payloads, and override scripts, or restoring the main file may leave references pointing to changed data. File names can indicate their purpose and save date, but don’t include sensitive subscription URLs. For system proxy, DNS, or TUN changes, also note how to restore the previous state. If you’re changing the default route on a device you access remotely, prepare a recovery path that doesn’t depend on the proxy.
To reproduce an issue, close unrelated proxy instances and use a fixed test target to compare direct and explicit-proxy connections. If it happens in only one app, record how that app is captured, resolves domains, and routes its processes instead of immediately replacing the entire subscription. If all nodes fail at the same time, check the local network, DNS upstream, and test target. If only some nodes fail, investigate the server and protocol settings. This order reduces unnecessary changes and keeps the logs tied to the actual issue.
For long-term maintenance, remove custom settings that are no longer needed: obsolete rule sets, old subnets, references to renamed groups, and exceptions added temporarily for a one-off issue. After each subscription or client update, check these boundaries first; there’s no need to retest every website. When asking for help, share a redacted minimal config, the error text, how traffic is captured, and the expected route. For common entry-point issues, see Troubleshooting. If you’re setting up your first connection, return to Getting Started and follow the steps in order.