Configuration Reference / mihomo

Clash Advanced Configuration Guide

How proxy groups, rule providers, and traffic interception fit together.

This guide is for users who can already import a subscription and connect. It explains settings, constraints, and troubleshooting in the order they depend on each other. For your first install, subscription import, or mode selection, start with the Quick Start Guide. To switch clients, visit the client downloads page and check the Clash Plus download for your platform first.

Examples follow mihomo configuration semantics. Client UI labels, permission requests, and override mechanisms may differ. Each code sample illustrates one part of a configuration and must be merged into the corresponding section of your actual config; do not concatenate the samples into a single file.

Configuration files and precedence

Know the difference between subscription files, generated config, and runtime state

Clash clients often manage three distinct things: the subscription file downloaded from a remote source, the final config generated by the client, and the runtime state loaded by the core. If editing a subscription copy has no visible effect, the settings may be valid—the client may simply be using a different generated file. Before making changes, check which config is active, which core is in use, and where the client shows the final config. Note the current mode, ports, and selected proxy groups as a baseline.

A subscription may include proxies, proxy groups, rules, and DNS settings, or it may provide only a proxy list. The client may also add settings based on system proxy, TUN, and override options, so the original YAML on disk is not necessarily the effective config. Treat the remote content as input, local overrides as transformations, and the runtime config as the source to inspect. When something differs, compare each layer in turn. Changing all three at once makes it hard to know which changes will survive the next subscription update.

Use a minimal config to verify the basics

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

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

rules:
  - MATCH,Manual

This minimal example is for understanding the structure only: the mixed port accepts both HTTP and SOCKS proxy requests, rule mode routes connections according to the rules, and the final catch-all rule points to the Manual group. No proxy nodes are included, and the group contains only DIRECT, so it will not provide a proxy exit. For real use, keep your valid nodes or proxy collections and add them to the relevant groups. Do not remove subscription authentication, transport settings, or server-required parameters just to match the example.

YAML uses spaces for indentation, not tabs. Keep items at the same list level aligned, and quote names or passwords that contain special characters. Do not define top-level dns, rules, or proxy-groups more than once in the same document. Duplicate keys may be rejected by the parser or overwritten by the later value. After copying a sample, check indentation and references. Valid YAML syntax does not guarantee that proxy group references or rule behavior are correct.

Check syntax before a controlled reload

If you run the core directly, validate the config with mihomo -t -f config.yaml. If the client has not added the core to your command search path, use the actual path to its executable. Test from the same working directory as the runtime environment, since rule-provider caches and other relative paths depend on it. Syntax checks catch structural and reference errors, but they do not replace a real connectivity test or confirm that remote rule providers can be downloaded.

Before editing, save a complete config that you know works and note the client's override settings. Change one area at a time and reload only after it passes validation. For fields involving listen addresses, virtual interfaces, or routes, restart the core as instructed by the client. A successful reload does not mean existing connections have moved to the new route: connections may keep using their original exits. Reconnect the target app to test, and check the config-load logs rather than relying on the appearance of a toggle.

If the core will not start, restore the previous config first, then distinguish a parse error from a port conflict or insufficient permissions. For port conflicts, see how to troubleshoot a busy mixed port; for structure issues, see a section-by-section guide to Clash YAML. Restore a basic working connection before adding advanced settings; stacking fixes onto a broken config makes the cause harder to find.

Proxy group types and traffic routing

Rules choose the destination; proxy groups choose the exit

Rules send a connection to a proxy group, and the group selects the actual exit from its candidates. Candidates can be proxies, other proxy groups, or built-in options such as DIRECT and REJECT. Design these layers separately: create groups for purposes such as manual selection, automatic selection, or work services, then have rules reference those stable names. Keep node changes at the lower layer to avoid rewriting the entire ruleset every time a subscription updates.

With select, users choose a candidate in the UI. It works well as a general entry point or for services that need a fixed exit. It will not automatically switch to another candidate when the selected proxy becomes unavailable unless the selected item is itself an automatic group. For services that need a consistent login location or long-lived sessions, a fixed manual choice is often easier to reason about than frequent switching. A group name is both a UI label and a rule reference; if you rename it, update every rule and parent group that uses it.

Automatic selection, failover, and load balancing

