YAML Guide / Configuration Reference

Clash YAML Configuration Reference

Look up fields by name and trace their effect through traffic flow. First distinguish the original subscription, client overrides, and the configuration loaded by the core; then edit ports, DNS, or rules.

Installing the client or importing a subscription for the first time? Follow the user guide to get connected. If it’s already running and you need to understand settings or resolve configuration conflicts, use this reference. Examples focus on commonly used mihomo syntax; older Clash cores may not support every field. Choose a client from the download center. For Windows, macOS, Android, and iOS, consider Clash Plus; on Linux, see options such as Clash Verge Rev.

Field Reference Copyable YAML Runtime Config Troubleshooting

1. YAML Structure and Configuration Sources

First, identify which file you’re editing

Saving changes in an editor doesn’t mean the core is using them. GUI clients typically separate the original subscription file, user-defined override snippets, and the merged runtime configuration passed to the core. A subscription refresh regenerates the original file, so edits to its rules may disappear on the next update. Changes to the runtime file may also be overwritten when the client starts. First check which profile is active, then find the configuration preview, runtime config, or export option and verify the final value of the field you changed.

The snippets on this page are organized by purpose; don’t concatenate every example into one file. A YAML document should have a mapping at the top level. dns, proxies, proxy-groups, and rules are separate keys. Writing dns twice at the same level doesn’t mean the sections will be merged automatically: the parser may reject the file or keep only the later value. When editing, find the existing section and modify it in place. The minimal configuration below checks the structure and a local listener. All traffic goes direct; it includes no working proxy nodes.

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info

proxies: []
proxy-groups: []

rules:
  - MATCH,DIRECT

Indentation, Lists, and Strings: The Basics

Indentation defines how values are nested. Use two spaces consistently; tabs are not a substitute. A space after a colon separates a key from its value, and a space after a hyphen marks a list item. Each entry under rules is a string in a list, while each item under proxies is usually a mapping with multiple fields. A node’s name, type, and server must use the same indentation level. Indenting port one level further may cause a parse error rather than change the port.

Quote strings containing special combinations such as a hash or a colon followed by a space. Passwords and identifiers should especially be treated as strings to prevent numbers from being parsed as numeric values or losing leading zeros. Single quotes are generally better for ordinary text containing backslashes; double quotes interpret escape sequences. If a string needs a double quote, escape it correctly. Avoid copying configuration from chat apps if it contains full-width colons, curly quotes, or invisible indentation: characters that look alike can parse differently.

proxies:
  - name: "Example Node"
    type: ss
    server: proxy.example.com
    port: 443
    cipher: aes-128-gcm
    password: "your-password"

proxy-groups:
  - name: "Manual Select"
    type: select
    proxies:
      - "Example Node"
      - DIRECT

rules:
  - MATCH,Manual Select

Nulls, Booleans, and Cross-References

false is a Boolean; "false" is a string. Don’t rely on the core to correct the type automatically. [] is an empty list, {} is an empty mapping, and a key with nothing after it usually represents a null value. These aren’t interchangeable. Node names, proxy group names, and rule targets refer to one another, so use consistent, unique names. Avoid commas in names because rules use commas to separate arguments. Readable names can include non-Latin characters, but every reference must match exactly.

Check configuration at two levels: successful YAML parsing only confirms the syntax is valid; successful core loading indicates that field types, protocol support, and name references are basically valid. Even then, the remote address, password, or rule intent may still be wrong. Avoid introducing complex anchors, merge keys, or template syntax all at once; they can amplify differences between client parsers. Start with ordinary mappings and lists, then consider reducing duplication. If you’re unsure which core is running, check the client’s About page or startup log rather than inferring compatibility from the client’s name.

2. General Settings: Listening Ports and Proxy Modes

Ports accept traffic; they don’t determine connection speed

mixed-port accepts both HTTP and SOCKS proxy requests on a single listening port, making it convenient to point browsers and command-line tools to the same endpoint. port is a dedicated HTTP proxy port, and socks-port is a dedicated SOCKS port; you don’t have to configure all of them. For typical desktop use, starting with the mixed port avoids confusion from multiple listeners. A port number is just part of a local service address. Changing it won’t make a remote proxy faster.

