Configuration reference

Clash Advanced Configuration Guide

Configuration boundaries for proxy groups, rulesets, DNS, and traffic routing.

This guide is for users who have imported a profile and can establish a basic connection. For installation and connection checks, start with the Getting Started guide. The sections here explain how configuration settings reference one another, how to validate changes, and how to roll them back—making this a practical reference when editing your config.

Proxy group types and egress design

Proxy groups sit between rules and nodes. Rules determine what kind of traffic a connection belongs to; proxy groups decide which outbound route that traffic uses. Referencing node names directly in many rules means that renaming nodes or updating a subscription can affect the entire config. Define stable, purpose-based group names first, then manage nodes within those groups. This separates routine node changes from rule maintenance and makes it easier to trace decisions in connection logs.

When to use manual and automatic selection

select is useful when you need to choose an outbound route manually—for example, for work services, region-specific content, or temporary troubleshooting. Members can be nodes or other proxy groups. A straightforward setup is to keep a manual selection group on the outside and an automatic testing group inside it. You then choose between automatic selection and direct connection without assigning a node to every domain rule.

url-test checks group members against a specified test URL and selects from nodes with similar purposes. The result only reflects connectivity to that test destination; it does not predict performance for every service. Choose a stable URL that permits testing and resembles your actual use case. Relying on a destination that fails intermittently can cause unnecessary switching.

fallback checks candidates in order and uses an available route, making it suitable for a primary connection with a backup. load-balance distributes connections according to a policy; it does not combine multiple routes into a single connection. For services sensitive to login state, source IP, or a consistent region, use a fixed outbound route first. Consider distributing connections only after confirming the service allows the outbound route to change.

proxy-groups:
  - name: PROXY
    type: select
    proxies:
      - DIRECT

rules:
  - DOMAIN-SUFFIX,github.com,PROXY
  - MATCH,DIRECT

This example only demonstrates the relationship between group names and rule references. PROXY contains only DIRECT, so traffic still connects directly. For actual use, add existing nodes or other proxy groups in your client. Names must match the current config exactly. A group named “proxy” does not necessarily use a remote route—expand its members to confirm the final selection.

Automatic testing settings and proxy providers

When using proxy providers, a proxy group references the key in proxy-providers with use—not the filename. Provider health checks and automatic group selection serve different purposes: the former tracks node availability, while the latter informs group decisions. Frequent checks in both places create redundant requests. Start with longer intervals and adjust them to match your recovery needs.

interval sets the test interval in seconds. tolerance helps prevent frequent switching due to small differences. It is neither a minimum-speed guarantee nor a connection timeout. Automatic selection mainly affects new connections; existing downloads, calls, and long-lived connections may not move immediately. To verify a change, close the test connection and make a new request.

TypeHow it decidesBest suited for
selectManually select a memberFixed outbound route and troubleshooting comparisons
url-testSelect based on test resultsCandidate nodes with similar purposes
fallbackSelect the first available memberPrimary and backup routes
load-balanceDistribute connections by policyServices that allow the outbound route to change

Check references and verify switching

Groups can be nested, but they must not form a cycle. For example, if a service group references an automatic group that then references the service group, there is no way to determine the final route. List the group names before making changes, then check each member in turn. The same node can appear in multiple groups; the issues to avoid are duplicate group names, references to names that do not exist, and indirect references back to the group itself through nested groups.

To verify routing, check the matched rule, proxy chain, and final node in the connection log. If the rule is correct but the route is wrong, first check the selection saved in the outer group, then the status of the inner automatic group. If a group is empty, check whether its provider loaded and whether a filter excluded every node. Don’t start by changing DNS; that would conflate routing and name-resolution issues.

A subscription update can remove nodes, but stable service group names should remain. You can create a dedicated group for important services so they do not follow changes in a general-purpose group. A documented, tested setup is easier to maintain than ever-deeper nesting. For ways to add nodes from multiple subscriptions, see Local overrides and merging multiple subscriptions.