TypeHow it selectsConfiguration focus
selectManual selectionClear entry point; good for a fixed exit
url-testSelects based on probe resultsUse a consistent test URL and set a tolerance
fallbackPrefers the first available candidateOrder candidates by preference
load-balanceDistributes connections according to policyConsider exit consistency and session requirements

url-test is useful for automatically choosing among similar proxies, but a probe only measures connectivity to its target—it does not represent performance across all websites. fallback prioritizes candidate order: it uses the first candidate that meets the availability conditions, making it suitable for a defined primary-and-backup setup. Both rely on probes. If the test site is unreachable, has certificate issues, or is blocked by the network, an otherwise usable candidate may be marked as failed. Verify the probe target separately when troubleshooting.

load-balance distributes separate connections; it does not split a single connection to combine bandwidth. With round-robin selection, different connections from the same service may use different exits. Consistent hashing also cannot guarantee that every related domain will use the same node. Put payment, login, and other source-IP-sensitive services in a dedicated fixed-exit group. Changing a policy usually does not move an established connection; reconnect to test the new selection.

proxy-groups:
  - name: Auto Select
    type: url-test
    use:
      - Main Proxies
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50

  - name: Proxy Entry
    type: select
    proxies:
      - Auto Select
      - DIRECT

rules:
  - DOMAIN-SUFFIX,github.com,Proxy Entry
  - MATCH,Proxy Entry

This example assumes a proxy collection named “Main Proxies” already exists; use refers to the collection name, not a subscription URL. You can use any probe URL that you have verified is reachable and responds consistently. The interval is in seconds; tolerance helps prevent needless switching over small differences, but does not guarantee real-world performance. With many proxies, keep probe frequency under control. Start with the default or a conservative interval, then adjust based on your device and network.

Check for empty groups, circular references, and rule matches

A proxy group may have no candidates because its collection has not loaded, a name is misspelled, or a regex filter matches no proxies. Temporarily remove the filter and inspect the candidates, then restore the expression. Groups can reference one another in layers, but must not form a cycle. For example, if a top-level group contains an automatic group that points back to the top-level group, exit resolution cannot finish. A one-way structure—“service group → selection group → proxy or collection”—is easier to inspect.

For testing, pin the group to a known working candidate, visit the target service, and confirm that the rule routes to the expected group before testing automatic selection. Otherwise, a failed connection could be caused by the rule, DNS, or the proxy itself, while the automatic group gets blamed. To compare client interfaces and core capabilities by platform, see client comparisons. Whether a group type can be edited directly in the UI depends on the client you use.

Manage rule providers with subscriptions

Maintain match data separately from routing policy

As domain and IP range lists grow, keeping every entry in the main config makes it harder to read and update. rule-providers stores match data separately, leaving the main config to define the sources and their order. A rule provider identifies targets in a category; a RULE-SET rule assigns that category to a policy. This lets you update the target list without changing proxy groups, or change the exit without rewriting the domain data.

Rules are evaluated from top to bottom, and the first match usually determines where a connection goes. Put exceptions for specific domains before broader rules, and keep MATCH as the final catch-all. The order in which rule providers are called matters just as much as their contents: a valid blocklist placed after the catch-all will never run. A broad DIRECT rule before a proxy rule can also capture connections too early. Before changing rules, establish the intended priority order.

Choose the right behavior and data format

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

rules:
  - DOMAIN-SUFFIX,github.com,Proxy Entry
  - RULE-SET,Internal Domains,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,Proxy Entry

The main config above references a local file and assumes a “Proxy Entry” group already exists. The corresponding rules/internal.yaml could look like the example below. It uses a reserved example domain rather than a real service; +.example.com matches the root domain and its subdomains. For deployment, replace it with the targets you need to manage and place the file where the core can access it. If the client restricts the config directory, use its import or rule-provider management interface.

payload:
  - '+.example.com'
  - '+.example.org'

Use behavior: domain for domain data, ipcidr for IP ranges, and classical for rule expressions of different types. Their data formats are not interchangeable: a domain list should not contain complete DOMAIN-SUFFIX rule lines. A provider using the classic rule format usually contains match conditions only; the RULE-SET that calls it specifies the policy. Do not copy the main rules list by appending the target policy to every provider entry.

