MIHOMO / CONFIGURATION REFERENCE

mihomo Advanced Configuration Guide

Proxy groups, rule providers, DNS, and TUN: configure in the order settings take effect, then verify with connection logs.

For your first setup, follow the quick-start guide to install the client, import a subscription, and verify connectivity. This page is a reference for working configurations: it explains what fields do, how components depend on one another, how client overrides are applied, and what to check after making changes.

Configuration Structure Rules & Routing Local Overrides Connection Testing

01 / Configuration basics

Configuration sources, runtime files, and validation order

Open the client’s configuration page and identify the active profile first. Then look for the runtime configuration or core configuration view. The downloaded subscription file, a file you edit locally, and the file ultimately passed to mihomo may all be different. System proxy, port, DNS, and TUN settings in the client may also affect how the final configuration is generated. Before troubleshooting, note the active profile name, configuration directory, and actual listening ports. A field in the subscription editor alone does not prove that the core is using it; start by checking the runtime logs and final generated file.

Create a configuration baseline you can restore

Export the configuration that currently works, and save local overrides separately. Backups may contain subscription URLs, server credentials, or controller passwords; store them in a restricted local directory and redact them from screenshots. Change one component at a time—for example, update proxy groups first, then DNS, and enable TUN last. This makes it easier to trace problems to the most recent change. If you run the core directly, also record the launch command and working directory. Relative paths depend on the configuration directory, so launching from elsewhere can make rule files and dashboard assets unavailable.

When reading YAML, check the indentation and look for duplicate keys. Use spaces for indentation and keep it consistent at each level; prefix list items with a hyphen. A hyphen in a field name is not a list marker. Quote strings containing special characters, especially passwords, URLs with query parameters, and text containing colons. Don’t append a second top-level dns or rules key to simulate an override: parsers may reject it or keep only one copy, producing results that are hard to predict.

# Merge into your working configuration; keep existing outbounds and rules
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
external-controller: 127.0.0.1:9090

Validate the syntax before checking real connections

If you use a standalone core, run the command below to test the file, adjusting the path to match your system. This can catch invalid YAML, some field errors, and reference problems, but it cannot confirm that a remote server is reachable or that system traffic passes through the process. For a graphical client, use its configuration check, reload, or log features first. If validation fails, start with the first meaningful error in the log. Later errors may be consequences of the same indentation problem, and changing fields blindly can break parts that were already correct.

mihomo -t -f ./config.yaml

After validation passes, reload the configuration, close existing connections in the test app, and make a new request. In the connections view, check the destination domain, matched rule, proxy-group chain, and outbound name. Simply refreshing a page may reuse an existing browser connection, making a new rule appear ineffective. To distinguish local proxy access from remote egress, explicitly specify the local proxy port for a test. The command below checks only whether the HTTP proxy is accepting connections; it does not test TUN routing. Use the port in your runtime configuration and any public site relevant to your troubleshooting.

curl -I --proxy http://127.0.0.1:7890 https://example.com

Your client also determines where configuration settings are managed. For a new installation, start with the recommended Clash Plus on the client downloads page, choosing the build for your Mac’s processor. If you already use Clash Verge Rev or FlClash, you can keep your current client; just confirm which core it runs and which fields that core supports. For a field-by-field walkthrough, see Understanding the config.yaml structure. If you run into a port conflict, permission error, or startup failure, start with the Help Center before moving on to advanced settings, so you don’t mistake an environment issue for a rules problem.

02 / Outbound selection

Proxy group types and practical auto-selection

Open the proxy page and check which proxy group the rules point to, then expand that group to see its members. Proxy groups handle outbound selection, not traffic identification: a rule sends a connection to a group, and the group selects an outbound. Changing a group’s options usually doesn’t require rewriting your rules, making it a useful way to separate routing intent from subscription details. For example, point your rules to a “Work Egress” group, then give that group both a manual and an automatic selection option. Group names are up to you, but every reference must match exactly, including spaces, capitalization, and punctuation.

Know when to use manual selection, automatic testing, or failover

