MIHOMO · CONFIGURATION REFERENCE

Clash Advanced Configuration Guide

Proxy groups, rule sets, DNS, and traffic routing. Follow configuration precedence to check each layer’s inputs, limits, and results.

For your first installation and subscription import, follow the Getting Started guide to establish a connection. This page is for users with a working configuration who need a focused reference for settings that require ongoing maintenance; it does not repeat the quick-start steps. Examples use mihomo configuration syntax. Menu labels and override methods vary by client.

Configuration Precedence and Validation

A Clash configuration file is not simply a copy of every setting in the interface. In desktop clients such as Clash Plus, the app handles subscription downloads, window controls, and system integration, while the mihomo core handles listening ports, rule matching, and connections. A client may read the subscription, apply local settings, and then generate the configuration used at runtime. If that process overwrites edits to the subscription file, those changes will not persist. Advanced configuration starts with understanding these layers.

Check what the core actually loads

Confirm the active profile on the client’s configuration page, then check the startup logs for the configuration directory in use. If there is a “View runtime configuration” option or similar, inspect the final generated configuration rather than just the editor’s source. Pay particular attention to the mixed port, operating mode, DNS settings, and rule list. File locations vary by client, so don’t copy an absolute path from another computer or move the working directory while the core is running.

Before making changes, keep a copy of the working configuration and note the state of the system proxy, TUN, and service mode. Change one category at a time—for example, update proxy groups and confirm they load before changing DNS. If you replace a subscription, enable a virtual network adapter, and change resolvers all at once, it’s difficult to tell which layer caused a problem. Keep backups locally: they may contain subscription URLs, proxy passwords, or control interface credentials and should not be posted publicly.

Use a minimal configuration to separate syntax from network issues

The minimal configuration below is for direct-connection testing on your own machine and can be saved as a separate file for the core to check. It has no proxy nodes and cannot provide remote proxy access. Use it to confirm that the YAML can be read, local ports can start, and direct connections work in rule mode. For normal use, return to your existing subscription; this file is not a complete proxy configuration.

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
proxies: []
proxy-groups:
  - name: Manual selection
    type: select
    proxies:
      - DIRECT
rules:
  - MATCH,Manual selection

Use spaces for YAML indentation and keep indentation consistent at each level; the dash before list items and the space after a colon are significant. Names containing special characters can be quoted, but references must match them exactly. Repeated top-level keys are especially easy to misread: having two dns: sections in one file does not mean the settings will be merged automatically, and parser behavior may vary. Combine them into a single object first, then use an override mechanism supported by your client.

A successful validation does not guarantee a working connection

When running the core directly, execute the command below from the configuration directory. The working directory determines how relative paths are resolved, so -d and -f should point to the same prepared set of files. Passing a syntax check only confirms that the configuration is accepted; it does not guarantee that remote rule sets can be downloaded, nodes can authenticate, or DNS servers are reachable. After startup, check the initial load logs instead of relying only on the exit code.

mihomo -t -d . -f config.yaml

If a port is reported as occupied, first check whether another client or core is still running in the background. Don’t keep changing ports just to clear the error: the app’s manual proxy setting, system proxy, and client listener must agree. If the configuration loads but only some apps fail, check whether they follow the system proxy, use their own DNS resolver, or send traffic through TUN. These are not YAML indentation errors.

To choose a client, start with the download center. Clash Plus is a good first option; compare other clients based on your operating system and existing workflow. For an overview of how the original Clash, mihomo, and graphical clients relate, see How Clash Cores and Client Forks Relate. The chapters that follow cover configuration behavior, not button locations shared by every client.

Proxy Group Types and Practical Use

Proxy groups sit between rules and nodes: rules send a connection to a group, and the group chooses its outbound route. Pointing rules directly at a node is simple, but renaming that node means updating every reference. A more maintainable setup points rules to stable, purpose-built groups, which can then reference manual or automatic selection groups. Grouping should serve real needs; there’s no need to create duplicate layers for every website.

What each of the four types is for