The format field must also match the content. YAML providers typically use a payload list; text formats store data line by line according to their specification, while binary rule formats require the matching behavior and generation tool. A successful download only confirms that a response was received, not that its contents can be parsed. An error page, login page, or redirected HTML response may end up in the cache. When an update fails, check the parse logs, file header, and actual response—not just whether the network request completed.

Remote updates, caching, and startup dependencies

For a remote provider, set type: http, a trusted and valid download URL, a cache path, and an update interval. Give each provider its own cache file to prevent updates from overwriting one another. A startup dependency can occur if downloading a provider requires a proxy, but the proxy itself depends on rules that have not been downloaded yet. Set an available route for provider downloads or prepare a local cache first. Do not mask a dependency loop with endless retries; confirm that basic proxy connectivity works with a minimal ruleset.

For IP rules that should match only against an already available destination address, use no-resolve if appropriate to avoid an extra DNS lookup for that rule. The tradeoff is that connections with only a domain name and no resolved IP may skip it. This is not a general-purpose speed switch; it changes when matching happens. Check domain rules, DNS policy, and IP rules together. In Fake-IP mode, do not design IP-based routing as if a synthetic address were the real server address.

Regression tests should cover at least one target that should use a proxy, one that should connect directly, and one test target that should be blocked. Check the connection details for the rule type, provider name, and final policy instead of judging only by whether a page opens. If the rule matches but the service still fails, check the proxy group exit, DNS response, and stale connections. Avoid adding duplicate rules straight away; a long list of exceptions makes future troubleshooting slower.

DNS configuration and resolution paths

Map the steps in a DNS request first

DNS configuration involves three questions: where the app sends its query, how the core chooses an upstream, and how the upstream's own hostname is resolved. System DNS, browser Secure DNS, app-specific resolvers, and mihomo DNS can all be active at once, so changing one upstream may not affect every app. Before tuning, confirm that the connection passes through the core and that the relevant query appears in its logs. If the request never reaches the core, changing its cache or upstream order repeatedly will not help.

nameserver defines the regular DNS upstream; default-nameserver is mainly used to resolve the DNS upstream's own hostname as part of the bootstrap process. An encrypted DNS endpoint still needs its hostname resolved to an IP address first. If bootstrapping fails, the entire resolution chain may appear to time out. Choose a bootstrap resolver that is reachable on your current network, and keep its role separate from resolving service domains. Avoid making an upstream depend on a proxy route that is not available yet.

Keep one easy-to-verify DNS path

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:
    - https://dns.alidns.com/dns-query
  nameserver-policy:
    '+.example.com':
      - 223.5.5.5
  fake-ip-filter:
    - '*.lan'
    - '*.local'

This example listens for DNS queries only on the local machine and assigns a separate upstream to the example domain. A listening port does not change system DNS or automatically take over queries from other devices. It is used only when system settings, client-level traffic interception, or an app's proxy path sends queries to it. Upstream reachability depends on your network, so verify the basic path before adding domain-specific policies. Internal LAN domains need a resolver that knows their records, not a public upstream by default.

nameserver-policy chooses a DNS upstream based on the domain; it changes the resolution path, not the connection's exit. Even when a domain resolves through the specified DNS server, rules still determine whether its connection uses a proxy or connects directly. Conversely, a domain matching a proxy rule does not mean its DNS queries use the same proxy exit. Keep DNS policies and routing policies in separate lists to avoid confusing “use this DNS server” with “use this proxy node.”

Proxy server DNS and fallback resolution

If a proxy server is configured by hostname, resolving it is part of setting up the proxy connection. Use proxy-server-nameserver to specify an upstream for proxy server hostnames when they need a separate resolution path, so the node's hostname does not depend on the node itself. Check this setting when using rule-based DNS routing, too. With multiple proxy layers, remote provider downloads, and encrypted upstreams, the priority is avoiding circular dependencies—not forcing every request through the same path.

Understand fallback and fallback-filter together: the latter helps determine which results should use fallback resolution. It is not simply a queue that switches whenever the primary DNS server fails. Overly broad filter conditions can send many domains to the fallback and increase query overhead. If you have no specific requirement, start with a single, easy-to-verify path. Add filters only when you can identify which domains or address results need special handling.