Use select to choose an outbound explicitly or to switch between child groups from a top-level menu. url-test selects an available member based on measured latency. fallback prioritizes member order, usually choosing the first available one. None of these guarantees that a test result reflects the experience of a specific app or service. The test URL reflects only the network path to that address; video, downloads, and business systems may take different routes. For troubleshooting, pin a known-good member first and check the actual connection so automatic switching doesn’t keep changing the test conditions.

load-balance distributes new connections according to a policy; it does not combine the bandwidth of multiple outbounds for a single connection. Frequent changes in egress may trigger reauthentication for login sessions, payment pages, or services that expect a consistent exit IP, so load balancing is best suited to traffic with predictable requirements. For services that need a stable route, create a separate select group and pin its outbound. More layers make connection chains harder to follow. Start with a manual group and an auto-select group for common needs, then split them further only when real use calls for it.

TypeHow it worksBest for
selectUser-selected memberFixed egress or a top-level selection menu
url-testCompare test resultsAutomatically choosing among outbounds for the same purpose
fallbackChoose the first available member in orderPrimary and backup routes
load-balanceDistribute connections according to a policyTasks where connections can use different outbounds

Create a two-level selection with local proxy groups

This example assumes providers/nodes.yaml already exists in the configuration directory and contains a valid proxies list supplied by an existing subscription or local configuration. It does not create remote accounts or replace a subscription. Confirm that the proxy collection loads before adding the two groups to your existing configuration. use references a proxy collection; proxies references an individual outbound or another group. Neither field is for a subscription URL. Use a test URL that is reliably reachable and appropriate for your network.

proxy-providers:
  local-nodes:
    type: file
    path: ./providers/nodes.yaml

proxy-groups:
  - name: Auto Select
    type: url-test
    use:
      - local-nodes
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50
  - name: Work Egress
    type: select
    proxies:
      - Auto Select
      - DIRECT
    use:
      - local-nodes

interval sets how often to run a test, in seconds. tolerance sets the switching threshold, in milliseconds, to reduce unnecessary switching when results are close. Very short intervals increase test requests and wake-ups, which can also use extra data on mobile networks. If a proxy collection has health checks enabled and multiple groups run their own tests, check for redundant probes. Different test layers may serve different purposes; prefer an arrangement you can explain and observe over enabling every check at once.

To verify the setup, route a clearly identified test domain to “Work Egress,” then select “Auto Select” and a specific member in turn. Open a new connection each time and check the proxy chain. A group must not reference itself, directly or indirectly, or it will create a loop. After a subscription update, a group that lists only removed members may be empty or fail to resolve. You can filter the collection when needed, but first confirm on the proxy page that the filter returns members. Automatic selection only helps choose among candidate outbounds; DNS failures, authentication errors, and restrictions imposed by the destination service need separate investigation.

03 / Rule management

Manage rules with rule providers and understand match priority

Open the rules section of the runtime configuration and check whether custom rules come before or after subscription rules. mihomo usually evaluates rules from top to bottom and uses the first rule that determines where the connection goes. Put specific business exceptions first, broader regional rules later, and the final catch-all last. Splitting rules into providers separates content management from routing intent: providers list domains or IP ranges, while the main configuration decides whether they go direct, through a proxy, or are rejected.

Match the rule content to its behavior

rule-providers defines where rules come from, and RULE-SET invokes a provider in the main rule list. behavior: domain is for domain collections, ipcidr for IP ranges, and classical for typed, traditional rule entries. Format and behavior are separate concepts: YAML, text, and binary describe how a file is stored; behavior describes how each entry is interpreted. Read the provider’s format documentation before using it. Don’t infer the contents from the file extension, or load a full client configuration as a rule provider.

Starting with a local file makes a minimal test easier to troubleshoot than connecting a remote source right away. Put the first snippet in rules/local-direct.yaml under the configuration directory, then merge the second into the main configuration. This example uses classical behavior, with each rule specifying a type and match value; it does not set the final policy in the rule file. The main configuration’s RULE-SET sends the entire collection to DIRECT. The catch-all uses the “Work Egress” group created in the previous section; if you use a different name, update the reference too.