FieldPurposeWhat to Check
mixed-portShared HTTP and SOCKS endpointClient and application ports match
portDedicated HTTP proxy endpointCheck for conflicts with other listeners
socks-portDedicated SOCKS proxy endpointConfirm the app uses the SOCKS protocol
allow-lanAllow connections from the local networkAlso check the bind address and firewall
modeChoose a traffic routing modeDoesn’t mean the system proxy is enabled
log-levelControl log verbosityRestore the usual level after troubleshooting

After changing a port, reload the configuration and confirm that the new listener is active. Then update the system proxy, browser’s manual proxy settings, or terminal environment variables to use the new value. Existing environment variables aren’t updated automatically by YAML, and already-open terminals may retain their old settings. Desktop clients may override the file’s port with a setting in the UI, so check the runtime configuration and listener logs. If a port is occupied, identify the process and check whether it’s another client instance. Don’t terminate an unfamiliar system process just to free a port.

mixed-port: 7891
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false

What Rule, Global, and Direct Modes Change

mode: rule routes traffic according to the rules list and is usually the right choice for everyday routing. global sends traffic entering the core through the global policy; check which outbound is selected by that policy. direct routes traffic directly. The key phrase is traffic entering the core: an app that isn’t using the system proxy or an explicit proxy, and isn’t being captured by TUN, won’t be proxied just because you switch to global mode. The routing mode and the way traffic enters the core are separate settings.

Switching modes is useful for comparison, not for hiding rule problems. If rule mode fails but global mode works, check rule matching, proxy group selection, or DNS rather than leaving the client in global mode and calling it fixed. If both fail, start with the node, authentication, listener, and network reachability. Existing long-lived connections may continue using the old outbound, so test with a new connection after switching. For more detail, see the proxy mode notes in Troubleshooting. Don’t mistake a mode change for a way to optimize the connection.

Manage LAN Listeners and the Controller Separately

allow-lan: false is suitable when only local apps need the proxy. To offer the proxy to other devices, allow LAN access and check bind-address, the host firewall, Wi-Fi client isolation, and the address those devices use. Other devices should connect to the LAN address of the machine running the client, not their own loopback address. Exposing a listener broadens access. Do so only on trusted networks, with authentication or access controls, rather than exposing the port on a public network.

external-controller is a management API, not a browser proxy address. Setting the system proxy to the controller port won’t provide a working proxy connection. Prefer binding the management API to a loopback address; if remote access is needed, plan authentication and network boundaries separately. log-level: debug can help temporarily with troubleshooting, but generates more detail. Redact subscription URLs and credentials before sharing logs. ipv6 controls address handling; it can’t provide IPv6 connectivity that the network itself lacks. Don’t change it alongside multiple DNS settings without a way to test the results.

For details on identifying the process and changing ports, see Troubleshooting a Busy Port 7890. The goal isn’t to pick a different number; it’s to ensure the listening address, protocol, and application settings all match, then verify the change with a new request.

3. DNS: Resolution Paths and fake-ip

First, distinguish core DNS from system DNS

DNS configuration involves more than entering a server address. Ask three questions: what sends domain names to the core, which upstream servers the core uses to resolve them, and how the results affect subsequent connections. dns.enable enables the built-in DNS service, and listen sets its listening address; neither automatically redirects all system requests to it. System DNS, browser Secure DNS, app-specific resolution, and TUN interception can coexist. Seeing a DNS server in the config doesn’t prove that a particular request uses it.

The example below shows a common fake-ip setup listening on a high-numbered local port for isolated testing. It isn’t a complete transparent proxy setup and won’t change the system resolver automatically. default-nameserver resolves the hostnames of upstream DNS servers, so use resolvers available as IP addresses directly. nameserver handles general domain queries. The example upstreams must be reachable on your network; replace them as needed. Don’t assume any set of addresses is suitable everywhere.

dns:
  enable: true
  listen: "127.0.0.1:1053"
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - "*.lan"
    - "localhost"
  default-nameserver:
    - 223.5.5.5
  nameserver:
    - https://dns.alidns.com/dns-query