Managing subscribed rulesets and match order

Rulesets move frequently updated domains or IP ranges out of the main config. rule-providers loads them, and RULE-SET adds them to the rule chain. This leaves the main config responsible for categories and outbound routes. A ruleset is not a node subscription and does not create proxy groups. Even when a ruleset loads successfully, it has no effect on connections until a rule references it.

Choose the behavior and file format first

behavior describes the meaning of the rules. domain contains a set of domains, ipcidr contains IP ranges, and classical contains typed rule entries. format describes how the file is encoded; the two settings are not interchangeable. A downloaded text file does not tell you which behavior to choose—inspect its contents and identify the entries it actually contains.

This example uses a local classical ruleset so you can check the structure without remote updates as a variable. Save the second block as rules/work.yaml in the main config directory, confirm the directory is readable, then load the first block. Define PROXY in a proxy group first. A ruleset stores matching conditions; it does not append an outbound route to every entry.

rule-providers:
  work:
    type: file
    behavior: classical
    format: yaml
    path: ./rules/work.yaml

rules:
  - RULE-SET,work,PROXY
  - GEOIP,CN,DIRECT
  - MATCH,PROXY
payload:
  - DOMAIN-SUFFIX,github.com
  - DOMAIN-SUFFIX,githubusercontent.com

A classical ruleset retains type prefixes such as DOMAIN-SUFFIX. Domain-only lists have different entry semantics, so you cannot reuse the file above by changing only behavior. If you use a binary rules format, confirm that the current kernel supports it. When loading fails, first check that the file contents match the declared behavior and format, rather than repeatedly changing the cache path.

What remote updates and caching do

For a remote rules provider, set type: http, enter the actual rules URL, and configure an update interval and a dedicated cache path. The interval is also measured in seconds. The URL must return rules in the declared format. A web page, login screen, or error message is not a successful update; a successful connection does not guarantee that the response was parsed.

Caching can let the client keep using existing rules when a remote file is temporarily unavailable, but startup still depends on whether a cache exists and whether the kernel can load it. On first use, check the logs to confirm that both downloading and parsing have completed. Give each provider a separate cache file. Sharing one can let an update overwrite another ruleset, causing the subtle problem of correct category names with the wrong contents.

Remote rules are part of your configuration’s trust boundary. A ruleset maintainer can change domain classifications and thereby change outbound routes. Before adding a provider, understand its purpose, update process, and coverage. Test it locally before using it in your main config. For a small number of services that need predictable routing, use precise rules in the main config rather than relying entirely on broad remote lists.

Order rules by priority

Standard rules are checked in order, and the first match determines the outbound route. Put local exceptions before general rulesets, broader IP range rules later, and MATCH last as a catch-all. If the catch-all comes first, later rules never get a chance to match. A broad reject rule placed before a service exception can also mask it; changing proxy groups cannot fix an ordering error.

Some IP-based rules need a domain to be resolved. Certain IP rules support no-resolve to avoid triggering an additional lookup for that rule, but this does not make the connection bypass DNS altogether. Whether to use it depends on the rule’s purpose: consider it when you want to match a known destination address, but use caution if you need to resolve the domain before checking its IP range. Otherwise, you may change which traffic matches.

When traffic is routed incorrectly, note the destination domain and the rule that actually matched, then identify the relevant provider. Temporarily add an exact domain rule at the top to help determine whether the issue is rule order or the outbound route itself. Remove the test rule afterward, keeping only documented exceptions. This prevents the config from accumulating overlapping rules that mask one another.

If you have many rules, organize them by purpose—such as work services, media services, and local networks—instead of piling them up by source. Update one category at a time and check connection logs to identify what changed. For how configuration fields reference one another, see A breakdown of top-level config.yaml fields. For general connection troubleshooting, see the FAQ.