# rules/local-direct.yaml
payload:
  - DOMAIN-SUFFIX,apple.com
  - DOMAIN-SUFFIX,example.com
  - IP-CIDR,192.168.0.0/16,no-resolve
# Merge into the main configuration
rule-providers:
  local-direct:
    type: file
    behavior: classical
    format: yaml
    path: ./rules/local-direct.yaml

rules:
  - RULE-SET,local-direct,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,Work Egress

Keep remote updates separate from local exceptions

Once local rules match as expected, change any collections that need ongoing updates to type: http, with a real rule URL from a trusted source, a cache path, and an update interval. interval is measured in seconds; there’s no need to set it extremely low for the sake of freshness. Give each provider a separate local cache path to prevent files from overwriting one another. On first launch, a remote provider must be reachable if no cache exists. Behavior when a cache is present depends on the file state and core, so check both download logs and the provider load result.

Rule providers also need a working network route to download their contents. If a rule URL requires a proxy, but that proxy route depends on the same provider not yet being loaded, startup can get stuck in a dependency loop. Use the client’s resource download settings to select an already working outbound, or set up a clear, reliable route to the provider’s domain. Don’t rely only on the rule page showing a provider name; check load logs, update times, and actual matches. A successful download can still produce unexpected routing if the entry count is unusual, the behavior is wrong, or the file is empty.

no-resolve is often used with IP rules. It means the rule won’t trigger an active domain-to-IP lookup just to see whether it matches. It does not disable DNS for the entire connection or mean that the connection has no address information; requests that already use an IP can still match by address. Domain rules are usually easier to interpret, while IP rules are useful for ranges and connections without a domain. A broad IP rule placed before a business domain rule may send traffic direct or through a proxy too early, so use the rule type shown in the connections view to confirm the actual match order.

For more detail, see Custom rule syntax and priority and Practical split routing for mainland China and overseas traffic. If an exception disappears after a subscription update, adjust where local overrides are merged instead of repeatedly editing the generated remote file. Before sharing a configuration, check that rule sources are trustworthy and that rules won’t route sensitive traffic through an unintended outbound. A rule file parsing successfully only means its structure is readable; it doesn’t mean the policy is right for your needs.

04 / Domain resolution

Optimize DNS settings and split resolution paths

Before changing DNS settings, check the logs to see whether the failure occurs during domain resolution, the connection to a proxy server, or the destination’s response. DNS translates domains into information that can be used for connections, but the browser, operating system, client, and remote proxy may all be involved in resolution. If a domain works from the command line but not in a browser, the browser may be using its own encrypted DNS. A failure to resolve a proxy server’s domain also doesn’t mean the destination site’s DNS is broken. First identify which domain needs resolving and where the request should go, then decide which field to change.

Separate bootstrap lookups from regular DNS queries

nameserver defines the primary upstream. default-nameserver handles bootstrap lookups, such as resolving the DNS upstream’s own hostname; proxy-server-nameserver is used to resolve proxy server hostnames. When an encrypted DNS URL uses a hostname, the core needs the server’s IP before it can connect. If that bootstrap lookup depends on a proxy that isn’t available yet, startup can get stuck. The minimal example below shows how to separate these roles and uses real public resolvers; their reachability varies by network.

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
  proxy-server-nameserver:
    - 223.5.5.5
  fake-ip-filter:
    - "*.lan"
    - "localhost"

Binding to the loopback interface lets local processes or TUN redirection access the resolver while limiting exposure to your local network. Port 1053 is just an example; it must match the port in the runtime configuration and any related redirection settings. Adding listen does not automatically send every macOS DNS query to the core. Check system DNS, TUN DNS hijacking, and app-level resolution separately. If you want other devices to use the local resolver, check the listen address, firewall, access scope, and return route—not just whether it listens on all interfaces.

Route DNS upstreams by domain instead of piling on resolvers