fake-ip doesn’t mean DNS failed, and it doesn’t provide encryption

enhanced-mode: fake-ip assigns synthetic addresses to queries and maintains a domain mapping, helping preserve domain information for subsequent connections. A result beginning with 198.18 isn’t necessarily an error. What matters is whether connections to the synthetic address are still intercepted by the same proxy core. If DNS returns fake IPs but subsequent traffic bypasses the core, connections will usually fail. That’s why the DNS path and connection path must work together; configuring a resolver in isolation on the system isn’t enough.

fake-ip-filter excludes specific domains from synthetic address assignment. It’s often used for LAN services that genuinely need real addresses. Don’t casually add large numbers of public domains to the filter; doing so loses the convenience of domain mapping and complicates troubleshooting. redir-host returns real DNS results. It’s a different operating mode, not inherently faster or safer. To investigate compatibility issues, compare one setting at a time. Note the affected domains, apps, and access paths before deciding whether to add an exception.

nameserver, fallback, and Per-Domain DNS

fallback isn’t simply a second-choice server. The core evaluates results using conditions such as fallback-filter; options may involve domains, IP ranges, and geolocation data. Check the documentation for the core you’re running. Copying a fallback block without understanding its filters can increase query volume or replace results that were already working. First confirm basic resolution with one reachable upstream, then add routing based on evidence. Don’t start by stacking multiple public resolvers.

mihomo’s nameserver-policy can route queries for specific domains to designated resolvers, such as sending internal domains to a LAN DNS server. Resolving the proxy server’s own hostname may also involve proxy-server-nameserver, which can prevent a dependency loop where the proxy is needed before its connection can be established. Encrypted DNS protects only the relevant DNS traffic; it doesn’t automatically route application connections through a proxy. Check the fields supported by your core to confirm whether DNS follows routing rules and how upstream connections are made.

dns:
  enable: true
  listen: "127.0.0.1:1053"
  enhanced-mode: fake-ip
  default-nameserver:
    - 223.5.5.5
  nameserver:
    - https://dns.alidns.com/dns-query
  nameserver-policy:
    "+.home.arpa":
      - 192.168.1.1
  proxy-server-nameserver:
    - 223.5.5.5

The example above shows a separate DNS section. Replace 192.168.1.1 with the actual internal resolver; don’t paste it alongside the previous example as a second top-level DNS section. TUN’s dns-hijack belongs under tun, not dns, and generally can’t intercept HTTPS DNS requests made directly by apps. Troubleshoot the core listener, system resolution, and browser behavior separately. Clear caches or start a new connection so old results don’t affect the test.

4. Proxies: Protocol Fields and Providers

Shared fields don’t make protocol settings interchangeable

proxies is a list of locally defined nodes. The most common shared fields are name, type, server, and port: the name is referenced by proxy groups, the type determines how the protocol is parsed, and the server and port specify the connection target. server usually contains only a hostname or IP address—not https://, a path, or subscription query parameters. The node’s remote port has no reason to match the local mixed-port. Don’t copy one into the other.

Protocol-specific settings must come from your provider. Shadowsocks needs the correct cipher and password; Trojan typically requires a password and TLS settings; VMess and VLESS use their own IDs and transport options. Changing only type to a different protocol won’t make the existing node work with it. The transport must match too: WebSocket paths and headers, gRPC service names, and similar fields matter only if the server is configured for them. Adding extra fields won’t improve compatibility.

proxies:
  - name: "Example SS"
    type: ss
    server: proxy.example.com
    port: 443
    cipher: aes-128-gcm
    password: "your-password"
    udp: true

  - name: "Example Trojan"
    type: trojan
    server: trojan.example.com
    port: 443
    password: "your-password"
    sni: trojan.example.com
    skip-cert-verify: false
    udp: true

TLS Names and UDP Support Can’t Be Added with a Toggle

sni is the name used for the TLS handshake. It may match the dial address or be specified separately by the provider. For certificate errors, first check the device clock, server name, certificate validity, and whether the connection has been intercepted. Don’t routinely set skip-cert-verify to true as a workaround. Certificate verification helps expose issues such as a name mismatch. If the initial TCP connection can’t be established, changing SNI or certificate settings usually won’t fix an unreachable address.