Optimizing DNS settings and resolution paths

DNS is about more than getting an IP address: the domain, resolved address, and outbound route need to work together. The same domain can resolve differently through different DNS services, and the network used by a proxy route can affect whether the destination is reachable. Before optimizing, check whether the app’s queries reach the client’s DNS, identify the route used for DNS requests, and only then compare DNS providers. Simply replacing the server list is not enough.

Separate the listener, upstreams, and bootstrap DNS

listen sets the address where the client’s DNS service listens; nameserver sets the upstreams used for general domain queries. They serve different purposes. A loopback listener is available only to the local device, and adding it to the config does not make the operating system use it. System DNS settings, TUN DNS interception, or a corresponding client feature must also route queries to that listening port.

default-nameserver is primarily used to resolve the hostnames of DNS upstreams, so choose an explicit address that is directly reachable. An encrypted upstream specified by hostname needs this bootstrap step. If bootstrap resolution depends on a proxy that has not yet started, the config can enter a startup loop: both node hostnames and DNS service hostnames may fail to resolve.

dns:
  enable: true
  listen: 127.0.0.1:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
  nameserver:
    - 223.5.5.5
    - 1.1.1.1
  fake-ip-filter:
    - "*.lan"
    - "*.local"

This example shows where the fields go. Choose the public DNS addresses based on what is reachable from your current network. The config does not automatically forward system queries to 1053, nor does it guarantee that every app will use this service. After setup, query the port directly to confirm the listener works, then verify the system and app resolution paths. This helps distinguish a system integration issue from an upstream failure.

Handle node hostnames separately from service domains

Service domains can ultimately be accessed through a proxy, but proxy node hostnames usually need to resolve before the proxy is available. Kernels that support it can use proxy-server-nameserver to configure a separate resolver for node hostnames. Before changing this setting, confirm that its upstream is directly reachable. If the node address cannot be resolved, failed proxy group tests do not prove that the remote service is unavailable.

nameserver-policy selects DNS servers for specific domains. It is useful for internal domains, split DNS, or services with specific regional requirements. Internal company domains need a resolver that can reach the internal zone; public DNS services usually have no record of those domains. Keep policies narrowly scoped: test one suffix before expanding coverage to avoid sending ordinary domains to an internal-only server.

respect-rules makes DNS upstream connections use the routing rules to select an outbound route. If you enable it, also account for how node hostnames are resolved; otherwise, DNS may depend on the proxy while the proxy depends on the same DNS path. This is not a universal speed boost. Unless you have a specific need to control DNS egress, keep the setup simple until basic connectivity is stable.

Test each layer; don’t rely on how a website feels

Apps may keep their own DNS cache or use encrypted DNS. A browser’s built-in resolver can bypass system settings, and an existing connection may not perform another lookup at all. After changing the config, check client queries, system queries, and new app connections separately, clearing the relevant cache if needed. Refreshing a page without closing its existing connection is not a reliable way to confirm that the new settings took effect.

On systems with dig, use the command below to query the example listening port directly. A Fake-IP response means the query reached the corresponding mapping mechanism; it does not mean the destination server uses that address. If the command times out, check the listening address and port availability first. If it returns an answer but the app still fails, check system integration, routing, and rule matches rather than immediately replacing every upstream.

dig @127.0.0.1 -p 1053 example.com A

If ordinary domains work but internal domains fail, check the search domain, internal DNS server, and VPN routes. If all domains fail but direct IP connections work, focus on DNS interception and the upstream path. If a domain resolves but the connection times out, check the routing chain and destination reachability. Successful DNS resolution does not guarantee that the connection uses the expected route.

Adding more upstreams is not a general-purpose optimization. More servers expand the privacy and failure surface and can make results harder to troubleshoot when answers differ. Start with a small number of reliable upstreams and document any special domain policies and why you chose them. The next section explains how DNS relates to Fake-IP, including address mapping, cache expiration, and addresses retained by apps.