nameserver-policy assigns specific upstreams to domains or matching collections, which is useful for internal business domains, home network names, and services that require a particular resolver. Start with one clearly identified domain, verify it, and then expand the scope. Adding many upstreams at once can increase concurrent requests, make routing less predictable, and complicate troubleshooting. If you use a rule provider as a DNS match condition, confirm the core supports the syntax and that the provider has loaded. Routing rules and DNS upstream settings use different syntax; don’t copy a policy string from one into the other.

If you enable respect-rules, DNS upstream connections follow the relevant routing rules, making separate resolution for proxy server hostnames especially important. Depending on a proxy for DNS before a working outbound is available can create a loop. First ensure proxy server domains can be resolved through an explicitly reachable resolver, then handle regular site lookups. If your configuration also uses fallback and filtering conditions, check how they actually work. This is not simply “try the second server only if the first fails,” so don’t assume traditional primary/backup DNS behavior.

SymptomCheck firstHow to verify
Proxy server hostname failsproxy-server-nameserverWhether the server hostname resolves to an address
Encrypted DNS cannot connectBootstrap lookup and outbound routeUpstream hostname resolution, routing, and port reachability
Internal domain is unreachablenameserver-policyWhether queries go to a server that can resolve internal domains
Browser and command-line results differApp-level DNS and connection reuseWhether the app bypasses the system resolver

When testing DNS, distinguish real-IP mode from Fake-IP mode. In Fake-IP mode, seeing an address from the mapping range is usually expected; it doesn’t mean resolution failed just because it isn’t the site’s public IP. After changing DNS, open a new connection and clear relevant caches if needed. Clearing every cache at once can erase useful diagnostic clues and cause temporary disruption. Choose resolvers based on your current network, privacy needs, and destinations; there’s no need to copy a public DNS setup by default. For local network services, keep the original DNS settings available so you can restore them if changes disrupt your work network.

05 / System traffic

How TUN, system proxy, and Fake-IP work together

After enabling the system proxy, check whether the apps you care about follow it. Consider TUN only if some apps or command-line tools don’t. A system proxy provides apps with HTTP, HTTPS, or SOCKS connection details; whether they use it depends on the app. TUN uses a virtual network interface and routes to capture a broader range of IP traffic. These are not two acceleration switches that must always be enabled together. Keep one verified connection method, confirm that the target app’s traffic reaches the core, then expand coverage if needed.

Check system permissions before enabling TUN

In your macOS client, find the TUN or service mode setting. Follow the prompts to install the helper service and authorize it, then check the runtime logs again. Button names and authorization flows vary by client and macOS version; follow the current UI and don’t disable system security features to work around an authorization issue. Running the core independently usually requires sufficient network permissions. If TUN fails to start, check permissions, virtual interface creation, and routes first. Whether the remote proxy works is a separate question to test afterward.

# Merge into your working configuration; keep the working DNS settings from the previous section
tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

auto-route sets up routes for traffic capture, auto-detect-interface detects the outbound interface, and stack selects the network stack used by TUN. The example uses mixed; if you encounter compatibility issues, compare other stacks supported by your core instead of changing MTU, DNS, rules, and system routes all at once. dns-hijack captures regular DNS queries that enter the relevant path. It does not turn an app’s HTTPS request to an encrypted DNS service into a regular DNS query just because it is a network request.

Why Fake-IP addresses can still reach websites

Fake-IP assigns a mapped address to a domain. When a connection arrives, the core uses the mapping to recover the domain and apply rules. This lets it retain domain information without first resolving the destination to its real address, which helps with domain-based routing and can reduce the influence of some local resolution paths. The mapped range is not the network where the actual website lives, and it doesn’t remove the need to connect to the site. How proxy and direct outbounds resolve domains and establish remote connections still depends on the protocol, DNS settings, and outbound behavior.