udp: true means the configuration allows the relevant capability; it doesn’t guarantee that the server, protocol, route, and app entry point all support UDP. If browsing works but games or voice calls fail, check the actual transport and interception path. Conversely, a timed-out speed test doesn’t prove all traffic is failing: the test target, request method, and node routing may differ. Distinguish handshake failures, authentication failures, and remote connection failures instead of treating every error as a dead node.

proxy-providers Load a Set of Nodes

proxy-providers lets the core load a set of nodes, which proxy groups can then reference with use. For an HTTP provider, url is the resource address, path is the cache location, and interval usually sets the refresh interval in seconds. A provider resource isn’t the same format as a full client subscription. Common node providers need to contain a proxies list. If the response is a web login page or another format, changing its file extension won’t turn it into valid YAML.

proxy-providers:
  remote-nodes:
    type: http
    url: "https://example.com/proxies.yaml?token=xxxx"
    path: ./providers/remote-nodes.yaml
    interval: 3600
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 600

proxy-groups:
  - name: "Subscription Select"
    type: select
    use:
      - remote-nodes

The example address shows the structure only; replace it with an actual provider resource. If the client’s profile page already manages the subscription, you usually don’t need to add a second update mechanism manually. First identify whether your provider supplies a full config, a node list, or a collection of URIs, then choose the right import method. Relative cache paths are resolved from the core’s working directory, not necessarily the folder open in your editor. If updates fail, check the client’s data directory and permissions before repeatedly moving the YAML file.

Credentials are sensitive. When sharing screenshots or support logs, include only the domain, error type, and necessary fields; never publish a full subscription URL. If node names change after an update, hard-coded proxy group references may break. Provider references reduce the need to maintain each node manually, but filtering and empty groups still need attention. A successful download only means the resource was fetched. It doesn’t prove that nodes connect or that the current core supports every protocol in the resource.

5. Proxy Groups: Manual Selection, Health Checks, and Failover

Start with clear references

Proxy groups sit between rules and the actual outbound. A rule can point to a group, which can then contain nodes, other groups, or built-in targets. This lets you change nodes without editing every domain rule. The basic select group provides manual selection and is a good starting point for confirming which routes work. In a group, proxies contains node or group names, not server addresses; use contains provider names. These fields reference different things, and even a one-character typo can prevent the config from loading.

Name groups by purpose and behavior—for example, “Everyday Outbound” for the traffic entry point and “Auto Test” for the selection method. Point everyday rules to the first group, which can then offer a test group, a backup group, or individual nodes. Don’t let a group include itself or create a cycle between groups. Avoid names that conflict with built-in targets or node names. A nested setup that loads successfully may still be hard to maintain; fewer levels make the actual outbound easier to trace.

proxies:
  - name: "Route A"
    type: ss
    server: a.example.com
    port: 443
    cipher: aes-128-gcm
    password: "your-password"
  - name: "Route B"
    type: ss
    server: b.example.com
    port: 443
    cipher: aes-128-gcm
    password: "your-password"

proxy-groups:
  - name: "Everyday Outbound"
    type: select
    proxies:
      - "Auto Test"
      - "Failover"
      - "Route A"
      - "Route B"
      - DIRECT

  - name: "Auto Test"
    type: url-test
    proxies:
      - "Route A"
      - "Route B"
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50

  - name: "Failover"
    type: fallback
    proxies:
      - "Route A"
      - "Route B"
    url: https://www.gstatic.com/generate_204
    interval: 300

rules:
  - MATCH,Everyday Outbound

A health check measures only its test request

url-test selects an outbound based on test results. url is the test target, interval sets how often to test, and tolerance reduces frequent switching caused by small differences, usually measured in milliseconds. Don’t set an excessively short interval, especially on mobile devices or with many nodes; frequent requests consume network data and battery. Choose a stable test URL with a predictable response. Avoid pages that require sign-in, redirect extensively, or restrict access from certain routes.