TUN and Fake-IP: traffic interception boundaries

TUN is a virtual network interface that receives IP packets routed to it by the operating system. Fake-IP is an address-mapping mechanism at the DNS layer. They are often used together, but they are not the same feature. System proxy settings mainly serve apps that honor them; TUN can cover more network traffic. Enable it based on which apps you need to route, rather than treating it as the default fix for every connection problem.

Set up interception so you can roll it back

Before enabling TUN, confirm that nodes, subscriptions, and proxy groups work with a standard proxy setup. Then check whether the client needs a service installed or administrator privileges. Desktop systems typically require permission to create a virtual interface and routes; mobile systems usually require authorization through the system VPN interface. Turning on a UI switch does not confirm that traffic is being intercepted. Check the logs for successful interface creation, route installation, and DNS interception.

The fields below cover common basics. auto-route configures routes automatically, auto-detect-interface identifies the outbound interface, and dns-hijack sets the DNS interception targets. Support and behavior depend on the system and kernel. Start with your client’s default TUN settings, then check the final config. Avoid setting conflicting values in both the UI and an override.

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

stack selects the network stack implementation; its name alone does not tell you how well it will perform. Support, protocol handling, and resource use vary by system. If a particular app misbehaves, keep the other settings unchanged and compare only the network stacks supported by your client. Note the system environment, and avoid changing routes, DNS, and MTU at the same time.

How Fake-IP domain mapping works

In Fake-IP mode, DNS returns a mapped address to the app. The client uses that address to recover the domain on subsequent connections and apply routing rules. The address range in the example is used by this mechanism; it is not the destination website’s real address. Fake-IP can make domain-based routing easier than relying on destination IPs alone, but the DNS query and subsequent connection must use the same mapping environment. If that link breaks, the connection can fail.

An app that caches an address for a long time, resumes a connection after sleep, or switches client instances may keep a stale mapping. Re-resolve the domain and establish a new connection first; clear the app or system cache if needed. Don’t put an old Fake-IP address in your hosts file or service config, or share it with another device as a server address. Outside the corresponding mapping table, the address no longer identifies the expected domain.

fake-ip-filter prevents specified domains from receiving fake addresses. It is useful for some local network discovery, internal services, or compatibility cases that require real address semantics. This filter is not a direct-connection rule: after receiving a real address, traffic still follows the routing rules. Add entries only for verified issues rather than using broad patterns that disable the mechanism altogether.

EnvironmentWhat to checkCommon sources of conflict
Desktop systemsService permissions, virtual interfaces, default routesOther VPNs and virtual machine networks
Mobile systemsVPN permission and background statusApps competing for the VPN interface
Devices with multiple network adaptersActual egress route and interface detectionCompeting routes over Ethernet, Wi-Fi, and tunnels

Route conflicts and local network access

Corporate VPNs, container networks, virtual machines, and other proxy tools can all change routes. If internal resources become unreachable after TUN starts, compare the routes for the affected subnets and check whether you need to exclude them or preserve the existing path. Don’t delete every route to restore connectivity; that could cut off your management connection. Always have another recovery option when managing a remote device.

Enabling “Allow LAN” and enabling TUN are separate actions. The former usually controls whether other devices can connect to the proxy listener; the latter routes traffic from the local device. To provide a proxy to other devices, also check the listening address, firewall, and authentication settings. Enabling TUN on one device does not automatically route traffic from the entire local network through the client.

If all connectivity is lost after interception starts, check recovery in this order: TUN, system DNS, then system proxy. Confirm whether the client removes its interfaces and routes when it exits. Restore basic network access before testing one interception method at a time. For installers and platform options, see the Download page and choose Clash Plus first. Check the client’s actual settings to confirm support for specific features.

Domain sniffing and rule matching