fake-ip-filter exempts specified domains from virtual address mapping. It’s useful for services that genuinely need real resolution results, such as some local network discovery services or apps sensitive to address values. Add an exception for the specific domain causing trouble and test whether the feature works again; don’t add every domain to the filter just to hide a symptom. If you change the Fake-IP range, make sure it doesn’t conflict with your local network, corporate VPN, or other virtual interfaces. Apps with an old mapping cached may keep using the old address, so account for connection and DNS cache lifetimes after making changes.

A command with --proxy cannot verify TUN by itself: an explicitly proxied request may bypass the system traffic-capture path you need to test. Choose an app that doesn’t have a separate proxy configured, open a new connection, and look for it in the client’s connections view. Then test local network devices, waking from sleep, and switching networks. If logs still show the old interface after switching from Wi-Fi to Ethernet, check interface detection and route recovery first. Running TUN in multiple proxy clients at once can cause route conflicts, duplicate DNS hijacking, or loops. Keep only the traffic-capture mechanism you’re testing enabled.

If enabling TUN cuts off all network access, roll back in reverse order: turn off TUN first, check the system proxy state, then restore the original DNS and network connection. Don’t immediately delete the entire configuration; that turns a diagnosable problem into a reinstall. An enabled UI switch only shows the intended setting, not that the virtual interface, routes, and DNS all started successfully. Check authorization logs, interface state, and destination connections together to tell an ingress problem from an outbound problem. For basic recovery steps, see the Help Center.

06 / Connection identification

Domain sniffing: what it does, its limits, and how to troubleshoot it

Open the connections view and find connections that genuinely lack a domain before deciding whether sniffing is needed. Some apps connect directly to an IP or use their own resolution path, so the core receives a connection without the original domain. Domain sniffing can extract a domain from some protocol handshakes or plaintext requests to help with rule matching. It isn’t a general-purpose tool for inspecting all encrypted traffic, and it won’t turn every IP connection back into a domain. The result depends on whether the target carries identifiable information, the protocol is supported, and the handshake is visible.

Start with conservative sniffing settings before overriding the destination

HTTP requests may contain host information, TLS handshakes may include a server name, and some QUIC handshakes may also provide identifiable clues. Modern encrypted handshakes, non-standard protocols, IP-only services, and unreadable handshakes all limit identification. The sniff setting specifies which protocols and ports to inspect; it doesn’t mean all traffic on those ports uses that protocol. The snippet below preserves the original connection destination and only adds sniffing options, making it useful for checking whether sniffing improves rule matching.

sniffer:
  enable: true
  force-dns-mapping: true
  parse-pure-ip: true
  override-destination: false
  sniff:
    HTTP:
      ports:
        - 80
        - 8080-8880
    TLS:
      ports:
        - 443
        - 8443
    QUIC:
      ports:
        - 443

parse-pure-ip allows sniffing attempts on IP-only connections with no domain. force-dns-mapping relates to how DNS mappings are handled. Whether to replace the destination address is controlled by override-destination; that is a separate decision from obtaining a domain for rule matching. Keeping the original destination can prevent unexpected changes when an app has chosen a specific address. If you do need to override it, test the specific service. This is especially important for apps that depend on a particular CDN address, dedicated gateway, or fixed route: correctly identifying a domain doesn’t necessarily mean rewriting the destination is appropriate.

Compare rule evidence using the same connection

For troubleshooting, pin a proxy group member, then choose a specific service. Turn sniffing off, open a new connection, and note the destination, rule type, and outbound chain. Turn sniffing on and repeat the same steps. Don’t compare two different pages or connections that have already been reused. If the logs don’t show a domain, that doesn’t necessarily mean the setting failed; traffic may not be reaching the core, the port may be outside the sniffing range, or the protocol may provide nothing to extract. Verify the traffic path first, then protocol identification, and finally rules. Reversing that order only adds complexity.

Sniffing results are not a substitute for DNS query results. A connection’s server name may identify only the entry point, while the service subsequently accesses content under a different domain; the same IP can also host multiple domains. Reverse lookup cannot reliably recover an app’s original intent from an address alone. Whenever possible, use verifiable collections of service domains in rules rather than treating one captured hostname as a permanent boundary for the whole service. For login, media, and update services, also consider whether redirect and resource domains use different outbounds.