Node latency is the result of one test request, not a measure of video throughput, download speed, or response time for every site. A test target can be reachable while a service is affected by region, account, or service policies. If a node reports a low latency, verify it with the actual app before letting test results determine all your routing. Think carefully before including DIRECT in the group: having a health check choose between direct and proxy routes may produce a very different outbound than expected.

fallback and Load Balancing Have Different Tradeoffs

fallback typically selects the first available item in the list. Its purpose is failover, not finding the lowest latency on every request. How new connections behave when an earlier node recovers depends on the core’s implementation and current state. It won’t migrate an interrupted TCP session, so an active download may need to reconnect. Think of it as a primary route with a backup, not a guarantee that service won’t be interrupted.

load-balance distributes connections across multiple outbounds according to its configuration; it doesn’t combine their bandwidth into a faster single connection. Some services are sensitive to changes in the outbound IP and may require reauthentication or lose session state. Pin those services to a stable group. When first setting up a config, validate it with manual selection before adding automation. If manual node selection also fails, investigate the node or entry point instead of adjusting the test tolerance.

Clients may remember the last selected group option, so reloading doesn’t necessarily select the first item in the list. Settings such as profile.store-selected, the GUI’s persistence behavior, and changes to group names can all affect what gets restored. Check the currently selected item instead of relying on YAML order. When nodes come from a provider, also check whether any remain after filtering. An empty automatic group, a missing name reference, and failed health checks are distinct problems and should be handled separately.

6. Routing Rules: Match Order and Rule Providers

Rules are checked top to bottom; the first match wins

In rule mode, ordinary rules are checked in list order, and the first match determines the outbound. The most common mistake isn’t syntax, but placement: a broad rule near the top can prevent a more specific exception below it from ever running. MATCH is the catch-all and belongs at the end of the regular list. When adding a site exception, confirm that its target exists and the group selection is right, then check the match using a new connection. Seeing a domain in the rules list doesn’t prove that the rule was reached.

DOMAIN matches an exact domain, DOMAIN-SUFFIX matches a domain and its subdomains, and DOMAIN-KEYWORD matches a keyword anywhere in a domain. For a site that should go direct, prefer an exact domain or suffix instead of a short keyword that could match unrelated domains. Rules generally don’t include the URL scheme, path, or query parameters. A site may also use multiple resource domains: routing its main page direct doesn’t guarantee that images, sign-in, and API requests use the same outbound.

rules:
  - DOMAIN,printer.home.arpa,DIRECT
  - DOMAIN-SUFFIX,home.arpa,DIRECT
  - DOMAIN-SUFFIX,example.org,Everyday Outbound
  - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - GEOIP,CN,DIRECT
  - MATCH,Everyday Outbound

What IP Rules and no-resolve Actually Do

IP-CIDR matches a destination address within a network range, making it useful for private networks or known address blocks. no-resolve means the rule won’t trigger a DNS lookup; it doesn’t prevent the entire connection from using DNS. If a request already has a destination IP, the rule can still match. If it has only a domain and that domain hasn’t been resolved, the rule may be skipped in favor of later rules. Before adding this option to every IP rule, decide whether you’re trying to reduce queries or need DNS results to determine routing.

GEOIP relies on the relevant IP database, while GEOSITE uses domain classification data. Both depend on core support and resource configuration. They don’t provide real-time checks of a server’s physical location; database updates and shared IP addresses can lead to inaccuracies. For a single misrouted service, an exact rule is often safer than changing broad classification logic. Don’t send every private address to one overly broad public-network exception for convenience, especially if you use a corporate network or multiple LAN subnets.

Match rule-providers Format to behavior

Rule providers keep long lists in separate resources, which the main config references with RULE-SET. behavior: domain is for domain lists, ipcidr for address ranges, and classical for rules expressed as a type and arguments. The resource content must also match format. Don’t treat a plain-text list as YAML containing payload, or read a binary resource as text. If a download succeeds but parsing fails, check the format and response body before assuming it’s a network problem.

rule-providers:
  local-domains:
    type: file
    behavior: domain
    format: yaml
    path: ./rules/local-domains.yaml

rules:
  - RULE-SET,local-domains,DIRECT
  - MATCH,Everyday Outbound