Encrypted DNS can protect queries in transit, but it cannot replace choosing the right exit or guarantee that remote results are suitable for local access. IPv6 also requires end-to-end support: getting an IPv6 address from the system does not mean the proxy node, routes, and destination all have a working IPv6 path. If only some websites stall, check AAAA responses and actual IPv6 connectivity before changing the core's IPv6 DNS settings. Do not assume every issue is caused by the resolver.

Check where queries enter and how caching affects results

During testing, query the system's default DNS and the specified listening port separately, then compare whether they use the same path. A tool that supports a custom port can use dig @127.0.0.1 -p 1053 example.com; you may need to install the tool separately, as the client may not include it. A synthetic address in Fake-IP mode can be expected behavior, so a difference from a public resolver alone does not indicate a misconfiguration. Better evidence comes from query logs, the domain-to-address mapping, and whether the subsequent connection is consistent.

After changing settings, reconnect the app, clear its own DNS cache if needed, and check whether browser Secure DNS is bypassing system resolution. Record the query entry point and upstream used so you do not compare results from different paths. If only internal domains fail, check the local resolver and domain-specific policies first. If all domains fail, start with upstream bootstrapping, the listening port, and network reachability.

TUN, Fake-IP, and traffic interception

Understand the difference between system proxy and virtual interface routing

A system proxy usually provides an HTTP or SOCKS proxy endpoint to apps that follow system settings, but it does not guarantee that every connection passes through the core. TUN uses a virtual network interface and routing rules to receive traffic, making it useful for apps that cannot be configured to use a proxy directly. The two approaches are not mutually exclusive, but you need to know how each connection enters. An enabled TUN switch only shows that the client attempted to activate the feature; verify that the interface, routes, DNS, and permissions are all working.

Desktop systems usually need administrator privileges, a service mode, or a helper component to manage virtual interfaces and routes; the client provides the specific controls. Android traffic interception commonly uses VpnService, and background operation may also depend on the system's battery optimization settings. Do not copy every desktop YAML routing field into a mobile UI, or layer this setup directly on top of an existing corporate VPN or other traffic interception tool. First understand which routes each one controls.

Start with conservative TUN settings

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

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16

This example shows how traffic interception relates to DNS. In practice, merge it into your existing tun and dns sections. auto-route configures routes automatically, while auto-detect-interface identifies the outbound network interface. Choose a stack based on platform support and core logs. If the client manages these fields, change them through its UI to avoid local overrides conflicting with client settings. A stack used in an example is not necessarily the best choice for every device.

dns-hijack routes matching traditional DNS requests to the core's resolver; the example does not mean that all DNS traffic can be intercepted. Apps using HTTPS or other encrypted channels no longer send ordinary DNS requests to the usual destination port, so check their routing and settings separately. Internal resolvers, router hostnames, and special networks may also need exceptions. Check where queries enter before deciding what to intercept; broadening the interception scope is not a substitute for finding the cause.

Fake-IP uses mappings; it is not a real server address

Fake-IP assigns synthetic addresses to domains and stores a mapping between each domain and address in the core, which then associates app connections with the original domain. This can reduce the need to resolve real addresses in some cases and helps domain-based rules work. A synthetic address is not the remote server's address. Do not use it for remote firewall allowlists or expect devices that bypass the same core to use it. If an app caches a mapping but its connection does not return to the corresponding core, access may fail.

fake-ip-filter excludes specific domains from Fake-IP assignment. It is useful for LAN discovery, internal services, or apps that are known to be incompatible. The filter returns a real DNS result, but routing and rules still handle the connection; it does not automatically mean DIRECT. Start by adding exceptions for specific domains with reproducible issues, and make sure they resolve correctly. Excluding broad ranges of commonly used domains changes how the mode works and makes domain matching more dependent on other sources of information.

Private network ranges, container networks, and corporate VPNs can conflict with the synthetic address range or automatic routing. If an address range becomes unreachable, check the system routing table and existing interfaces before changing all DNS settings. Before choosing a custom address pool, make sure it does not overlap with an existing network, then configure route exclusions as supported by the client. Excluding a range may keep its traffic out of the core, so core rules will no longer be able to route that traffic; understand this boundary in advance.

Troubleshoot in order: interface, routes, DNS, connection