Domain sniffing tries to identify hostnames from protocol data early in a connection, adding information that is missing when only the destination IP is available. It complements DNS domain mapping but cannot replace a complete DNS and routing setup. Before enabling it, confirm that a missing domain is actually the problem. If the connection log already shows the correct domain and matched rule, more sniffing is unlikely to fix an outbound routing issue.

What it can identify—and its limits

HTTP requests may include a Host header; TLS handshakes may include a server name; some QUIC handshakes may also provide clues. Whether this information is available depends on the protocol, handshake, and kernel support. Sniffing does not decrypt HTTPS traffic or expose the full encrypted request. If the hostname is protected or the protocol is unsupported, the client cannot recover the domain out of thin air.

Some apps connect directly to a fixed IP or use their own DNS resolution, so their connections never pass through the client’s DNS. In such cases, sniffing may give domain rules another chance to match. However, one IP can host multiple services, and the hostname in an app’s handshake may differ from the address entered in its UI. Check the connection log to confirm the result instead of relying only on whether the site loads.

sniffer:
  enable: true
  sniff:
    HTTP:
      ports:
        - 80
        - 8080-8880
      override-destination: false
    TLS:
      ports:
        - 443
      override-destination: false
  skip-domain:
    - "*.lan"
    - "*.local"

The example covers common HTTP and TLS ports and disables destination overrides, making it useful for observing detection results. It does not cover every custom port or enable QUIC sniffing. If a service uses another port, confirm its protocol before expanding the scope. A port is only a filter, not proof of the protocol. Forcing every parser to run on arbitrary ports can cause unnecessary interference.

Verify domain detection separately from destination overrides

override-destination controls whether the connection target is replaced with the detected domain. With it disabled, you can first observe domain detection and rule matching. Enabling it may change how the destination is resolved and connected to. Test these behaviors separately: confirm that detection is reliable before deciding whether to change the target. Otherwise, if something breaks, it will be harder to tell which step caused it.

Fixed-IP access, internal reverse proxies, and some apps with strict destination requirements may not work well with destination overrides. A connection intended for a specific server could be redirected to another server when the detected hostname is resolved again. If login fails or the service response changes, compare the original address, detected domain, and final connection target—not just whether the expected proxy group was selected.

skip-domain excludes domains from sniffing. Start with known internal services and specific compatibility exceptions; don’t copy long exclusion lists without understanding their purpose. An overly broad exclusion can leave the original missing-domain issue unresolved, while a narrow one may introduce changes to internal connections that don’t need them. Verify each entry individually.

Troubleshooting DNS and encrypted app-level resolution

A browser’s encrypted DNS may hide regular queries from the client, but sniffing is not guaranteed to recover the domain. If the hostname is also hidden during the handshake, the client has only the IP and other limited information to work with. Choose a clear approach: make the app use a resolution path the client can intercept, or accept the limitations of IP-based rules. Repeatedly adding sniffing ports that cannot help will not solve the issue.

Choose a service with a fixed domain and connections that are easy to recreate. First record the result with sniffing off. Then enable detection without overriding the target, and try an override only if needed. Close old connections after each change, keep the proxy group selection fixed, and check both the detected domain and final route. This separates domain detection, rule matching, and target changes so they are less likely to mask one another.

If only UDP services fail, separately check whether the node supports the required transport, whether TUN intercepts it, and whether the protocol is in the sniffing scope. A browser may fall back to TCP when QUIC fails, so a page loading does not prove both paths work. Don’t block all UDP traffic to prove that your rules are correct; doing so changes app behavior and can hide the original problem.

Keep sniffing narrowly scoped and tied to a clear purpose. Once DNS mapping is stable, enable sniffing only for protocols that need it and document why. If you cannot reproduce an improvement, a simpler config is easier to maintain. For rule modes, connection logs, and common issues, check the FAQ alongside this guide rather than expecting sniffing to handle all routing decisions.

Local overrides and merging multiple subscriptions