The corresponding local-domains.yaml can look like this. Create the file and make sure the core can read it; relative paths are still resolved from the working directory. The target “Everyday Outbound” in the main config must exist as a proxy group. The rule provider file should contain only match entries, without repeating the policy name on each line. Keeping resource responsibilities clear is easier to maintain than mixing outbounds into every file.

payload:
  - "+.home.arpa"
  - "printer.example.com"

mihomo process-name rules and similar features also depend on the operating system, permissions, and how traffic enters the core. Process detection on one platform doesn’t guarantee the same behavior elsewhere. Domain rules may also lack the necessary domain information when an app resolves a name itself and then connects by IP. Check connection details for the domain, destination IP, matched rule, and actual route. Confirm the input information is complete before deciding whether to change DNS, traffic interception, or rule order.

7. Overrides and Merging: Preserve Subscription Updates

Separate Core Configuration from Client Processing

Overrides aren’t a YAML standard that works the same in every client. The core reads the final configuration, while GUI clients may apply global settings, subscription-specific settings, merge snippets, or scripts beforehand. You can’t assume that Clash Plus, Clash Verge Rev, FlClash, and other clients use the same settings locations or precedence. Check the override documentation for your client, then confirm whether the setting applies to every subscription or just one profile. If the generated file doesn’t contain the expected value, investigate the client’s processing pipeline instead of repeatedly editing the original subscription.

Common merge behaviors include replacing scalar values, recursively merging mappings, and replacing lists, but there’s no universal rule that every client must follow. For example, an override that contains only dns.nameserver may preserve other DNS keys in one tool and replace the entire section in another. Lists such as rules and proxies need particular care: a patch containing one rule might replace the entire rule list. The word “merge” doesn’t guarantee that values will be appended.

# Only for clients that accept plain YAML merge snippets.
# Confirm how the client merges mappings and lists.
mixed-port: 7891
allow-lan: false
log-level: info

dns:
  enable: true
  ipv6: false

Prepending, Appending, and Replacing Rules

To add local rules, prefer a client’s documented prepend or append feature over guessing at a private field. Prepending is useful for domain exceptions that must take priority. With appending, check whether the original list already contains MATCH; ordinary rules added after it won’t run. If the tool replaces the entire list, preserve the existing rules and catch-all, and expect to maintain a copy as subscription rules change. Choose an approach based on how much control you want to retain from the subscription.

Nodes and proxy groups also depend on one another. Removing a node but leaving its old group reference can result in a missing target. Renaming a group without updating rules breaks those references too. First decide on the final names, then keep the links between nodes, groups, and rules in sync. If you only need to change the outbound for one site, an exact rule pointing to an existing group is usually enough; there’s no need to take over the entire node list. Smaller changes are less likely to conflict with subscription updates.

YAML anchors and merge keys can reuse structures only within the semantics supported by the parser. They don’t provide cross-file overrides by default or act as a universal list-append syntax. A preview that works in one editor may still be processed differently by the client. Script overrides offer more flexibility, but also depend on the client’s expected function entry point, execution order, and error handling. This guide doesn’t provide a script template that assumes every client supports the same interface. Without clear documentation, ordinary field overrides are easier to verify than scripts from an unknown source.

Keep Configuration Layers Easy to Roll Back

Organize configuration into three layers: the subscription layer for nodes and provider rules, the local layer for ports, trusted-LAN exceptions, and personal policies, and a temporary layer for troubleshooting only. After a temporary change works, move it into the appropriate persistent layer and remove duplicate keys. Document the purpose of each override and keep a working backup from before the change. Don’t set the same port in the UI, a global override, and a subscription override; changing only one later can make it look as though the setting was saved but nothing changed.

Don’t verify an override by checking only whether the file was saved. Reload the current subscription, inspect the merged config, and search for the target key. Then confirm that proxy groups and rule references exist, and check a new request for a match. Manually refresh the subscription to confirm that the change persists; this specifically tests whether you chose the right place to store it. If it disappears after an update, move it to a client-supported local layer instead of reapplying it after every refresh. Check the scope when switching subscriptions too, so global rules don’t reference a group that exists only in one profile.

