Clash Configuration Reference
From YAML structure to rule merging, find out what each field does, where its limits are, and how to verify it.
Importing a subscription for the first time? Follow the Getting Started guide to connect. This page is a reference for what comes next: which fields belong to the core, which settings the client controls, why changes may not take effect, and how to narrow an issue down to a specific part of your config. Examples focus on commonly used mihomo fields; don’t assume every legacy core supports the same features.
YAML Structure
A Clash config is more than a set of unrelated switches: its fields reference and depend on one another. General settings control how the core listens for connections; DNS resolves domain names; proxies provide exits; proxy groups organize those exits; and rules route requests to a policy. Understanding this chain is more useful than memorizing every key. Follow it when troubleshooting: first confirm the request reaches the core, then check its rule target, and finally inspect the selected proxy.
Read the structure before the fields
YAML uses indentation to show nesting. Top-level keys such as dns, proxies, proxy-groups, and rules sit at the same level; nameserver belongs under DNS and must be indented. A hyphen starts a new list item—it isn’t decorative. Use two spaces consistently, never tabs. What looks aligned in an editor may not use identical characters, so check for full-width spaces at the start of lines, especially after copying text from a web page.
This structural example uses direct connections only. It can help you check config loading, listening ports, and policy references, but it won’t provide proxy service or replace connection details from a provider. Start by validating this small config, then add your own proxies and rules one section at a time. That makes issues easier to isolate than combining snippets from multiple sources all at once.
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
dns:
enable: false
proxies: []
proxy-groups:
- name: PROXY
type: select
proxies:
- DIRECT
rules:
- MATCH,PROXY
Strings, lists, and references
Proxy and group names are string references. If a rule specifies PROXY, the config must define a proxy group or exit with that exact name. Similar names don’t count: capitalization, spaces, and punctuation all matter. Choose short, stable names; avoid using changing traffic labels or dates as key references. If you rename a proxy, check the group lists and any rules that reference it directly. The YAML can be syntactically valid while references are still broken.
Booleans are usually written as true or false; ports and intervals are numbers. Quote text such as passwords. Strings containing a colon followed by a space, a hash, square brackets, or other special characters should also be quoted explicitly. Quotes clarify the data type; they don’t hide sensitive information. Don’t use a full-width colon as a key-value separator, or typographic quotes in place of the straight quotes YAML expects.
Don’t declare the same key twice at the same level. For example, adding another dns: block at the end of a file doesn’t append to the first one. Parsers may reject duplicate keys or keep only the later value, so the result isn’t reliable. To add a DNS server, edit the existing list. To have a client merge configs, use an explicit override mechanism and inspect the config it generates.
Full configs vs. proxy lists
A full config contains runtime settings such as listeners, proxy groups, and rules. A proxy list mainly describes connection parameters. Both may use YAML, but they serve different purposes. A file referenced by proxy-providers usually uses the provider format; its file extension alone doesn’t make it a complete subscription. If an import fails, check whether the response is actually a login page, an error message, or encoded text. For format differences, see Subscription URLs and YAML Formats.
Treat the examples below as snippets showing how particular fields are written, not as standalone, runnable config files. In particular, snippets that name proxy groups or providers must match the definitions in your config. Before saving, check whether each snippet belongs at the top level or inside a list item. A misplaced field may be ignored without an error, leaving the old behavior in place—that’s often harder to spot than a failed load.
Ports & Operating Modes
Port settings determine where an app sends its connection—not which proxy it eventually exits through. A system proxy usually points apps to a local HTTP or mixed port; an app’s SOCKS setting needs a SOCKS listener. Confirm the listener type before entering its address and port. Entering the remote proxy’s port as a local listening port, or vice versa, can cause a connection failure, but those ports belong to different parts of the connection path.
port, socks-port, and mixed-port
port listens for HTTP proxy connections, socks-port for SOCKS connections, and mixed-port accepts both HTTP and SOCKS on one port. A single mixed port is usually enough for everyday use; you don’t need to enable every listener for the sake of completeness. Listeners can’t share the same address-and-port combination. If another client or background service already has the port, the core may fail to start.
mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false
profile:
store-selected: true
| Field | Purpose | What to check |
|---|---|---|
mixed-port | Mixed proxy listener | The port matches the one entered in the app |
allow-lan | Allow devices on the local network to connect | Listen address, firewall, and access scope |
mode | Select rule, global, or direct mode | Whether the UI overrides the runtime setting |
log-level | Set the level of log detail | Restore an appropriate level after troubleshooting |
Local network access requires all of the following
allow-lan: false is suitable when the proxy is for local use only. To connect another device, enable LAN access and use a reachable listen address. On that device, enter the LAN address of the machine running the client—not its own loopback address. Then check the operating system firewall and whether Wi-Fi client isolation is enabled. Allowing LAN access doesn’t add authentication or make it safe to expose a listening port to the public internet.
Be clear about who can use a shared listener and which networks can reach it. Where needed, configure authentication and access controls supported by the client. Keep the management interface separate from the proxy listener: external-controller is for controlling the core, not an address to enter in a browser’s proxy settings. If remote control isn’t needed, keep it accessible only on the local machine. Don’t copy examples that expose the controller publicly or put its credentials in a publicly downloadable config.
Mode and traffic interception are different things
rule selects an exit according to rules, global uses the global policy, and direct connects directly. Global mode doesn’t force every app through the proxy; it only changes how requests that reach the core are routed. An app that bypasses the system proxy may still connect directly, even when the UI shows global mode. First check whether the connection appears in the client’s connection list, then investigate the selected mode.
A system proxy typically covers apps that honor the system proxy settings. TUN intercepts traffic through a virtual network interface; it isn’t another name for the same setting. TUN also involves permissions, routing, DNS interception, and other virtual adapters. Turning it on alone doesn’t mean everything is configured. For an initial test, try a proxy-aware app through the mixed port. Enable TUN separately to avoid troubleshooting listener and routing issues at the same time.
The client may override the mode and policy selections in the config with persisted state. For example, store-selected saves proxy group selections to avoid choosing them again after a restart, but a changed default list order may not become the current selection. Check the live mode shown in the UI, the group’s current exit, and the runtime config—not just a line in the subscription.
If a port is in use, first close duplicate clients and check whether a background core is still listening; then choose another port if needed. Update the system proxy, browser extensions, and any manually configured app settings to match. If you change only the YAML and leave an app on its old port, the core may appear healthy while web pages fail to load. There’s usually no need to reinstall: make sure the listener and app settings agree.
DNS Configuration
DNS resolves domain names to addresses and can affect routing decisions based on names or IPs. A page failing to load doesn’t necessarily mean the proxy is down: DNS may fail before a connection to the remote server is attempted. When troubleshooting, distinguish the target website’s domain, the proxy server’s domain, and the upstream DNS server’s domain; they may use different resolution paths. Using one DNS server for every purpose looks simple but can create dependency loops when network conditions change.
Enable built-in DNS and fake-ip
dns.enable controls the built-in DNS service. listen sets its listening address, but that alone doesn’t send operating system queries to it. System DNS settings, client interception, or TUN-based DNS interception must route the requests to the core. With enhanced-mode: fake-ip, domains receive virtual addresses and the core keeps the mapping for routing connections later. A virtual address isn’t the website’s real server address and mustn’t be used as a proxy node address.
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:
- 223.5.5.5
nameserver:
- https://dns.alidns.com/dns-query
proxy-server-nameserver:
- 223.5.5.5
fake-ip-filter:
- "*.lan"
- "localhost"
The addresses above illustrate how the fields relate; test whether they work on your network. default-nameserver is commonly used to resolve the domains of upstream DNS servers, so choose a bootstrap resolver reachable directly on your current network. proxy-server-nameserver sets the resolution path for proxy server domains. This can help avoid a loop where connecting to the proxy requires resolving its hostname through the proxy first. It isn’t the universal resolver for website queries.
Check resolution and connection routing separately
nameserver lists the primary upstream resolvers. nameserver-policy can select upstreams by domain or supported rule conditions. For finer control, start with a narrow policy you can verify, then expand it gradually. A DNS query taking one path doesn’t mean the subsequent website connection uses the same exit; the connection still follows routing rules. Confusing the two can lead to the mistaken conclusion that a successful lookup proves the proxy is working.
mihomo’s respect-rules lets DNS upstream connections follow routing rules. Before enabling it, plan how proxy server domains will be resolved and make sure the rules don’t depend on lookups that haven’t happened yet. For beginners, a clear bootstrap path matters more than stacking multiple encrypted upstreams. If your network can’t reach an upstream, adding more addresses along the same path may not help and can make logs harder to read.
Use fake-ip-filter for domains that shouldn’t receive virtual addresses, such as some LAN discovery services or apps that need real addresses. Filtering changes DNS behavior; it doesn’t make a connection go direct. If a domain should connect directly, also check that its routing rule targets DIRECT. Don’t add every site with a problem to the filter. A long list can hide an interception issue and make fake-IP mappings harder to observe.
IPv6, Caching, and Troubleshooting Boundaries
Top-level ipv6 and the DNS setting with the same name aren’t interchangeable switches. The top-level field affects IPv6 use by the core; the DNS field affects how the built-in resolver queries and returns addresses. The operating system, apps, and other DNS services may have their own IPv6 paths. If some sites work intermittently, check whether IPv4 is intercepted while IPv6 bypasses the proxy before concluding that a node is unstable.
Changing DNS doesn’t re-resolve existing connections, and app or system caches may retain old results. Reload the config, close the affected app connections, and make a new request. Clear the relevant cache only if needed. With fake-ip, avoid carrying stale cached results into a different or incompatible address mapping. Resolving a domain to an address only confirms that one step worked; also check the destination, rule, and exit in the connection list.
When comparing DNS setups, change one thing at a time: try a different upstream, test filtering, then adjust whether DNS follows routing rules. Note the failing domain, test time, and stage shown in the logs—not just that a page was slow. This helps distinguish a bootstrap failure, an unreachable upstream, a broken domain mapping, and a failed connection after resolution. For the last case, look at the proxy and routing sections instead of adding more DNS servers.
Proxy Node Fields
proxies describes what’s needed to connect to a remote service. A node name is just a local label; the protocol is specified by type, and the required fields vary by protocol. A name that mentions a protocol doesn’t mean the node actually uses it. Check the fields and confirm that the current core supports the specified type. A GUI importing the text doesn’t prove the core can connect; validate both steps separately.
Shared fields and protocol-specific fields
Most nodes have name, type, server, and port. The server can be a domain or an IP address, and the port must match the remote service. Authentication varies by protocol: it may use a password, a user ID, or other credentials. Don’t mix fields from different protocols or assume changing type converts a node. The client and server must agree on how to connect.
proxies:
- name: SS-Example
type: ss
server: example.com
port: 8388
cipher: aes-128-gcm
password: "your-password"
udp: true
This snippet shows the structure of a Shadowsocks node. example.com and the sample password don’t point to a usable service. Replace them with details from your provider and add the node name to a proxy group. cipher must match the server; don’t choose another method just because it looks stronger. If the server address is right but authentication is wrong, the underlying connection may still be established while app traffic fails.
Don’t change TLS and transport settings interchangeably
Protocols that support TLS may also use servername, certificate verification, and application-layer protocol settings. Some transports have separate paths, headers, or options. These fields describe different layers: the server address determines where to connect, the server name is used in the TLS handshake, and the transport path helps the server identify the connection. Replacing a server name with an IP address without preserving the original name can cause certificate verification to fail.
For certificate errors, first check the system clock, the server name, the certificate chain, and any intermediary devices on the network. Disabling certificate verification isn’t a general fix, and a temporary connection doesn’t mean the issue is resolved. Check any provider-specific settings against their instructions, and note which stage failed in the logs. A handshake failure, an authentication failure, and a timeout connecting to the destination call for different fixes.
udp: true allows the relevant UDP capability for that node, but actual support depends on the protocol, remote service, connection method, and local network. It isn’t a universal switch that enables UDP proxying for every app. A browser opening web pages only shows that some TCP or app connections work. Test games, voice apps, and other UDP traffic separately, and check whether an app is bypassing the proxy listener.
Proxy Providers and Subscription Updates
When you have many nodes or frequent updates, proxy-providers can keep the node source separate from the proxy group definitions. A provider reads or fetches a node list; a group references the provider by name using use. This refers to a provider, not an individual node. The file format, accessible path, and update method must be supported by the current core and client. Don’t put a full client config in an entry that accepts only a node list.
proxy-providers:
local-nodes:
type: file
path: ./providers/local-nodes.yaml
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 600
proxy-groups:
- name: PROXY
type: select
use:
- local-nodes
The provider file should organize nodes in a top-level proxies: list. Paths are usually resolved relative to the core’s working directory, but a GUI client may restrict readable locations or use a different directory. Don’t assume that putting the file beside the subscription makes it accessible. If it can’t be found, check the actual path in the runtime logs. If a health check returns nothing, determine whether the provider failed to load, the list is empty, or the test request failed before treating every node as unavailable.
After a subscription update, renamed or removed nodes can break proxy groups that reference them by name. For long-term customization, use stable provider references or node filters supported by the client. Don’t repeatedly edit the original node list if each refresh overwrites it. If the update itself fails, follow the Subscription Refresh Troubleshooting steps to check the URL, network, and response format before inspecting node settings.
Proxy Groups & Health Checks
Proxy groups sit between rules and nodes. A rule doesn’t need to know which server is available; it sends the request to a stable group name, and the group handles manual selection, automatic selection, or failover. That way, changing nodes doesn’t require editing every rule, and different use cases can have separate groups. For example, everyday browsing and a specific service can use different groups. A group name grants no special behavior on its own; the result depends on its exits, test method, and matching rules.
Choosing among four common group types
Use select for manual choices when you want a fixed exit. url-test picks a node based on test results, for cases where you want the core to choose among candidates. fallback prioritizes available candidates in list order rather than always choosing the lowest test value. load-balance distributes connections using a supported strategy; it doesn’t combine multiple connections into a faster download.
proxy-groups:
- name: PROXY
type: select
proxies:
- Auto Select
- DIRECT
- name: Auto Select
type: url-test
proxies:
- SS-Example
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 50
This snippet requires the node with the same name defined in the previous section. The outer manual group leaves control to the user; the inner automatic group tests candidates. An automatic group with one candidate can still test it, but has no alternative to switch to. interval sets the check interval, and tolerance helps prevent frequent switches caused by small changes in test results. It isn’t a download-speed threshold and can’t guarantee the same experience on every site.
| Type | Selection basis | Best for |
|---|---|---|
select | User’s current selection | When you want a controllable exit and repeatable tests |
url-test | Health check results | Many candidates, with automatic selection allowed |
fallback | Candidate order and availability | A clear primary/backup setup |
load-balance | Connection distribution strategy | When you understand the impact on sessions and exits |
A successful test answers one question
A health check tells you whether a candidate can reach a test target in the specified way; it doesn’t replace real-world testing. The test target may be unreachable, blocked on your network, or fail to resolve, making working nodes appear unavailable. Conversely, a successful test doesn’t prove that a particular account service, streaming platform, or game will work. Choose a stable, lightweight test target that’s reasonably relevant to your use case.
A very short check interval means more frequent requests, not necessarily better choices. An unstable network can also make results fluctuate. Look for patterns first: does the failure happen only after waking from sleep, on a particular network, or with just one test URL? To isolate an issue, temporarily switch to a manual group and pin one node. This reduces the effect of automatic switching on logs and the actual experience while you test each candidate.
Provider health checks and proxy group checks operate at different levels. Know which component runs each check and which candidates it tests. A result in a provider doesn’t mean every group that uses it behaves the same way. When referencing a node source with use, confirm the provider loaded successfully. If you also specify a name list, check for duplicate candidates or an unexpected direct connection in the group.
Nested references and saved state
A proxy group can reference another group, but references must not form a loop. If group A points to B and B points back to A, the names may exist but no definite exit can be selected. Keep the structure shallow: a use-case group points to a selection group, which points to nodes. Too many layers make connection records harder to read and put several selections between the node shown in the UI and the actual exit.
Login, payment, and long-lived sessions can be sensitive to exit changes. If automatic switching or connection distribution sends requests through different exits, a service may ask you to authenticate again; that doesn’t necessarily mean the node is broken. Use a separate manual group for these tasks to keep the policy stable. After changing a group type, start a new connection to test it. Existing long-lived connections may not move immediately, so the new UI selection and old sessions can coexist briefly.
If a proxy group selection changes unexpectedly after switching subscriptions, check whether the client restored a saved selection, whether the original node was removed, and whether the group name was reused from an older config. Stable group names can preserve your preferences, but they can also carry over state. When troubleshooting, note the actual selected node—not just “Auto Select”—so you can reproduce the connection after a reload or automatic switch.
Rule Syntax & Matching Order
Rules are checked from top to bottom; usually, the first matching rule determines the exit. Put narrow exceptions first, broader categories later, and finish with MATCH for everything else. No keyword can replace careful ordering: the same rules can produce different results when rearranged. Before writing a custom rule, state which requests it should match, then choose a rule type that expresses that intent precisely.
Domain and IP rules
DOMAIN matches an exact domain, DOMAIN-SUFFIX matches the domain and its subdomains, and DOMAIN-KEYWORD matches a keyword. Short keywords can catch unrelated sites, so exact domains or suffixes are usually better for exceptions. Don’t include a scheme, path, or query string in a domain rule. A URL is a complete web address; domain rules match its hostname.
rules:
- DOMAIN,router.example.com,DIRECT
- DOMAIN-SUFFIX,example.com,PROXY
- DOMAIN-KEYWORD,example,PROXY
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- GEOIP,CN,DIRECT
- MATCH,PROXY
In this example, router.example.com matches the exact direct rule before the later suffix rule can send it through a proxy. IP range rules are useful for LANs or defined network ranges; GEOIP classifies addresses using geographic data. Location doesn’t tell you what a site is used for, and a content delivery network can give one service addresses in multiple regions. Don’t treat an IP’s location as a permanent label for a service.
What no-resolve actually does
no-resolve is commonly used with IP rules to avoid actively resolving a domain just to check that rule. It doesn’t disable DNS for the entire request or guarantee that the rule skips all domain requests. If the core already knows the destination address, it may still match the IP rule. Use this option to reduce unnecessary lookups or control matching—not as a way to bypass every DNS problem.
Domain rules require the core to know the domain. If a request uses an IP address directly, the app performs encrypted DNS itself, or the connection doesn’t include a usable hostname, a domain rule may have nothing to match. DNS mappings or sniffing can help in some cases, but sniffing has its own protocol, encryption, and config limitations. Check whether the connection details show a domain before deciding whether the rule is wrong or the core lacks the information to match it.
GEOSITE and RULE-SET
GEOSITE uses domain category data to represent a group of services; RULE-SET references a rule provider. Both depend on available data, and the category name must actually exist. Adding a category name found online doesn’t provide the data automatically. Before importing a large rule setup, check the data format, update path, and core support. A config may load while failing at runtime because a referenced resource is missing.
rule-providers:
private-domains:
type: file
behavior: domain
format: yaml
path: ./rules/private-domains.yaml
rules:
- RULE-SET,private-domains,DIRECT
- MATCH,PROXY
The provider file above can use a top-level payload: list containing domain matches such as "+.example.com". behavior: domain is for domain sets, ipcidr for IP ranges, and classical for supported complete rule entries. They aren’t interchangeable without conversion. Don’t put full rule entries in a list that accepts only domains; the result may be a format error or unexpected matching.
A rule provider supplies the match conditions; the RULE-SET entry decides which policy receives matching requests. This lets multiple configs reuse the same domain set without hardcoding every exit into it. If sets overlap, the outer rules still apply in order. A more specific-sounding set name doesn’t give it higher priority. Change priority by moving the referencing rule.
Use connection records to explain a match
If traffic is routed incorrectly, inspect a specific connection and note its domain, destination address, matched rule, and final exit. If it matches MATCH, earlier conditions didn’t match; the catch-all rule isn’t broken. If the rule is right but the exit is wrong, check the proxy group’s current selection. If the request isn’t listed at all, go back to traffic interception. For a fuller look at combining these methods, see GEOIP, GEOSITE, and RULE-SET Routing in Practice.
Overrides & Config Merging
Overrides let you keep local settings while a subscription updates. Editing the original subscription may mean your changes disappear at the next refresh; editing a generated runtime file may not survive a client restart. The right place is usually the client’s persistent override, extension config, or merge settings. Clients implement these differently, so don’t assume an override format in one UI is a standard field understood by every core.
First, find out what generates the final config
A config may pass through several stages: the original subscription, persistent local settings, client processing, and the core’s runtime state. The client might set a fixed listening port, add a controller, replace DNS, or insert rules during loading. If a subscription line has no effect, the field may still be supported—it may have been overridden later. Find the client’s runtime config preview, export, or log, then compare what actually reaches the core before and after your change.
Clash Plus is a good first choice for a multi-platform client; check the app itself to see which config options it supports. To install a client, choose your platform on the client downloads page. Clash Verge Rev, FlClash, and other clients may use different names and execution orders for extension configs. Don’t follow another client’s button labels, and don’t edit a temporary file that the client regenerates on every run just to preserve local rules.
Merging objects and lists are different
Object fields may merge recursively or replace the whole section; lists may be replaced, prepended, appended, or deduplicated. For example, overriding one DNS subkey may preserve the other DNS fields in one merge mechanism but require the entire object in another. Rule lists need particular care: if you append a custom rule after the existing MATCH, the file contains the rule but it will never match.
# Example override for a client that supports this merge behavior
# Not a universal field that can be passed directly to every core
prepend-rules:
- DOMAIN-SUFFIX,example.com,DIRECT
append-proxies:
- name: Local SOCKS
type: socks5
server: 127.0.0.1
port: 1080
Names such as prepend-rules and append-proxies may describe client-provided merge operations. Don’t add them to the top level of a standard config.yaml without confirming support. The core’s final runtime config should still contain regular rules and proxies lists. If your client doesn’t support these keys, use its own merge or extension feature instead of pasting the same snippet repeatedly.
The local SOCKS snippet also requires a service to be listening at the specified address and port; defining a node won’t start that service. After adding a node, you’ll usually need to add it to a proxy group before it can be selected in the UI. If a provider generates the group automatically, check whether it includes locally added nodes. Having a node in the config and being able to reach it through a rule are separate things to verify.
| What you change | Main risk | How to verify |
|---|---|---|
| DNS object | Replacing the whole object can remove existing fields | Compare the complete final DNS configuration |
| Rule list | Custom rule placed after the catch-all | Check the order and send a request that should match |
| Proxy list | Duplicate name or no group reference | Check the name and selection path |
| Proxy group list | Replacing the list can break existing references | Check rule targets and group candidates |
Make small changes to keep the config maintainable
For long-term maintenance, override a few specific fields rather than copying an entire subscription and maintaining a separate fork. A full copy also makes you responsible for tracking node changes, group updates, and rule resource updates. If you only need one domain to connect directly, add a clear rule near the top. If you only need a different port, change just the listener field. Smaller changes are easier to spot when the subscription changes and easier to roll back.
If you need script-based processing, treat it as a config build program, not text to paste in casually. A script may fail if a field is missing, a list is empty, or a name changes, so define its input assumptions and failure behavior. Don’t print credentials to the console or depend on fixed indexes in a node list. Use stable group names or explicit conditions, then check the result for empty groups, duplicate names, and broken references.
Verify persistence twice: reload the local config and check the current run, then update the subscription and make sure the local change remains in the right place. Finally, close and reopen the client to see whether saved state affects the result. Testing just once after editing doesn’t prove the update process works. Keep a note of what belongs to the original subscription and what belongs to local overrides; that makes rebuilding the config easier if you switch clients later.
Validation & Troubleshooting
Validate at three levels: can the file be parsed, can the core start, and does a real request use the expected exit? Passing the first check doesn’t guarantee the other two, and reaching a test target doesn’t mean every app is intercepted. Troubleshooting these stages separately is usually faster than reinstalling. Change one relevant field at a time and keep the previous config plus a reproducible request so you can tell what each change did.
Run static checks before reloading
With a standalone mihomo core, use its config test option to check the file. In a GUI client, use the built-in validation and reload features first. Run commands from a directory where the program and file are available; if the program isn’t on your PATH, specify its actual path. The command below won’t set the system proxy for an app or prove that a remote node is online. It’s mainly for catching parse errors, broken references, and related config issues early.
mihomo -t -f ./config.yaml
In a Windows command prompt, you may need to use the actual executable filename and path. If an error points to a line, also check the preceding list item, whether quotes are closed, and whether the previous indentation level is correct. If a policy is missing, search for both its definition and every place it’s used. Don’t just delete the reported line; removing a rule may send traffic through a different fallback exit.
Read logs in the order of the connection stages
After reloading, first confirm the config loaded and that listeners were created. A port conflict, insufficient permissions, or an unreadable provider file can fail before you make a web request. If the client won’t start, see How to Troubleshoot a Client That Crashes on Startup. Once the core is running, make a new request and check DNS, rule matching, policy selection, and the remote connection in order. Don’t lump every error together as a network problem.
Interpret timeouts in context: check the DNS upstream path when the resolver times out; check the node address, port, and current network when the proxy server times out; if the proxy is connected but the destination times out, investigate the server’s exit and destination reachability. A single error line is rarely enough to draw a conclusion. The surrounding log lines and connection details from the same time are more useful. See Runtime Log Errors: What They Mean and How to Troubleshoot Them.
| Symptom | Check first | Don’t assume |
|---|---|---|
| Config won’t load | Indentation, field types, and name references | Don’t start by adjusting node test settings |
| App has no connection records | System proxy, app proxy settings, and TUN routing | Global mode doesn’t automatically intercept traffic |
| Request matches MATCH | Earlier conditions, domain information, and rule order | A catch-all match isn’t an error by itself |
| Correct rule, wrong exit | Current group selection and nested references | The configured default may not be the active selection |
| Test succeeds but the service fails | Actual destination, protocol, and session requirements | A health check doesn’t cover every service |
Use a minimal test to isolate the issue
Select one node in a manual group, turn off unnecessary automatic switching, and send a request from an app known to support proxies. If the listener works but traffic fails after enabling TUN, focus on permissions, routing, DNS interception, and other virtual adapters—not the node password. If both direct and proxied requests fail to resolve the same domain, troubleshoot DNS first. Change one condition at a time so each result is comparable.
To test a custom rule, add an exact-domain rule near the top and make a new connection to check whether it matches. If the exact rule works but a larger ruleset doesn’t, check the set’s format, load status, and position in the outer rule list. If the exact rule also misses, check whether the request hostname is what you expect. A page may request resources from several domains, so its homepage loading doesn’t mean every resource uses the same exit. Inspect the specific connection that failed.
After reloading, account for existing connections, DNS cache, and saved selections. Long-lived connections may keep using their original exit, browsers may reuse connections, and the client may restore a previously saved policy. For a clean test, save the current state, close the relevant connections, and make a new request. Don’t keep old sessions open and infer that all traffic has migrated just because the UI shows a new group name; that can produce contradictory observations.
Roll Back and Share Useful Troubleshooting Details
If a change fails, return to the most recent working config instead of stacking more switches on top of an error. Reapply changes in order—ports, DNS, nodes, groups, rules, then overrides—and note where things start or stop working. When asking for help, include the operating system, client name, core, failure stage, and the smallest relevant config snippet. Remove subscription URLs, passwords, user IDs, and controller credentials first; check screenshots for sensitive details in sidebars and logs too.