Subscriptions provide remote content; local overrides handle device-specific and personal needs. Keep them separate. Direct edits to a downloaded subscription can be overwritten by the next update, while relying on a subscription for every setting can cause ports, DNS, or traffic interception to change remotely. A stable setup makes clear which fields are maintained remotely and which are controlled locally.

Check how your client merges configuration

Clients may offer config merging, override files, rule patches, or script-based processing. Similar names do not guarantee similar behavior. Array fields are especially important: some implementations replace the entire list, while others append or prepend entries. Before using a feature, understand when it runs and what it applies to. Don’t treat a patch format for one client as general mihomo YAML, or enable two overrides without knowing their execution order.

Start by testing a low-risk field, such as the log level, then check the final config to see whether it changed. Next, test prepending rules and replacing lists. A successful save in the UI only confirms that the input was accepted; it does not prove that the final result was merged as intended. Check the effective config passed to the kernel and confirm that the kernel accepted and loaded the fields.

Keep local settings in two layers: device settings and service settings. Store ports, DNS, TUN, and controller settings in the device layer; keep stable group names, rule order, and local exceptions in the service layer. This lets you change network settings when moving to another device without rewriting all your service rules. If overrides use scripts, review what they do first—they may rebuild the entire config.

For multiple subscriptions, use separate proxy providers

When merging two full subscriptions, the common issues are not with the nodes themselves but with duplicate proxy group names, repeated rules, and incompatible DNS settings. If you only need nodes from both sources, a clearer approach is to give each source its own node file and organize the proxy groups in a local config. The example below shows the structure for local files. Each file must include a proxies list that a proxy provider can read.

proxy-providers:
  access-a:
    type: file
    path: ./providers/access-a.yaml
  access-b:
    type: file
    path: ./providers/access-b.yaml

proxy-groups:
  - name: PROXY
    type: select
    use:
      - access-a
      - access-b
    proxies:
      - DIRECT

A full subscription usually includes proxy groups and rules as well, so renaming the file does not make it a valid node provider. Confirm that its structure works with the provider and the way it is loaded, or use a conversion feature explicitly supported by your client. For remote providers, enter the actual subscription URL and use separate cache paths. Subscription URLs may contain access credentials; don’t include them in public documents or troubleshooting screenshots.

Avoid name conflicts and preserve rule order

Two sources may use the same node names, making options hard to distinguish or references ambiguous. Prefer adding a stable source prefix during import or preprocessing, after confirming which renaming methods your client supports. Don’t infer a node’s region or purpose from its display name alone. Source labels distinguish where it is maintained; verify actual reachability with a connection test.

Merging rules must preserve their order. Put precise personal exceptions first, general subscription categories in the middle, and a single catch-all at the end. Simply concatenating two rule arrays can let the first MATCH mask every entry in the second. If the client appends rules by default, check whether it can prepend them. Seeing an entry in the config does not prove it is effective.

Check that proxy group references still form a valid chain after merging. Keeping two service groups with the same name or renaming a group without updating its rule destinations can cause load errors or unexpected selections. A minimal validation order is: load the providers, create unified proxy groups, then add the rules. Check the logs at each step so provider loading errors and rule reference errors do not reach the final config together.

Backups, updates, and rollback

At a minimum, back up local overrides, the main config, rules files, and notes on how providers are organized. Store sensitive subscription URLs separately. Client screenshots alone are not enough to restore references; backing up only the effective config after an update may lose the original override logic. Before a major change, keep a working version and notes so you know which layers to restore if you need to roll back.

When testing a subscription update, check that local exceptions remain, rule order is unchanged, and the current selection does not point to a removed node. If something breaks, disable the latest patch and load a backup instead of repeatedly patching a broken config. For the difference between switching profiles and updating subscriptions, see Notes on managing multiple configurations. For the basic import process, start with the Getting Started guide.

External controllers and configuration validation