If enabling TUN cuts off all connectivity, disable it to restore the original network, then check core permissions and whether the virtual interface was created successfully. Next, check whether the default outbound interface was detected incorrectly, especially on devices with multiple interfaces, hotspot sharing, or a VPN. Once basic routing is correct, test DNS. If a domain resolves but the connection fails, check the matched rule and proxy protocol support. Verify each layer with one reproducible request instead of switching between stacks and DNS settings before looking at the logs.

If only Android background connections drop, check system permissions and battery optimization; see Android VpnService and background operation. If only LAN devices are affected, check the shared proxy port, firewall, and listen address separately. The computer's TUN status does not prove that other devices are using the proxy.

Domain sniffing and rule matching

Sniffing adds domain information; it does not replace DNS

When a connection enters the core, it may not include a usable domain name. For example, an app may connect directly to an IP, or its DNS query may happen outside the core, leaving the rule engine with only a destination address. Domain sniffing tries to extract host information from the beginning of a connection to provide clues for domain-based rules. It is not a general-purpose name resolver for apps, and it cannot identify every connection. Before enabling sniffing, find out whether and where domain information is missing.

Common sources include the host field in an HTTP request and the server name visible in a TLS handshake. QUIC detection also depends on protocol support and whether the data can be parsed. Encrypted ClientHello, nonstandard handshakes, protocols without domain names, and established connections can all limit detection. A successful sniff is not the only measure of a correct config. Unidentified connections still need sensible IP rules and a catch-all policy; do not expect sniffing to supply every missing detail.

Limit protocols and ports before expanding coverage

sniffer:
  enable: true
  sniff:
    HTTP:
      ports:
        - 80
        - 8080-8880
      override-destination: false
    TLS:
      ports:
        - 443
      override-destination: false
  skip-domain:
    - '+.example.com'

This example enables detection only on common HTTP and TLS ports, with destination overriding disabled. The skip list uses an example domain; replace it with targets that have a demonstrated compatibility need. The port list defines the detection scope—it does not open firewall ports or automatically route those connections through a proxy. Rules still decide where connections go. Start with a limited scope to see what changes before enabling detection on a large range of ports.

override-destination controls whether a sniffed domain replaces the connection's destination. That is different from simply obtaining a domain for rule matching. For a service originally contacted by IP, overriding the destination may trigger another DNS lookup and ultimately connect to a different address. This can cause compatibility problems for fixed-address services, special CDN routing, or internal gateways. Keep the setting conservative at first; enable it gradually by protocol or domain only when a specific service needs it.

Handle false positives and service-specific exceptions

Some services reuse connections, use a handshake name that differs from the access hostname, or route traffic through an intermediary gateway. The sniffed name may not be the domain the user originally entered, sending the connection into a different rule category. If a service becomes unreliable only after sniffing is enabled, record the domain, destination address, and policy before and after, then add a skip entry for that target. Do not immediately disable all domain rules or force an entire service ecosystem to connect directly; that makes the change much broader than necessary.

force-domain and sniffing for IP-only connections are advanced controls whose value depends on the traffic entry point and core support. Keep the scope narrow; a useful requirement should be specific, such as “this app has no domain mapping for this domain, so detection needs to be added.” If you cannot identify the affected connection, check the DNS entry point and Fake-IP mapping first. Many cases that appear to require forced sniffing are actually caused by DNS and the connection taking different paths.

Sniffing also affects early connection handling. On timing-sensitive apps, protocol waits and failed detection can change how connections are established, so test with the transport protocols the service actually uses. Opening a website in a browser does not prove that in-app voice, video, or other long-lived connections work. Increase log verbosity only temporarily while diagnosing, then restore the normal level to avoid collecting unnecessary domain and connection details.

Verify sniffed results through the full routing chain

Choose a target you can test repeatedly. First establish a baseline with sniffing disabled, then enable it, reconnect, and compare whether rule matching changes as expected. If the destination has no domain information but IP rules already handle it correctly, there is no need to add complex settings just to display a domain in the UI. If a detected domain still hits the catch-all rule, check rule order, spelling, and provider contents. Successful detection does not create a routing rule for that domain.

