1. YAML Structure and Config File Boundaries
Mappings, Sequences and Scalars
config.yaml is a text file that describes how the core runs. The top level is usually a mapping: a collection of keys and values. Under dns, you’ll find another mapping; under rules, an ordered sequence. Strings, numbers and Boolean values are scalars. Recognizing these three structures before editing helps prevent mistakes such as writing a sequence as a string or indenting a top-level field inside another object.
YAML uses indentation to show parent-child relationships. Use two spaces consistently, never tabs. Fields at the same level must align, and leave a space after the hyphen in sequence items. A space is also usually required after a key’s colon. Here, mode and dns are siblings, enable belongs to the DNS object, and the two nameserver values form a sequence. Blank lines improve readability but don’t affect nesting.
mixed-port: 7890
mode: rule
dns:
enable: true
nameserver:
- https://dns.alidns.com/dns-query
- https://doh.pub/dns-query
rules:
- MATCH,DIRECT
Use true or false for Boolean switches and integers for ports. Treat values that function as identifiers as strings. Quote passwords, addresses containing a hash sign and complex text containing colons to keep special characters from being parsed as comments or mapping syntax. Backslashes in single-quoted strings are generally literal; double-quoted strings support escapes. Take care with backslashes when copying Windows paths from a webpage. A comment starts at a syntactically valid hash sign outside quotes.
Top-Level Layout Does Not Determine Execution Order
Putting rules at the end of a file is a reading convention; it doesn’t mean the core processes every preceding field before applying the rules. Order matters in the rules sequence and in the candidate list of some proxy groups. The order of top-level keys usually doesn’t affect the result. Don’t define the same key twice in one mapping: parsers may reject duplicate keys or keep only the last value, so relying on that behavior is not a dependable way to override settings. To change DNS, edit the existing DNS object rather than appending a second one at the end.
Also distinguish between the original subscription, the config saved by the client and the runtime file passed to the core. A subscription may contain only nodes or a complete set of groups and rules. After import, a client may reorganize the content and add ports, a controller address or TUN settings. Editing a cached subscription may therefore have no effect, and restarting the client may overwrite your changes. To diagnose an issue, find the active config, runtime config or core config preview in the client, then note how it differs from the original file.
Valid YAML Still Needs Reference Checks
Successful YAML parsing only confirms that the indentation and data format are basically valid; it doesn’t guarantee that the current core supports every field. A rule pointing to a nonexistent group or a group referencing a misspelled node is a semantic error. Names are usually case-sensitive; spaces, trailing whitespace and full-width punctuation can also change them. Make a list of group and node names, then check the target at the end of each rule. That’s more effective than repeatedly adjusting indentation in the wrong place.
Code in the remaining sections consists of partial examples. When adding a snippet to an existing config, keep the existing fields at the same level and merge sequences item by item. A client may not use a file named config.yaml; startup options can specify another filename. The active core’s input path is what matters. For differences between the original Clash and mihomo, see Core Evolution and Compatibility Compared. Don’t assume the same config will behave identically across different cores.
2. Common Options: Ports, Modes and Network Access
Inbound Ports and the System Proxy Are Separate Settings
An inbound port is where the core accepts connections from apps. port provides an HTTP proxy, socks-port provides a SOCKS proxy, and mixed-port supports both HTTP and SOCKS on one port. For typical desktop use, starting with a single mixed port can reduce the work of maintaining multiple endpoints. Port numbers are local choices, not fixed values required by every client. The proxy address in an app must match the address the core is actually listening on.
mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false
A core listening successfully doesn’t mean the system proxy is enabled. The system proxy tells compatible apps to connect to a proxy address; the inbound port in the config simply accepts connections. With the system proxy off, apps with a manually configured proxy address may still use the core. Conversely, if the core exits without clearing the system proxy setting, a browser may keep trying to connect to a port with no listener. Check the process, listening port and system proxy separately when troubleshooting instead of relying on the client’s master switch.
| Field | Description | What to check |
|---|---|---|
mixed-port | Combined HTTP and SOCKS endpoint | Whether the local port is already in use |
allow-lan | Allow devices on the local network to connect | Whether the listening address and firewall rules match |
mode | Traffic handling mode | Whether traffic is still routed by rules |
log-level | Log verbosity | Restore an appropriate level after troubleshooting |
rule, global and direct
rule selects a policy for each connection according to rule order. global sends connections entering the core through the global policy. direct connects to the destination directly. The mode controls what happens after traffic enters the core; it doesn’t make every app send its traffic there. Global mode is not a substitute for TUN, nor can it force an app that ignores the system proxy to use a proxy automatically. First determine which traffic is captured, then decide which outbound route it should use.
Rule mode is usually a good everyday starting point because it lets you define separate conditions for direct and proxied traffic. Global mode can temporarily rule out matching issues when checking whether an outbound works. Direct mode is useful for comparison, though inbound handling and DNS may still affect the result. Restore your original mode after testing and review the connection log. For a fuller comparison, see How to Choose Between the Three Proxy Modes. A single webpage loading doesn’t prove that all traffic is routed correctly.
Listening Scope and the Controller
allow-lan and bind-address together determine whether other devices can connect to an inbound. If you only use the current computer, limiting access to the loopback address makes troubleshooting easier. To share the proxy with a phone, allow LAN access, make sure the listening address includes the LAN interface, confirm both devices can reach each other, and allow the inbound through the firewall. An open listener is not automatically safe to expose to the public internet; router port forwarding significantly changes who can reach it.
external-controller is a management interface, not a browser proxy port. It lets dashboards and clients control the core and must not be entered as an app’s HTTP proxy. A client may generate its own controller address and authentication settings; overriding them can disconnect the interface. If you don’t need separate management, keep the client’s defaults. If you do change them, bind to the local machine first, configure authentication and never post runtime files containing management credentials in a public forum.
If a port is already in use, first quit other proxy apps, then check whether an old core process is still running. After changing a port, reload the config and update any proxy addresses entered manually in apps. You can temporarily set log-level to debug, but detailed logs may include destination domains and connection information; remove sensitive details before sharing. To choose another client, visit the client downloads page and browse by platform. Clash Plus is a good starting point for everyday desktop use.
3. DNS: Resolvers, Upstreams and Domain Mapping
First Identify Who Sends Queries to Whom
DNS configuration involves at least three roles: an app or the operating system sends a query, the core’s DNS module receives and forwards it, and an upstream resolver returns the result. dns.enable controls the core module, listen sets its listening address, and nameserver specifies the upstream. Enabling the module alone doesn’t make the system use it. System DNS settings, a client’s traffic capture or TUN hijack rules must also direct relevant queries to that endpoint.
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"
- "*.local"
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://dns.alidns.com/dns-query
- https://doh.pub/dns-query
This example binds the DNS service to a non-standard local port so it can coexist with an existing system service. It shows the DNS module structure; it does not change the system resolver by itself. default-nameserver is mainly used to resolve the hostnames of upstream DNS servers, providing the bootstrap path needed to reach encrypted DNS. It is not the default resolver for every domain. If an upstream is specified by hostname and bootstrap resolution fails, the DNS module may be unable to query reliably at all.
fake-ip vs. redir-host
fake-ip assigns a virtual address to a query. The core uses it when the connection arrives to recover the original domain, then apply domain rules and select an outbound. This address is not the destination server’s real public IP; an app receiving it doesn’t mean DNS is broken. redir-host generally returns the actual resolved address and handles domain mapping differently. Choose between them based on app compatibility and how traffic is captured, not as if they were performance tiers or security levels.
Some LAN services, device discovery features and apps that require real addresses may not work well with virtual addresses. fake-ip-filter can exclude specified domains from virtual IP assignment, but it only changes DNS responses; it doesn’t add a direct rule. For domains that need access to real internal addresses, also confirm the upstream can resolve internal names and subsequent routing can reach that network. When troubleshooting, add one known domain to the filter first rather than using an overly broad wildcard.
The top-level ipv6 field and the field with the same name in the DNS object apply at different levels. The former affects IPv6 support across the core; the latter controls IPv6 resolution in the DNS module. Disabling IPv6 DNS responses won’t necessarily clear app caches, bypass built-in resolvers or remove previously stored addresses. If your network supports IPv6, enable it only after confirming the routes and outbound support. Don’t hide AAAA results just to mask a misconfigured IPv6 path.
Split DNS and Proxy Server Name Resolution
nameserver-policy selects a resolver for specific domains, which is useful for internal company domains or regions with specific DNS requirements. It determines which DNS upstream receives a query; it does not set the proxy policy for the resulting connection. proxy-server-nameserver can resolve proxy server hostnames separately, reducing the risk of a loop where reaching the proxy depends on resolving its address through that same proxy. Add these layers only when you’ve confirmed a loop or resolution mismatch; avoid changing several variables at once.
dns:
nameserver-policy:
"+.internal.example.com":
- 192.168.1.1
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
The internal domain and router address above are structural examples. Replace them with an internal domain you actually manage and an address that really provides DNS service. To troubleshoot, first check whether the core receives the query, then test upstream reachability, and finally inspect the response and how the domain is associated with the subsequent connection. An app’s built-in encrypted DNS may bypass system settings, and an existing browser connection won’t be recreated immediately after a DNS change. If needed, close old connections, clear the relevant cache and test the same destination again so you’re not judging the new config by an old result.
4. Proxy Nodes: Protocol Fields and Providers
Common Fields and Protocol-Specific Options
proxies is a static list of proxy nodes, with each entry describing one outbound. Common fields include the name (name), protocol (type), server (server) and port (port). Other options depend on the protocol; don’t copy authentication fields from another protocol. Node names are referenced by groups and rules; they don’t authenticate you. The server can be a hostname or address, but a website homepage URL or subscription link with a path cannot replace the server field.
proxies:
- name: SS-Example
type: ss
server: proxy.example.com
port: 443
cipher: aes-128-gcm
password: "your-password"
udp: true
This example shows the structure of a Shadowsocks node. The server hostname and password are illustrative and won’t establish a working connection. The encryption method, port and credentials must exactly match the server. udp: true allows the node’s UDP capability to be used; it can’t add forwarding support to a server that doesn’t provide it. Whether an app can use UDP also depends on support across the inbound, policy group, server and intermediary networks.
For TLS-based connections, distinguish the connection destination from the name checked against the certificate. The address tells the client where to connect; the server name is used for the TLS handshake and certificate validation. They can differ in some setups, but only when the service provider supplies the correct values. If you see a certificate error, check the system clock, server name, certificate chain and address rather than disabling verification. Skipping verification changes the security boundary and may temporarily hide a connection to the wrong server.
A Node List Is Not a Complete Subscription
proxy-providers keeps a node list in a separate source, which the main config references by provider name. This separates node updates from locally maintained rules. A provider generally expects content with a proxies structure; it can’t necessarily read any subscription text. Base64 text, a single URI and full Clash YAML have different formats. If they don’t match, convert the content or import it through the client. See Subscription Link Formats and How to Convert Them.
proxy-providers:
local-nodes:
type: file
path: ./providers/local-nodes.yaml
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 600
This provider uses a local file, not a subscription URL. Relative paths are usually resolved from the core’s working directory or a client-defined config directory, not necessarily the directory containing the file you’re editing. If the file can’t be found, check the startup options and final path in the logs, then confirm the file is readable. The file still needs to contain a node list; copying the whole main config won’t make the core extract nodes from any arbitrary level. Client-managed directories may also be restricted by app sandbox permissions.
Remote providers usually use type: http with a source URL, cache path and update interval. The URL may contain access credentials, so treat it as sensitive and keep it out of screenshots and public repositories. If an update fails, distinguish among a failed network request, authentication failure, non-YAML content and an unsupported protocol field. When a cache exists, the core may keep using old nodes; seeing nodes in the interface doesn’t prove the latest update succeeded.
Health Checks Don’t Guarantee Real-World Usability
A health check tests a node’s connectivity to a specified URL. The result depends on the test target, resolution path and server response. Passing only shows that this test path works; it doesn’t guarantee access to every website, UDP app or region-specific service. Provider checks and group checks also operate at different levels. Running frequent checks repeatedly adds requests. Use a clear test target and reasonable interval, verify one node first, then expand to automatic selection.
If a node looks complete but won’t connect, check the specific error during the handshake. A DNS failure points to an earlier network issue; a timeout may involve the address, port or firewall; an authentication error usually calls for checking credentials; a protocol parsing error points to the type or core compatibility. Don’t replace every field at once. Keep the original values, compare each option with the provider’s protocol details, then pin the outbound to a manual selection group for testing so automatic switching doesn’t hide the problem.
5. Proxy Groups: References and Selection
Proxy Groups Select Outbound Routes
proxy-groups organizes nodes, other groups and built-in policies into targets that rules can reference. A rule usually points to a stable group name, and the group selects the actual outbound. This means node updates don’t require rewriting every business rule. Group names are part of the config interface; if you rename one, update all its references. Duplicate names or circular references make the config difficult to understand and may prevent it from loading. Design the references as a one-way graph from rules to groups to nodes.
proxy-groups:
- name: Proxy
type: select
proxies:
- Auto
- DIRECT
use:
- local-nodes
- name: Auto
type: url-test
use:
- local-nodes
url: https://www.gstatic.com/generate_204
interval: 600
tolerance: 50
This example depends on the local-nodes provider defined in the previous section. proxies explicitly lists candidate names; use imports nodes from a provider. These aren’t interchangeable. Proxy is a manual selection group and can select an automatic group, a direct route or a provider node. Auto must not reference Proxy, or the groups form a loop. Keep the provider definition when combining examples; copying the group on its own leaves an undefined reference.
Manual Selection, Automatic Testing and Failover
select lets users choose a candidate explicitly, making it useful for testing one outbound or fixing a policy. url-test selects a candidate based on test results, which suits setups that should automatically maintain an available outbound. fallback prefers available candidates in order, making it useful when there’s a clear primary and backup. These aren’t progressively more advanced modes. Choose based on whether the service can tolerate switching, whether the outbound must stay stable and whether the extra test connections are acceptable.
| Type | How it selects | Best for |
|---|---|---|
select | User selects manually | Fixed outbound and testing candidates one by one |
url-test | Test results and switching tolerance | Automatically maintaining candidate outbounds |
fallback | Order and availability | Use a primary first, then a backup if it fails |
load-balance | Traffic distribution policy | Distributing connections across outbounds |
In an automatic group, interval sets the check interval, while tolerance reduces frequent switching caused by small differences in test results. It is not a latency target or a speed boost. A node that responds faster to the test URL won’t necessarily be faster for downloads or video services. load-balance distributes connections; it doesn’t combine multiple nodes’ bandwidth for a typical single download. Different connections may also use different outbounds, changing session behavior on the service side.
Filtering Candidates and Checking Selection State
Large providers can use filters to narrow the candidate list, but check that the filter still returns results. Regular-expression metacharacters interact with YAML quoting rules; when using a node name as a regex, parentheses, plus signs and square brackets may need escaping. Preview the candidate list in the client before sending traffic through the group. Don’t assume subscription names will stay the same: a rename can invalidate existing filters.
A client or mechanisms such as profile.store-selected may save the selection in a manual group. If the previous selection remains after reloading the file, that doesn’t necessarily mean the config failed to load; the client may have restored the previous runtime state. If a new candidate appears but the interface doesn’t switch to it, check the group’s actual selection first. Conversely, after removing the selected node, the core or client may choose another available candidate. Don’t infer the final outbound from the first item in the list.
When troubleshooting groups, first identify which group a rule matched. Then expand that group’s current selection layer by layer until you reach a node or built-in policy. If you see only a group name in the log and don’t follow its references, you may mistake a node problem for a rule problem. Keep a clear manual test path and avoid nesting several automatic groups. To compare clients by operating system, see the client selection guide; different interfaces display groups differently, but the underlying references are the same.
6. Rule Syntax: Match Types, Order and Rule Sets
Rules Are Evaluated Top to Bottom; First Match Wins
rules is an ordered sequence. The core checks connections in order and applies the policy for the first matching rule; it doesn’t continue looking for a later rule that seems more specific. Put exceptions for specific services before broad rules, and leave the catch-all rule at the end. Rule order is runtime logic, not a matter of formatting. Moving a broad match to the top can make many later entries ineffective.
rules:
- DOMAIN,api.example.com,DIRECT
- DOMAIN-SUFFIX,github.com,Proxy
- DOMAIN-KEYWORD,example,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- GEOIP,CN,DIRECT
- MATCH,Proxy
A rule usually consists of a type, a match value and a policy, separated by English commas. MATCH needs no match value; it specifies the final policy directly. A policy can be the built-in DIRECT or REJECT, or the name of an existing group or node. Don’t replace English commas with full-width Chinese commas or add explanatory text to a policy name. In this example, Proxy must exactly match the group name; otherwise, the rule may look valid but its reference won’t resolve.
Domain Rules vs. IP Rules
DOMAIN matches an exact domain, DOMAIN-SUFFIX matches the domain and its subdomains, and DOMAIN-KEYWORD matches a keyword appearing in the domain. Suffix matching is easier to control than using keywords indiscriminately. Enter a hostname, not a full URL with a scheme, path and query string. Standard domain rules can’t target a specific page path on the same site because proxy routing may not see the request path inside an encrypted connection.
IP-CIDR matches a destination IPv4 network; for IPv6 networks, use the corresponding IP-CIDR6 rule. The optional no-resolve means not to trigger domain resolution just to check this IP rule. It doesn’t force the entire connection to never resolve a domain. If the connection already has a usable destination address, it can still be matched by IP. This option avoids unnecessary lookups, but a connection known only by domain may skip the network rule, so interpret it in the context of actual traffic.
GEOIP uses an IP address database; GEOSITE uses domain classification data. These rules reflect database classifications, not permanent properties of a service. A domain on a cross-region CDN may resolve to an address whose location doesn’t match the service’s region. If traffic takes an unexpected route, first check whether a domain or IP rule matched, then confirm the data files exist and updated successfully. Don’t start by replacing every node or disabling DNS.
Rule Providers and behavior
rule-providers stores rule content in external files, which RULE-SET then adds to the main rule chain. The provider’s behavior determines the content format: domain stores domain matches, ipcidr stores network ranges, and classical stores entries with rule types. You can’t switch formats by changing one field alone; the file contents must match too. Whether the source is plain text or YAML must also match the format setting.
rule-providers:
local-direct:
type: file
behavior: classical
format: yaml
path: ./rules/local-direct.yaml
rules:
- RULE-SET,local-direct,DIRECT
- MATCH,Proxy
# ./rules/local-direct.yaml
payload:
- DOMAIN-SUFFIX,example.com
- IP-CIDR,192.168.0.0/16,no-resolve
Rule sets generally don’t specify the final policy internally; the main config assigns one in RULE-SET. In the example, the full set of entries is sent to DIRECT, leaving outbound selection under the control of the main rule chain. If a remote rule update fails, the cache may still work, so “still matches” doesn’t mean “successfully updated.” To validate a rule, choose a specific destination, close old connections, reconnect and check the matched entry, policy group and final outbound. Existing long-lived connections won’t automatically restart under the new rule order.
7. TUN: Virtual Interfaces, Routing and DNS Capture
TUN Captures Traffic; It Doesn’t Replace Rules
TUN uses a virtual network interface and routing to send traffic that doesn’t use the system proxy into the core. It operates at a different layer from mode: TUN controls how traffic gets in; rules control what happens after it arrives. Even with TUN enabled, routing exclusions, interface selection or permission issues may leave some traffic uncaptured. Don’t judge capture by the toggle alone; check whether the target app appears in the core’s connection log.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
enable turns on the virtual interface, stack specifies the network stack, auto-route requests automatic route configuration, and auto-detect-interface detects the outbound interface. mixed is a stack option supported by mihomo, but it isn’t necessarily the best choice on every operating system. The availability and behavior of other stacks depend on the core and platform. When troubleshooting, change one stack option at a time and compare logs so you don’t mix up stack and routing changes.
DNS Hijacking vs. Encrypted DNS
In dns-hijack, any:53 captures queries on this path that target the standard DNS port and passes them to the core’s DNS handler. It is not a general-purpose encrypted DNS interceptor. A DNS query sent over HTTPS looks like ordinary encrypted traffic; this rule won’t automatically convert it just because its destination is not port 53. If the browser has its own resolver enabled, confirm the query’s actual path before repeatedly changing the core’s upstream settings.
TUN and the DNS module usually need to work together, but they have separate switches. If the DNS module is disabled, has a listening conflict or can’t reach its upstream, traffic may be captured but fail to resolve. Conversely, a successful DNS response doesn’t prove that business traffic is routed correctly. Test connectivity to a known IP and access to a domain separately to distinguish connection failures from resolution failures, then check the policy, outbound and routes.
Platform Permissions and Route Conflicts
Desktop systems typically require administrator privileges, a privileged service or system authorization to create an interface and adjust routes. A client may manage these capabilities for you; editing YAML can’t replace the system authorization process. Android clients generally use VpnService to capture traffic, which is not exactly the same as a desktop virtual network interface. iOS clients use their own supported network extension mechanisms. Don’t copy desktop fields one by one into a mobile app’s interface.
| Symptom | Check first | Next step |
|---|---|---|
| Virtual interface creation fails | System authorization and service status | Check core startup errors |
| Domains fail, but IP addresses are reachable | DNS module and query path | Check resolution logs |
| Corporate network is unreachable | Internal routes and other VPNs | Check network exclusions |
| Connection problems after sleep | Interface changes and stale connections | Redetect the outbound and test again |
Corporate VPNs, virtual machine networks, container bridges and other proxy tools may all change routes at the same time. If automatic detection selects the wrong interface, traffic may bypass the core or loop back through it. First quit other traffic-capture tools and record the current routes, then test with just one client enabled. If you need them to run together, decide which subnets go through the corporate VPN and which traffic goes through the proxy core. Don’t rely on repeated restarts; the issue will return if interface order changes.
Stricter routing constraints can change LAN access, hotspot sharing and the behavior of other VPNs. Don’t treat these options as universal fixes. Start with a minimal working TUN config, then add exclusions or platform-specific options to address confirmed issues. After waking from sleep or switching networks, check that the system proxy and virtual interface returned to the expected state. For setup steps, see How TUN Works and How to Capture Traffic. If Android stops the app in the background, see VpnService and Battery Optimization Exemptions; the cause may not be YAML.
8. Overrides, Merging and Runtime Validation
Identify the Config Source Before Defining Merge Behavior
An override is a process in which a client replaces, supplements or reorganizes some fields while loading a subscription or local config. YAML itself doesn’t provide a universal override feature, and there is no merge order shared by every Clash client. The same option name in different clients may mean a shallow replacement, recursive merge or script processing. Before editing, read the client’s override documentation and confirm whether the entry applies to the current config or all configs, and whether it runs again after subscription updates.
Treat mappings and sequences separately. Recursively merging a DNS object may preserve upstream fields you didn’t change; replacing the whole object deletes its other settings. Replacing the rules sequence loses subscription rules, while appending to it may leave your rules unreachable if an existing MATCH already catches everything first. Node and group lists also contain name references; concatenating two files doesn’t guarantee a valid result.
# DNS object in the original config
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- https://dns.alidns.com/dns-query
# Fields to add through a client override
# This is a separate input; don’t append it as a second dns key.
# dns:
# ipv6: false
The intended result above is to add ipv6: false to the existing DNS object, not to remove its existing enabled state, resolution mode or upstreams. Whether this merge works depends on the client. After saving, open the runtime preview and confirm all four fields are present. If the client only supports whole-section replacement, explicitly include every field you need to keep in the override rather than relying on implicit behavior to keep the network working.
Subscription Updates and Where Local Changes Belong
Direct edits to a cached subscription file are often overwritten at the next update. A more reliable approach is to put personal rules, DNS preferences and port settings in a persistent override supported by the client, or maintain a separate local config and reference remote nodes through a provider. Each approach has trade-offs: the first depends on the client’s merge behavior; the second means managing groups and rules yourself. Before choosing, decide which fields are maintained by the subscription and which are maintained locally.
Treat node and group names as an interface referenced across sections. Build the final nodes and groups first, then check every rule target. Before deleting an object, search for other groups that reference it. Subscription converters may also rebuild names, rules and groups, so the converted text is a different structure from the original. For sensitive subscription URLs, prefer a trusted local conversion method and remove credentials from URLs before sharing a config.
Syntax Checks, Loading and Connection Retests
If you have a command-line core, use its test option to check whether the current binary can read the config. Use the same core and relevant data directories as the client; passing with a different executable doesn’t prove the GUI client’s core supports those fields. If the config uses provider files or geodata, make sure the test environment can access those dependencies too. A successful test can reveal config issues, but it doesn’t replace testing a real network connection.
mihomo -t -f ./config.yaml
Validate in four steps: save a backup and run a syntax test, reload the config in the client, check the logs to confirm the new config was accepted, then close old connections and test a destination. The runtime file shows whether fields were kept; connection records show whether the rule and outbound match expectations. If saving doesn’t trigger a reload, or you aren’t editing the active config, the network behavior won’t change.
Keep a change log: note which fields you changed, the expected and actual results, and how to roll back. Work on one layer at a time and move on only after it checks out. Enable detailed logs only while troubleshooting, and remove subscription credentials, server authentication details and unnecessary access records before sharing them. If the client itself seems misconfigured, return to the user guide to review import, mode and connection steps. To switch clients, visit the client downloads page and choose one for your platform rather than assuming every issue means the config file is corrupt.