select is a manual selection group, useful when you need a fixed route or want to troubleshoot. url-test automatically picks a route based on probe results and suits routine traffic where the route can change. fallback selects an available option in the configured order; it provides primary/backup behavior, not a guarantee of choosing the fastest route. load-balance distributes separate connections across multiple routes; it does not combine bandwidth for a single download connection.

How to choose a proxy group
TypeSelection basisConsiderations
selectUser selectionConfirm the selected route is still available
url-testProbe responseA successful probe does not guarantee the service you need is reachable
fallbackOrder and health statusMay switch back when the primary route recovers
load-balanceDistribution algorithmLogin services may require a stable route

Choose a probe endpoint that is stable, responds quickly, and is reachable through every candidate node. If the endpoint itself is blocked, every node in the group may appear unhealthy even when actual traffic works. Conversely, connecting to a single test site does not prove that streaming access, work system logins, or other region-specific requirements are met. Track health checks and service-specific tests separately when troubleshooting.

Keep the service entry point stable

The snippet below places an automatic group inside a manual group. include-all includes eligible proxy candidates already present in the configuration, so the full configuration must actually load usable nodes. It is not a source of nodes and does not create proxies. The probe URL is a common connectivity test endpoint; if it is unreachable on your network, replace it with a lightweight endpoint you have verified.

proxy-groups:
  - name: Automatic selection
    type: url-test
    include-all: true
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50
  - name: Outbound
    type: select
    proxies:
      - Automatic selection
      - DIRECT

interval is measured in seconds and sets how often probes run; tolerance is measured in milliseconds and helps avoid frequent switching between similar results. A shorter interval is not always better: it increases background requests and makes the group more sensitive to brief fluctuations. On laptops or mobile networks, start with a more conservative interval and review the logs instead of treating probe frequency as a guarantee of connection quality.

For proxy providers, use use to reference an existing proxy-providers name instead of listing every node in a group. A provider name and a node name are different things: the provider manages a source, while a node represents a specific route. When filtering provider nodes, account for upstream renames and the possibility that no nodes match. After making changes, check the candidate list—not just whether the configuration loads.

Switching behavior and recovery

Automatic group changes typically affect new connections; existing long-lived connections may not move immediately. If a refreshed page still uses the old route, close the app’s existing connections and try again before assuming the group is broken. Video playback, terminal sessions, and work systems vary in their tolerance for route changes. Services that require a stable source IP are usually better suited to a manually pinned group than automatic switching between regions.

Groups can reference other groups, but they must not form a loop. For example, if “Outbound” references “Work” and “Work” points back to “Outbound,” there is no clear final route. Follow the reference chain when designing groups and make sure it ends at an actual node or a built-in policy such as DIRECT. Avoid naming groups after nodes as well; it makes both the interface and rule targets harder to interpret.

Validate in this order: confirm the proxy page has candidates, manually select a known working node, then enable automatic selection. If the fixed node works but the automatic group fails, check the probe endpoint, filters, and group references. If the fixed node fails too, investigate node authentication and the underlying network rather than adding more groups. For help finding the relevant interface pages, see Proxy, Configuration, and Log Pages Explained.

Manage Rule Sets with Providers

Rules are evaluated in list order; the first match determines the policy. Rule sets simply put many match conditions in separate files—they do not change this order. For easier maintenance, put a few local exceptions first, followed by service-specific and general regional rule sets, then use MATCH as a catch-all. Only rules that depend on DNS lookup results need the core to resolve the destination address.

Match specific conditions before using a catch-all

DOMAIN matches an exact domain; DOMAIN-SUFFIX matches a domain and its subdomains. IP-CIDR matches an address range, while GEOIP relies on geolocation data. Broad rules placed first can shadow more specific exceptions later in the list. If a website consistently uses the wrong route, find the first matching rule instead of repeatedly adding the same domain at the bottom.

The policy target in a rule must exist. If a rule points to “Outbound” but the actual group is named “Proxy,” the difference will not be corrected automatically. Subscription updates can also rename groups, so local rules should reference a stable entry point that you maintain. Another common issue is switching to global mode: the regular rule list no longer participates in routing as expected. Check the operating mode before investigating match details.

Build a test case with a local rule set