When maintaining configurations across people or devices, record four things: the field, its source, its final value, and how it was verified. Don’t record only menu clicks, since client interfaces can change. The final structure is easier to restore after an upgrade, migration, or reinstall. If an update suddenly prevents startup, first review recent overrides and references, then follow the steps on the troubleshooting page.

8. Validation and Troubleshooting: From Loading to Real Requests

Start with Parsing and Core Tests

Use the same validation order every time: syntax, core loading, port listener, node connection, rule match, and only then the app itself. Each step should have a clear input and result. If startup fails, roll back to the most recent working config rather than piling more changes onto a broken file. Before testing from the command line, confirm that you’re using the core associated with the current client. An older binary elsewhere on the system may not support newer fields, so its results may not reflect the client’s behavior.

# Run this from the configuration file's directory; adjust the command name for your installation.
mihomo -t -d . -f ./config.yaml

-f specifies the file, and -d specifies the working directory. Tests may need access to provider caches or other resources. A successful command means the configuration passed a basic loading check in that environment; it doesn’t mean remote nodes or every rule resource is working. If the client doesn’t offer a standalone command-line tool, use its configuration checker and logs for equivalent validation. Don’t copy the core binary into an uncontrolled directory or start another persistent instance just to run a test.

Parser errors often include a line number, but the cause may be on the preceding line—for example, an unclosed string, a missing list item, or a change in indentation. Inspect the complete mapping around the reported line and, if needed, work outward from a minimal structure. If a name is missing, check references between nodes, groups, and rules; deleting the reported line doesn’t fix the cause. If a field isn’t supported, confirm which core is running and where the field is valid. For permission or resource errors, check the working directory rather than changing YAML indentation.

Use an Explicit Proxy to Isolate System Interception

Once the core is running, send a new request through an explicit proxy first, temporarily taking the system proxy and TUN out of the test. The command below is for curl versions that support these options. On Windows, use curl.exe explicitly to avoid command-alias differences. Replace the port with the actual listener and choose a test URL expected to be reachable from your environment. A single failed request shows only that this path has a problem; it doesn’t prove that all proxy functions are broken.

curl --proxy http://127.0.0.1:7890 --connect-timeout 10 --max-time 20 https://example.com/
curl --proxy socks5h://127.0.0.1:7890 --connect-timeout 10 --max-time 20 https://example.com/

socks5h sends the domain to the proxy for resolution, unlike a test where the client resolves it locally before connecting. If one path works and another doesn’t, compare DNS resolution and the entry protocol before replacing all your nodes. If explicit proxying works but the browser doesn’t, check the system proxy, browser extensions, Secure DNS, and existing connections. For TUN, also check system routes, permissions, and other network interception software to make sure two tools aren’t competing for the same traffic.

Collect the Minimum Evidence for Each Symptom

SymptomCheck FirstNext Step
Fails during loadingIndentation, types, and referenced namesRun a core configuration test
Connection refusedListening address and actual portConfirm the core process is still running
DNS resolution failsQuery path and upstream reachabilitySeparate system and core DNS
One node failsProtocol, authentication, and handshake logsCompare with manual selection
Wrong outbound selectedRule match and group selectionVerify again with a new connection
Breaks after subscription updateOverride location and list mergingInspect the final runtime config

When asking for help, include your operating system, client name, core identity, steps to reproduce, and relevant redacted logs. Also say whether explicit proxying works, whether rule and global modes behave differently, and whether only one destination fails. This is more useful than a screenshot that just says “timed out.” Don’t upload a huge debug log; first select the related entries from before and after the failure, redact credentials, and state which variable you changed in each test. A consistently reproducible error makes it easier to confirm whether a fix works.

Finish with a regression check: restart the client and confirm the listener is back; update the subscription and confirm local overrides remain; switch networks, retry the target service, and check DNS caches and proxy group selection. When done troubleshooting, restore the usual log level and remove temporary relaxations and duplicate rules. The goal of configuration maintenance isn’t to add as many fields as possible, but to ensure that every field has a clear purpose and every change can be verified. For a fresh look at the connection workflow, return to the user guide. To switch clients, see the download center’s OS and architecture options.

Download the Latest Clash Version