If enabling sniffing causes an app’s handshake to fail, adds connection delays, or sends it to the wrong endpoint, turn off destination overriding first, then narrow sniffing for that service. Fields such as domain-based sniffing exclusions, where supported by the core, can create local exceptions; check the documentation for your core’s exact syntax. Don’t reset DNS, TUN, and sniffing globally because of one app issue—that removes the basis for comparison. Keep the working path, change one identification setting, and check the logs to see whether it affected the connection.

When sharing troubleshooting details, include only the necessary destination domain, rule type, and error message instead of uploading your full connection history. Domains and access times can reveal work or personal activity. To check rule syntax, return to the rule provider section and see whether an earlier IP rule took precedence over the domain rule. If the connection isn’t listed at all, go back to the TUN and system proxy section and check the app’s network path. Sniffing should address a specific identification gap, not serve as a default switch for every connection problem.

07 / Configuration maintenance

Local overrides and merging multiple subscriptions

Open the configuration management page and find the client’s override, extension, or merge feature before deciding where to put custom settings. Remote subscriptions are updated data sources; editing a downloaded file directly means your changes can disappear the next time it refreshes. A more reliable division is to let subscriptions provide proxy data and use local overrides for ports, DNS, business rules, and proxy group structure. Clients differ in how they name these features and apply them, so don’t assume the same override file behaves identically everywhere.

Understand how objects and lists are merged

Configuration maps and lists need different merge behavior. Maps may be merged recursively by field or replaced entirely; lists may be prepended, appended, concatenated, or replaced. Rule order determines match priority, so a successful append doesn’t necessarily mean an exception will take effect. A custom direct rule placed after MATCH will never see the traffic. Client settings may also override DNS fields, so check the final runtime file rather than just what’s saved in the override editor.

Start with a small local exception and confirm where it appears in the runtime configuration before adding the full set of rules. The snippet below shows the intended final rule order; it is not a universal override file format for every client. It assumes the “Work Egress” group from the previous section and puts the local host and private ranges before broader rules. Whether those addresses should go direct depends on your network. Check corporate ranges, addresses assigned by other VPNs, and container networks individually rather than using one overly broad range to hide a routing issue.

# Rule order in the intended runtime configuration
rules:
  - DOMAIN-SUFFIX,lan,DIRECT
  - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - GEOIP,CN,DIRECT
  - MATCH,Work Egress

Keep proxy providers separate when merging subscriptions

Before merging subscriptions, check whether each source provides a complete Clash configuration or content that can be read directly as a proxy collection. A full configuration includes DNS, rules, and other top-level fields; you can’t simply put it where a proxy list is expected. Setting each usable source up as a separate proxy-providers entry and referencing it from local proxy groups is usually easier to maintain. Use a unique provider key and cache path for each source, and have business rules reference stable local group names. Then changes to an upstream server list won’t require frequent edits to your main rules.

Duplicate proxy names are a common merge hazard. Two sources may use the same name for different servers, causing duplicates or ambiguous references when you manually combine proxies lists. Keep each source separate first, check its members, and only then decide whether to use a supported naming option. Don’t rename nodes but leave old group references in place, or concatenate duplicate top-level keys from multiple files. If a conversion script is unavoidable, use an interface explicitly supported by your current client and keep the original files so you can roll back.

ContentWhere to maintain itWhat to check after an update
Servers and authentication settingsOriginal subscription or separate proxy providerProvider loads and members are available
Business rule exceptionsLocal overrides or a local rule providerWhether it comes before broader rules
DNS, ports, and traffic capture settingsClient settings or a clearly defined local layerFinal runtime values and listening state
Public domain listsSeparate rule providerFormat, cache, and download path

After making changes, run a subscription update and check that custom settings are still present. This is easier to troubleshoot than discovering a broken rule days later. An exported runtime configuration may not contain the full maintenance logic: it can include only the merged result, without override order, scripts, or external provider sources. Back up both the configuration data and how it is generated, but keep sensitive subscription URLs secure. When showing your configuration to someone else, share a minimal reproduction with account details removed, not your full personal backup.