For services involving fixed IPs, certificate errors, or proxy gateways, check application-level errors too; do not look only at whether the proxy connection was established. The core does not normally decrypt application data because of sniffing, and it cannot fix server certificates or account permissions. Track “domain detected,” “policy selected,” “destination reached,” and “app request succeeded” as separate outcomes to avoid mistaking a later service failure for a sniffing failure.

For internal systems that must retain their original destinations, prefer explicit domain rules, internal DNS, and a short sniffing skip list. Complex services cannot be made consistent with one global switch. If you disable sniffing, recheck that connections previously identified through it now reach an appropriate catch-all policy. For basic terminology, see the glossary.

Local overrides and subscription merging

Define the boundary between remote input and local settings

Subscription updates usually download remote content again, so direct edits to a downloaded copy can be lost at the next update. Put persistent settings in the client's override, merge, or script interface, but these interfaces are not standardized by mihomo. Clash Plus, Clash Verge Rev, FlClash, and other clients may apply changes at different stages and merge fields differently. Check the final config before proceeding; similarly named controls do not guarantee identical override behavior.

Settings suited to local maintenance include listen scope, DNS preferences, internal domain rules, and a stable proxy group structure. Node parameters and external rule data are better suited to remote updates. Keeping these concerns separate prevents local settings from changing with every node update. If the remote config already includes a complete rules framework, decide whether to keep it or use your own before adding overrides. Otherwise, two nested structures may compete without a clear source of final control.

Organize multiple proxy sources into collections

proxy-providers:
  Source A:
    type: file
    path: ./providers/source-a.yaml
  Source B:
    type: file
    path: ./providers/source-b.yaml

proxy-groups:
  - name: Subscription A
    type: select
    use:
      - Source A
  - name: Subscription B
    type: select
    use:
      - Source B
  - name: Proxy Entry
    type: select
    proxies:
      - Subscription A
      - Subscription B
      - DIRECT

This example uses local proxy collections, and both files must contain a valid proxies list. The structure lets you verify each source separately, then select between them through a top-level group. A complete Clash config, a YAML file containing only proxies, a Base64-encoded list, and a protocol share link are different formats. Adding any subscription URL to a collection does not mean the core can parse it. Check the response format first, and use a trusted local conversion process if needed; see subscription formats explained.

For remote proxy collections, configure a valid subscription URL, cache path, and update interval, and decide how downloads will be routed during startup. Subscription URLs often contain account credentials; keep them in private local config and never paste them into public conversion tools or issue screenshots. Remove real URLs, credentials, and account-recoverable parameters from teaching or shared examples. Even without a proxy password, a full subscription URL may grant access and should not be treated as an ordinary public link.

Merging lists is not simple text concatenation

Dictionary fields can be overridden by key, but lists can have different semantics: replace, prepend, or append. Appending a local rule after a remote MATCH usually will not make it an exception with higher priority. Replacing the DNS list outright may remove the existing internal resolver. Before adding an override, define the intended operation and check that the client supports it. If the client only supports replacing a whole section, maintain the complete desired section instead of submitting a few entries and assuming the rest will be preserved.

Different sources may contain proxies and proxy groups with the same names. Duplicate names in the UI are hard to distinguish, and rule or group references may become ambiguous. Prefer clear naming at the source, and use name prefixes or modifiers only where the client supports them. Do not change only the displayed label while leaving old references behind. Check regex filters after merging as well: new prefixes, changed sources, or different naming conventions can make a previously valid expression return no results.

Health checks also have separate layers. A proxy collection can check its nodes, and an automatic proxy group may run its own probes; duplicating checks increases traffic. Not every manual selection group needs another round of automatic tests. First decide whether you need to know “which proxies in this collection are reachable” or “which candidate the automatic group should choose,” then configure the appropriate check. With multiple subscriptions enabled, each source being available does not guarantee that the shared parent group or its rule references are correct. Verify the final candidates and references too.

Build a repeatable update and rollback process

After merging, check YAML parsing, provider loading, proxy group candidates, rule order, and DNS results in sequence, then save a preview of the final config. Run a subscription update and repeat the same checks to confirm that local settings persist. Treat an override as persistent only after testing it through an update. A UI selection that works only in the current session may depend on whether the client saves runtime state; verify behavior after a restart separately.