The snippet below uses a local file, making it useful for validating the path, format, and rule reference first. File paths are resolved relative to the core’s working directory. The example sends reserved example domains directly; it does not make any recommendations for actual traffic. Once the mechanism is confirmed, replace the contents with a domain list you maintain. The main configuration and rule file are separate files—do not save the two snippets concatenated together.

# Relevant section of the main configuration
rule-providers:
  local-direct:
    type: file
    behavior: domain
    format: yaml
    path: ./rules/local-direct.yaml

rules:
  - RULE-SET,local-direct,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,Outbound
# rules/local-direct.yaml
payload:
  - '+.example.com'
  - '+.example.org'

behavior: domain is for domain collections, whose entries do not need the full DOMAIN-SUFFIX prefix. Use ipcidr for address ranges; classical supports traditional rule conditions, but entries should still omit the final policy name. Set format to match the file’s actual format. Marking an HTML error page, JSON API response, or plain text file as YAML will cause loading to fail.

Keep remote updates from overriding local exceptions

For an HTTP rule provider, set a valid url, a cache path, and an update interval. Rule set update intervals are also measured in seconds. The remote URL should return the rule file itself, not a preview page from a code hosting site. Give each source its own cache path; sharing a path makes it difficult to identify the file during updates or rollbacks.

Rule set downloads also need a working network route. A startup dependency loop can occur if downloading a rule set requires a policy that itself depends on rules or node sources that have not loaded yet. For initial setup, make sure a basic route works before adding remote rules. If downloads need a specific proxy, use a clearly available policy group. When an update fails, keep the HTTP status and parsing error from the logs instead of deleting all cached files.

Using no-resolve with IP-CIDR or GEOIP avoids an extra DNS lookup just to test an address rule, but it also means the rule may not match when no destination IP is available yet. It is not a general-purpose performance switch. A better approach is to put known domain rules first, let address rules handle connections with an actual IP, and check connection records to confirm what happened.

For validation, test one domain that is in the sample and one that is not, then check the matched rule, policy group, and final route for each. New connections are the reliable way to observe rule changes; a browser may reuse an existing connection and keep the old route. If the subscription updates but a rule file does not, see the Subscription and Configuration Troubleshooting Checklist to distinguish download failures from parsing failures.

DNS Configuration and Resolution Paths

A DNS configuration needs to answer three questions: what receives app queries, what resolves them upstream, and which network route carries those requests. Changing the upstream to encrypted DNS does not mean every app query goes through the core. Browser Secure DNS, system caches, app-specific resolvers, and local network gateways can all bypass it. Before investigating a Clash DNS leak, map the actual query path on your device.

Separate listening, bootstrap, and regular resolution

listen sets the address where the core’s DNS service listens; nameserver lists upstreams for regular queries. default-nameserver handles bootstrap needs, such as resolving the hostnames of upstream DNS servers; it is not a universal fallback for every failed query. A DoH resolver identified by hostname must first resolve its own hostname, so avoid a loop where you need to reach the resolver to find its address.

The DNS snippet below is intended for local diagnosis and uses a dedicated loopback port. It does not automatically change the operating system’s DNS server to this address or capture app traffic. First query the listening port explicitly with a command, then verify traffic interception with TUN or system settings. This helps distinguish a failure in the DNS service itself from an app that never reached it.

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
  nameserver:
    - https://dns.alidns.com/dns-query
  nameserver-policy:
    '+.example.com':
      - 223.5.5.5

Example addresses illustrate the configuration structure; choose actual resolvers based on your network operator, location, and access requirements. Use nameserver-policy to direct specific domains to particular resolvers, for example when internal DNS or a specific regional result is required. Don’t send an entire business domain to a public resolver without a reason, or internal addresses may not resolve. Keep match scopes narrow: verify a single domain before expanding to its subdomains.

Align DNS requests with routing policies

To route DNS connections according to routing rules, consider respect-rules and configure proxy-server-nameserver correctly to resolve proxy server hostnames. Otherwise, resolving a proxy node may require the proxy, while connecting to the proxy requires the node’s address—a startup loop. There is no universal combination of switches for every subscription. The key is to ensure at least one bootstrap path does not depend on a proxy that has not been established yet.

