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.
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.
| Type | How it works | Best for |
|---|---|---|
select | User-selected member | Fixed egress or a top-level selection menu |
url-test | Compare test results | Automatically choosing among outbounds for the same purpose |
fallback | Choose the first available member in order | Primary and backup routes |
load-balance | Distribute connections according to a policy | Tasks 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.
| Symptom | Check first | How to verify |
|---|---|---|
| Proxy server hostname fails | proxy-server-nameserver | Whether the server hostname resolves to an address |
| Encrypted DNS cannot connect | Bootstrap lookup and outbound route | Upstream hostname resolution, routing, and port reachability |
| Internal domain is unreachable | nameserver-policy | Whether queries go to a server that can resolve internal domains |
| Browser and command-line results differ | App-level DNS and connection reuse | Whether 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.
| Content | Where to maintain it | What to check after an update |
|---|---|---|
| Servers and authentication settings | Original subscription or separate proxy provider | Provider loads and members are available |
| Business rule exceptions | Local overrides or a local rule provider | Whether it comes before broader rules |
| DNS, ports, and traffic capture settings | Client settings or a clearly defined local layer | Final runtime values and listening state |
| Public domain lists | Separate rule provider | Format, 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.