An external controller lets you view runtime status, switch proxy groups, and perform some management tasks. A control panel is its visual interface; it does not provide proxy routes or replace the kernel. A panel connection failure is separate from a proxy connection failure: traffic may still be forwarded normally even if the management interface is not listening, authentication fails, or the browser blocks the request for security reasons.

Local listening and local panel files

For local management only, bind external-controller to a loopback address. external-ui points to a local panel resource directory, which must contain the actual static files. Specifying a directory name does not create a panel. The example below shows the listener and resource path. Before enabling the controller, set an authentication key locally; don’t reuse a key from a public example as a long-term credential.

external-controller: 127.0.0.1:9090
external-ui: ./ui

The top-level secret field is used for authentication. Use a separate, long random string and configure the panel to use the same value. This key authenticates the controller; it is not a node password or subscription URL, and the three should not be reused interchangeably. Sharing the key in a public screenshot, link, or config also exposes management access. Remove sensitive details before troubleshooting.

Binding to all interfaces can allow other devices on the network to reach the management interface. Don’t open it just for convenience. For remote management, protect the connection with a controlled network, access restrictions, and an appropriate encrypted channel, and check the system firewall. Authentication alone does not replace network isolation. Treat the controller as an administrative interface that can change runtime behavior.

Check network access, authentication, and browser restrictions separately

If the panel cannot connect, first confirm that the running kernel loaded the controller settings, then check the address and port. A loopback address points to the device running the browser. When you open the panel from another device, it does not point to the host running the kernel. Don’t widen the listener just to compensate for this misunderstanding; first decide whether you really need to manage the client remotely.

On a local system without authentication, the command below can check whether the controller responds. If you have set a key, send a request with the appropriate authentication; this is not a reason to remove it. A connection refused error usually means that nothing is listening or the address is wrong. An authentication error usually means the controller is reachable but the credentials do not match. Troubleshoot these separately; changing proxy nodes will not help.

curl --fail --silent --show-error http://127.0.0.1:9090/version

A remote HTTPS page requesting a local HTTP controller may be blocked by mixed-content, cross-origin, or local network access restrictions. A blank panel can also result from an incorrect static file path. Prefer a panel built into your client or a trusted local panel, and check the browser console for specific errors. Don’t treat allowing any origin as a universal fix or disable all browser protections to connect the panel.

Validate the config before and after loading

The first check is before loading: verify YAML indentation, field types, reference names, and file paths. If mihomo is available, run the test command in the example environment. When the config includes local providers, make sure their files are in place first. Testing can catch syntax errors and some reference issues, but it cannot prove that remote nodes are reachable, system permissions are in place, or every rule works as intended.

mihomo -t -f ./config.yaml

The second check is after loading. Start with the logs and confirm that the controller, providers, and rulesets all loaded successfully. Then make a repeatable test connection and check the domain, matched rule, proxy chain, and final route. Test both services that should connect directly and those that should use a proxy. A panel showing “running” is not a substitute for checking the full path from config to actual connection.

A temporary change in the panel may not be saved to the subscription or local override. For selections you want to keep, check how your client persists them; put lasting rules in a maintainable configuration layer. Don’t rely on runtime changes as your only backup. After a restart, update, or profile switch, panel changes may be lost, making the config seem to have changed on its own.

Change one troubleshooting variable at a time

Troubleshoot in this order: config parsing, file loading, DNS, outbound route, rules, and system-level interception. Change one layer at a time, record what happens, and then choose the next step. If the issue started after an update, restore the most recent working config to confirm the cause rather than enabling sniffing, changing the network stack, and rewriting DNS all at once. Fewer variables usually make problems easier to isolate.

If the app crashes on startup, save the error and stop repeated automatic restarts. Follow the log-based diagnosis and config rollback steps. If the app starts but a specific feature fails, consult the relevant section of this guide. After making changes, save the final config and a note explaining its purpose so you can repeat the same validation steps after a subscription update or device migration.