direct-nameserver can handle resolution for direct outbound connections. If you also use domain policies, decide whether those lookups should follow nameserver-policy. Don’t configure several sets of nameservers, fallbacks, and policy mappings all at once without checking the results. Complex configurations can trigger multiple queries for the same domain and make it harder to trace where an answer came from.

The traditional fallback and fallback-filter settings control how DNS responses are selected; they do not simply mean “try the second DNS server only if the first one times out.” Filters, geolocation checks, and candidate responses all affect the final answer. If explicit domain policies already meet your needs, keep the configuration simple. Add filtering only when you have reproducible cases of DNS pollution or unexpected responses.

Verify the response and request route separately

Use the command below to query the local listener on systems with dig installed. Windows tools vary in their support for custom ports, so make sure you are querying the local core rather than system DNS. Record the query time, response type, and upstream shown in the logs, then compare them with the app’s connections.

dig @127.0.0.1 -p 1053 example.com A

In Fake-IP mode, returning a virtual address is expected; a difference from a public DNS result does not by itself indicate a resolution error. For IPv6, distinguish the core’s main setting, whether DNS returns AAAA records, the system’s IPv6 routes, and the proxy node’s transport support. The example disables IPv6 DNS responses only to reduce variables during initial diagnosis; it is not a recommendation to disable IPv6 permanently on every network.

Leak test sites usually show the DNS sources involved in one web request; they cannot cover every app and protocol. If a browser has its own Secure DNS setting enabled, check that separately. Managed devices may also have organization policies. Don’t repeatedly change system settings just to pass a particular test page. First define what you need to protect and which queries should be intercepted, then cross-check logs, routes, and app behavior.

TUN and Fake-IP Together

TUN and Fake-IP operate at different layers. TUN creates a virtual network interface that sends IP traffic meeting the routing conditions into the core. Fake-IP changes DNS responses, using virtual addresses to preserve the domain association. TUN handles how traffic gets in; Fake-IP helps identify the domain it is going to. They are often used together but can be configured separately, so enabling one does not mean the other is working.

Check permissions and route ownership first

Enabling TUN in a desktop client usually requires administrator privileges, system authorization, or an installed background service. The system proxy setting mainly serves apps that follow system settings; see System Proxy Settings for details. If a browser works but command-line tools do not, those tools may simply ignore the system proxy. First decide whether you actually need TUN rather than changing both the proxy node and DNS at once.

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

This configuration describes a common traffic interception setup, but its results depend on system permissions, the client service, and local routing. auto-route adds the relevant routes, while auto-detect-interface attempts to identify the outbound interface. With multiple network adapters, virtual machines, or VPNs running together, automatic detection may not choose the right one. Record the default route before making changes; if something breaks, inspect the routes instead of repeatedly switching network stacks and hoping for the best.

Key TUN checks by platform
EnvironmentCheck firstCommon conflicts
WindowsService permissions, virtual interface, and system firewallOther VPNs, virtual switches, and loopback restrictions
macOSNetwork authorization, default route, and service statusOther tunnel interfaces and network filtering software
LinuxTUN device, permissions, and policy routingFirewall rules, containers, and network namespaces

Understand virtual addresses and domain exceptions

Fake-IP maps domains to a dedicated pool of virtual addresses, then restores the domain association when the connection returns to the core. Apps may fail if they store only the IP, forward the address to another device, or reuse a cached address after the core exits. A virtual address is not the website’s real IP and should not be used in firewall allowlists or copied to a device that does not use the same core.

For printer discovery, local devices, or services that need real addresses, add exceptions in fake-ip-filter so matching queries return real addresses. Base filters on domains that actually fail instead of excluding a broad range of public services. Excluded connections may lose the domain-mapping benefits of Fake-IP and rely on address rules or sniffing instead; overly broad filters make routing harder to explain.

# Merge into the existing dns object; do not declare a second dns configuration
dns:
  fake-ip-filter:
    - '*.lan'
    - '*.local'

.local services may also use multicast DNS, which means a regular DNS exception will not necessarily restore device discovery. Intercepting ordinary port 53 traffic in TUN does not automatically capture every encrypted DNS or multicast query either. If a printer is reachable by fixed address but not discoverable automatically, check multicast, local network routing, and system services instead of changing only the DNS server.