If your client lacks the merge features you need, a stable main configuration with local provider files may be a better choice than adding an opaque subscription conversion chain. If conversion is necessary, understand that third-party services may have access to information in your subscription. For the differences between importing from a URL, clipboard, or local file, see Subscription formats and import methods. This section focuses on maintaining your setup after import. A good maintenance approach makes updates repeatable, preserves exceptions, and keeps the final result understandable—not necessarily more complex.

08 / Local control API

External dashboards and a safe configuration workflow

If you need an external dashboard, first check the external-controller listen address in the runtime configuration, then confirm where the dashboard runs. The controller API can list connections, switch groups, and manage core state; it isn’t the proxy port apps use to reach websites. Connecting a dashboard to a 7890-style mixed port will usually not get a controller response. For local use, prefer a loopback address and keep the client’s existing management path. A graphical client may depend on the same API, so changing the port arbitrarily can disconnect the UI from the core.

Configure the local API and dashboard assets separately

external-ui specifies the directory for local static dashboard files, which should already contain compatible frontend assets. The core doesn’t create a complete dashboard just because this directory is set. The snippet below shows how the local listen address and directory relate. Before merging it, confirm the port is free and that your client allows changes to the controller API. If authentication is required, set a strong, unique value locally using a method supported by the client, then use the same value in the dashboard. Never put a real password in a public example, screenshot, or shareable configuration link.

# Local access only; put the dashboard files in the specified directory first
external-controller: 127.0.0.1:9090
external-ui: ./ui

A dashboard usually needs the controller address, port, and authentication details. If the API refuses the connection, first check that it’s listening. If authentication fails, check the password. Only investigate CORS, secure context, or mixed content restrictions if the browser fails but the API is reachable from the command line. A loopback address always points to the device making the request: entering 127.0.0.1 in a phone’s browser won’t connect to your computer. For cross-device access, use a controlled, secure method and understand the extra risks of widening the listen scope instead of exposing the management port directly to the public internet.

Start with read-only checks before making changes

When first connecting a dashboard, check the current mode, proxy groups, and connection list to confirm it’s attached to the intended core instance. If two clients are running on the same computer, the dashboard may be connected to an old process, making a group change appear to work without affecting current traffic. Check the listening port, active configuration, and a newly opened connection to avoid that mistake. The command below makes a read-only request to the local version endpoint. Its response confirms that the API is reachable. If authentication is enabled, include the authorization header used on your system; don’t mistake an unauthenticated access denial for a broken core.

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

After changing a group member in the dashboard, check whether the change needs to be saved persistently. Runtime state, client configuration, and remote subscriptions are separate layers; whether a selection survives a restart depends on the core configuration and client. Don’t assume that an API write also updates your local override file. If you automate changes with a script, verify the response and target group name before making a narrowly scoped change. API errors, renamed groups, or a switch to another active configuration can make a script act on the wrong target. Automation should make tasks repeatable and reliable, not skip checks.

Use the connection list to verify domains, rules, and proxy chains; use logs to investigate download, resolution, and handshake errors. You can temporarily increase log verbosity while debugging, but restore the usual level afterward to avoid accumulating excessive connection records. Choose dashboard sources carefully too: a page with controller access may read connection data and perform management actions. Use trusted local assets or a deployment you understand. If the browser reports certificate, CORS, or content security issues, check how the dashboard connects before loosening access for all origins just to make it load.

Finish with an end-to-end check: subscriptions update, proxy and rule providers load, system proxy or TUN captures traffic as expected, DNS resolves common domains, local services remain accessible, and the dashboard controls the current instance. Test waking from sleep and switching networks too, so you know the setup works beyond a fresh launch. If a step fails, return to the relevant section of this guide and narrow down the cause. For first-time installation and basic imports, follow the quick-start guide; for client selection, return to the downloads page; for general troubleshooting, visit the Help Center. A configuration you can understand and restore is easier to maintain than one with every advanced feature enabled.