When migrating from an older client, export local overrides and any important proxy selections first, then import them into the new client and verify each section. Do not assume that configuration databases can be used across clients. Choose a client for your platform on the downloads page. Start with one subscription and a working connection, then add a second source, and restore complex rules last. This gives every change a clear scope for testing.

External controllers and API security

The controller port and proxy port serve different purposes

The mixed port forwards app connections; the external controller port reads status and performs management actions. A dashboard uses the controller API to inspect proxy groups, connections, and logs, and may also change modes or reload config. It is not another proxy port to enter in a browser. The two listeners cannot use the same port on the same address. If startup reports a conflict, check the proxy, DNS, and controller listeners separately rather than only changing the number in your system proxy settings.

The controller API has more privileges than a read-only status page because software with access can change how traffic is handled. A desktop setup usually needs only a loopback address. For remote management, consider an authenticated tunnel or a network with restricted access first. Binding the controller to all interfaces only broadens access; it does not add access controls, and a dashboard that is not visibly shared with others is not a security measure. The actual security boundary depends on the listen address, firewall, and authentication together.

Local binding and authentication

external-controller: 127.0.0.1:9090
secret: "your-controller-password"

The password in this example is a dummy for demonstration. Replace it locally with a unique, strong value; do not reuse proxy credentials or another account password. A client may manage the controller address and authentication fields itself. If the dashboard disconnects after a manual override, first check whether its saved connection settings still match rather than clearing authentication. After changing the listen address or credentials, update existing dashboard connections too. Multiple dashboards with different saved values can cause intermittent connection failures.

If the client provides a built-in local dashboard, use its supported launch option. When running the core directly, external-ui can point to a prepared local directory containing static dashboard files; setting a path does not create the dashboard for you. Resolve relative paths against the core's working directory, and recheck them if you move the config. Do not loosen permissions on the entire config directory just to make the dashboard load.

Distinguish network access, authentication, and browser restrictions

When a dashboard cannot connect, first confirm that the core is running and the controller address is listening. Then check the protocol, host, port, and credentials entered in the dashboard. If the local machine can connect but other devices cannot, check the bind address and firewall. If the connection succeeds but returns unauthorized, focus on authentication. A dashboard that loads with no status may have accessible page resources but a failed API connection; the page's appearance does not prove that the control channel is working.

Browsers may also block requests because of cross-origin policies or mixed content. A dashboard opened over HTTPS may try to call a plain HTTP controller API, and the browser can block that request before it reaches the core. Check the specific error in the browser's network panel, then consider same-origin hosting, the client's built-in dashboard, or a protected proxy. Do not assume every browser error means the core lacks support, and do not broaden allowed origins and network listeners just to silence an error.

If cross-origin access is necessary, restrict allowed origins according to what the core and dashboard support, and keep authentication enabled. A remote reverse proxy must also forward WebSocket connections correctly; otherwise, ordinary requests may work while live logs keep disconnecting. Protect the entry point with both transport encryption and access controls. Adding a login page in front of the dashboard is not enough if the underlying controller port remains exposed to untrusted networks. If you are unsure of the deployment boundary, keep the controller bound to the local machine.

Use connection details to close the troubleshooting loop

The dashboard's most useful details are the connection entry point, target domain or address, matched rule, and final policy chain. To troubleshoot a failed request, reconnect and find its entry in the connection list, then verify that it reached the expected service group. If there is no entry, check whether the app uses the proxy or TUN. If there is an entry but the wrong rule matched, check rule order. If the rule is right but the connection cannot be established, check the proxy, DNS, and protocol support. This order keeps troubleshooting focused on observable layers.

Changing a proxy group affects future selections; existing connections may keep using the previous exit. To test, close only the relevant connection and retry rather than interrupting all traffic. If you temporarily enable detailed logs, note the reproduction time and target, then restore the normal log level. Before sharing screenshots or exported logs, remove subscription URLs, credentials, internal domains, and unnecessary destination details. Diagnostics need evidence related to the issue, not your entire private network history.

Use a consistent maintenance process: save a working config, change one thing, validate syntax, reload in a controlled way, verify the match, update the subscription, verify again, and record a rollback point. For each issue, check four layers in order: entry point, resolution, matching, and exit. There is no need to reinstall the client and replace the subscription at the same time. For common setup and usage questions, visit the Help Center. To review the import and connection basics, return to the Quick Start Guide.