Avoid overlapping interception and routing loops

Corporate VPNs, remote work tunnels, and other proxy clients may all change routes. In general, first turn off interception you don’t need, then test a single TUN setup. If they must coexist, determine routing for each work subnet, proxy server address, and local management address. Excluded subnets should come from your actual network plan. Copying a long list from the internet could bypass the proxy for traffic that should use it.

After switching Fake-IP, disabling TUN, or restarting the core, apps may still have old addresses cached. Close the app’s connections and query the domain again; if needed, clear the system DNS cache before checking a new connection. Don’t draw conclusions from a single page refresh while old connections are still open. If only one app fails, record its destination address and protocol; that is more useful than changing every route at once.

Follow a clear recovery sequence: disable TUN and confirm the basic network works, check whether the client removed its routes, then restore the previous system proxy state. The client should normally clean up its own interception settings on exit, but a crash can leave leftovers. For common issues, see the Troubleshooting FAQ. Before changing system-level networking—especially on a remotely accessed device—make sure you have a way to recover locally.

Domain Sniffing and Its Limits

Domain sniffing extracts the target host from the initial data of some protocols after a connection has entered the core. Common sources include the HTTP Host header and the server name in a TLS handshake. It can help apply domain rules to connections that have only a destination IP, but it is not a replacement for DNS and cannot identify all encrypted traffic. Think of it as an additional clue, not a complete application identification system.

Traffic must reach the core before it can be identified

Sniffing only handles connections the core has received. If an app bypasses the system proxy and does not enter TUN, enabling sniffing will not bring its traffic in. Conversely, sniffing may add little when a connection already has reliable domain information. First confirm the connection appears on the client’s connections page, then check its domain, matched rule, and final route. Don’t start by expanding the sniffed port range.

sniffer:
  enable: true
  sniff:
    HTTP:
      ports:
        - 80
        - 8080-8880
      override-destination: false
    TLS:
      ports:
        - 443
        - 8443
      override-destination: false
    QUIC:
      ports:
        - 443
      override-destination: false

The example limits sniffing to common protocol ports and preserves the original destination so you can first check whether identification is reliable. A port is only a place where a protocol may appear, not a guarantee about its contents; port 443 can carry other protocols too. Sniffing every port adds unnecessary processing and makes compatibility issues with nonstandard services harder to isolate. Expand gradually based on actual use.

Identifying a domain is not the same as rewriting the destination

override-destination determines whether the sniffed result replaces the connection destination. Services that rely on a specific IP may reach a different server after it is rewritten; for a site using a CDN, resolving again may also change the selected address. If you only want to improve rule matching, keep the original destination and check the connection records first. Enable destination override only when you have a specific need for it.

Enabling parse-pure-ip lets some connections with IP-only destinations be considered for sniffing, but identification depends on whether the protocol contains a readable domain. An HTTP request sent directly to an IP may not include the domain you expect, and TLS may not include a server name. An app’s proprietary encrypted protocol may not follow HTTP, TLS, or QUIC parsing either. If identification fails, don’t assume it must work just because the connection uses HTTPS.

Use settings such as force-domain and skip-domain to define specific cases where sniffing is required or skipped. Exceptions should address reproducible service behavior; don’t copy an unexplained domain list into your configuration. With shared IPs, reverse proxies, or internal gateways, an identified name may not reflect the original intent of the connection. Consider the original destination as well.

Encrypted protocols and privacy limits

Some TLS deployments use Encrypted ClientHello and may prevent traditional server name extraction. QUIC runs over UDP, so it is handled differently from TCP and is also subject to node UDP support, routing, and network policy. If a browser can reach a site but the client cannot identify its domain, the configuration may still be correct. If rules work using other reliable information, there is no need to display a domain for every connection.

Sniffing does not decrypt HTTPS content, and ordinary domain identification does not require installing a self-signed root certificate on your device. It does not read login passwords or webpage content. Domains can still reveal browsing intent, so share logs and dashboards cautiously. Before sharing troubleshooting details, remove private domains, subscription information, and node credentials; include only what is needed to reproduce the rule issue.

To test, use a known domain and create a new connection with sniffing both disabled and enabled. Compare the domain field and matched rule. Don’t judge only by whether the page loads: the same catch-all policy may succeed either way. If enabling sniffing causes access problems, first disable destination override and narrow the port range. If the issue remains, temporarily turn sniffing off and check the DNS mapping and rules.

For financial logins, corporate intranets, and services accessed by fixed IP, stability is usually more important than broader identification. Keep explicit address or domain rules and add narrow exceptions for known incompatible services. The acceptance test for sniffing should be that the intended traffic is routed correctly without causing problems—not that every connection displays a name. That avoids sacrificing usability for a complete-looking interface.

Local Overrides and Merging Multiple Subscriptions

A subscription supplies remote nodes and base configuration; local overrides preserve preferences specific to your device. Keeping them separate helps prevent subscription updates from overwriting ports, DNS settings, or rule exceptions. But “override” does not mean the same file format in every client: some support object merging, some prepend rules, and others generate configuration with scripts. Check your client’s documentation before editing; don’t assume one app’s workflow applies to another.

Decide who maintains each category of data

The subscription source typically maintains node addresses, authentication parameters, and server-side changes. Local settings are better suited to listening addresses, LAN access scope, device-specific rules, and control interfaces. DNS and proxy groups fall between the two, depending on whether the upstream configuration already provides a complete design. If you take ownership of either, decide whether to replace the whole object or add a few fields; avoid mixing upstream assumptions with local logic.

Check object merging and array merging separately. Overriding dns.enable may involve just one boolean, while rules and proxy-groups are arrays that a client may replace, prepend, append, or process by name. Seeing a new rule in the editor does not mean the runtime configuration still contains the original rules. After changing merge behavior, check the final rule order and the number of proxy groups.

What to maintain locally
ItemRecommended ownerWhat to check
Node credentials and addressesSubscription sourceUpdate status and whether nodes are still available
Listening port and access scopeLocal settingsWhether the client interface overwrites them again
Personal domain exceptionsLocal rules placed firstWhether they appear before broad rules
Proxy groups and DNSExplicitly assign one ownerName dependencies and complete object structure

Use proxy providers to organize multiple sources

Merging multiple subscriptions should not mean simply concatenating two complete YAML files. Both usually contain the same top-level keys, catch-all rules, and proxy groups, leading to duplicates and overrides. A clearer approach is to keep one main configuration, load each source as a proxy provider, and reference them through a unified set of local groups. If a remote source returns a complete client configuration, confirm that it matches the proxy provider format; changing only the URL will not make it compatible.

proxy-providers:
  personal:
    type: file
    path: ./providers/personal.yaml
  work:
    type: file
    path: ./providers/work.yaml

proxy-groups:
  - name: Source selection
    type: select
    use:
      - personal
      - work
    proxies:
      - DIRECT

Each local file above should contain a valid proxies list, with the path pointing to a prepared node file. These are not storage locations for arbitrary subscription contents. For remote updates, use HTTP providers and give each source its own cache path. Don’t publish real subscription URLs in documents, screenshots, or synced repositories; they often contain credentials that grant direct access to the service.

Different sources may use the same node names. Add recognizable prefixes using a source override mechanism supported by your client or core, then check that proxy groups still reference the right targets. Don’t identify a source by node display order alone. Account for prefix changes in regular expression filters, especially when filtering by region or purpose. After merging, check the actual candidates and verify that both sources can establish connections.

Set clear rollback points for updates

A safer sequence is to copy the current configuration, add one source, confirm it works, then add the second and unify the rule entry points. Keep a recoverable state at every step. If a subscription update fails, don’t immediately delete every source. First determine whether authentication failed, the download failed, or the content could not be parsed. Clear a specific cache only after confirming it is corrupted and that a usable remote source is available.

Script-based overrides must also handle missing fields, empty arrays, and name changes. If a source is temporarily empty, the script should report that clearly instead of generating a configuration that references a nonexistent group. Don’t paste scripts from untrusted sources that can make network requests or read and write files. For simple changes, declarative fields are usually easier to maintain and review than a full script.

Final validation means more than seeing that both subscriptions imported successfully: local rules must remain in the right order, node sources must be clear, proxy groups must be acyclic, and DNS and ports must not change unexpectedly. For quick setup, see the Subscription Import Guide. The merge structure on this page is designed for long-term management; first-time users do not need to build a multi-source setup before establishing a connection.

External Dashboards and Security

An external dashboard uses mihomo’s control interface to read runtime status, switch policies, and view connections. It is neither a proxy entry point nor a subscription server. The mixed port handles app traffic; the control port handles management. They are not interchangeable. If a dashboard will not open, check separately whether its static page loads, whether the control interface is reachable, and whether authentication succeeds. Don’t change the mixed port used for internet access.

Start local management with a loopback listener

If you use the desktop client’s built-in interface, you usually don’t need to open another control port. If you do need a local dashboard, start with a loopback address to avoid exposing the management interface to devices on your LAN. The credentials below are examples only. Replace them before use with a strong password you generate and store locally; never use the sample value for a service accessible from other devices.

external-controller: 127.0.0.1:9090
secret: "your-password"
external-ui: ./ui

external-ui points to a prepared directory of dashboard files, resolved relative to the core’s working directory; it does not generate those files. If the directory exists but has no entry file, the interface may work while the page returns an error. Get dashboard files from a trusted project and deploy them locally according to its instructions. Don’t treat control credentials entered on an unfamiliar webpage like an ordinary website login.

Binding to 127.0.0.1 allows access from the local machine through that address only. Listening on all interfaces may expose the port to devices on your LAN or other reachable networks; actual reachability also depends on the firewall and network topology. allow-lan mainly controls the proxy listener’s access scope; it is not a master switch for the control interface. Turning it off does not replace limits on control port binding and access.

Separate connectivity, authentication, and browser restrictions

If a connection to the interface is refused, first check that the core is running, the listening address is correct, and the port is not occupied. If the connection succeeds but returns unauthorized, check the control password saved in the dashboard instead of changing firewall rules. If the page loads but cannot retrieve data, browser cross-origin restrictions or a mismatch between the page and interface addresses may be involved. Use the browser’s developer tools to inspect the specific request.

An HTTPS page connecting to an HTTP control interface may be blocked as mixed content. Prefer a local deployment on the same machine and origin to avoid cross-origin configuration. If a reverse proxy is necessary, decide which layer handles TLS, authentication, and origin restrictions. Don’t allow arbitrary origins just to clear a browser error, and don’t put control passwords in public URLs; they may end up in browser history, logs, or shared content.

For management across devices, prefer a controlled secure tunnel or access limited to a trusted management network, and use the system firewall to restrict which devices can connect. Exposing the control interface directly to the public internet increases risk: it can show status and change active policies and configuration. Setting a password alone does not address encryption in transit, brute-force attempts, or whether the dashboard itself is trustworthy.

Complete the validation loop after a configuration change

After switching a group in the dashboard, confirm that the client interface and the route used by new connections both reflect the change. After changing the runtime mode, check whether it affects the current rule test. Dashboard state, configuration files, and runtime state do not always stay in sync: some choices are saved by the client, while others are overwritten on reload. For persistent settings, edit the configuration layer that owns them instead of changing them only through the control interface.

Keep logs to the minimum needed for troubleshooting. Temporarily increase the log level for debugging, then restore your usual level after reproducing the issue; avoid recording large volumes of visited domains over time. Before sharing materials, check for node credentials, subscription URLs, control passwords, and personal browsing records. If management credentials are exposed, change the actual credentials and remove the old value saved in the dashboard; deleting text from a screenshot is not enough.

Use a consistent final checklist for the whole guide: the configuration loads, node sources work, proxy group references resolve without loops, rules match as intended, the DNS path is clear, TUN captures the expected traffic, sniffing causes no compatibility issues, and the control interface is reachable only where needed. Change one variable at a time and keep a rollback point; it is usually easier than piling on more settings. If you cannot isolate the issue, share redacted logs and check each symptom under the Troubleshooting category.