mihomo Advanced Configuration

Proxy Groups · Rule Providers · DNS · TUN · Sniffing · Overrides · External Controller

Use this page to look up configuration details and troubleshoot issues, with each module explained in terms of mihomo fields. For first-time setup, importing a subscription, and enabling the system proxy, start with the quick-start path in the Getting Started Guide. Once you have a working connection, adjust the settings here as needed. To choose a client, visit the download page. Clash Plus is a good place to start on desktop and mobile; available settings depend on the client.

Most YAML snippets below are partial examples, not complete configurations with proxy credentials. Keep your existing proxy definitions when merging, and include each top-level field only once. Back up a working configuration before every change, modify one module at a time, then check the logs and test an actual connection. Graphical clients may generate runtime files; make changes through the client's persistent override or configuration settings, not a temporary file.

Proxy Group Types and Examples

Separate rule targets from actual proxy exits

Rules decide which target handles a connection; the proxy group then determines the actual proxy exit for that target. Names in rules must match the proxy, group, or built-in policy exactly, including capitalization and spaces. Start by choosing stable names for your traffic groups, then let subscription updates change only their members. That way, changes to individual proxies won't require rewriting every rule.

select is for choosing an exit manually. It won't switch to another member just because the selected one is temporarily unavailable. Client dashboards often save your selection, but whether it persists depends on the configuration name and client implementation. When troubleshooting, look beyond the group name: expand it, check the selected proxy, and follow the full policy chain for a new connection. Existing long-lived connections usually won't move immediately.

Choose an automatic strategy based on your needs

url-test selects a member based on probe results and suits traffic where the exit can change. A probe measures access to a specific URL; it doesn't represent performance across all sites or protocols. A proxy that performs well against the test URL may still be unsuitable for a particular service. tolerance can reduce frequent switches caused by small differences, but it doesn't guarantee a fixed exit. Use a separate manual group for services that need a consistent session identity.

fallback prioritizes member order: among members considered healthy, it prefers the one listed first. Use it when you have a clear primary and backup, not when you want the lowest probe time on every selection. load-balance distributes connections across multiple members; it doesn't combine their bandwidth for a single download. Avoid applying rotation blindly to logins, payments, or services that restrict access by source address.

TypeHow it selectsKey limitation
selectUser selectionUnavailable members require manual attention
url-testProbe results and toleranceThe test target may not reflect real-world traffic
fallbackAvailability and list orderFailover depends on health checks
load-balanceConfigured distribution strategyDoes not combine bandwidth for a single connection

Use two layers to separate manual choices from automatic testing

A practical setup uses a manual group on the outside and an automatic group inside it. The outer group offers choices such as automatic selection, a fixed proxy, and direct access; the inner group contains only proxies to be tested. Don't add the outer group back into the inner one, or you'll create a circular reference. Keep nesting shallow: being able to trace a rule target to the actual exit in two or three steps is easier to maintain than a maze of groups.

The example below references only the built-in DIRECT. It illustrates how groups can reference one another, but does not provide a remote proxy exit. To use it, add the names of real proxies from your configuration to the automatic group's members, then keep or remove the direct option as needed. The test URL uses HTTPS, and the probe interval is in seconds. Whether the test URL itself is reachable also affects health checks.

proxy-groups:
  - name: PROXY
    type: select
    proxies:
      - AUTO
      - DIRECT
  - name: AUTO
    type: url-test
    proxies:
      - DIRECT
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50

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

If your proxies come from proxy-providers, groups can reference a provider with use instead of duplicating a long list of member names. First confirm that the provider loads successfully, then check that the group contains the expected members. Add filters gradually, starting broad and narrowing down. If a filter is too restrictive, the subscription may update successfully while the group has no usable members. Changing probe settings won't fix an empty group.

To verify a proxy group, check its type, candidate members, and current selection in the dashboard, then start a new connection for the service you're testing. A successful probe confirms only that the health-check path works; it doesn't verify the service itself. If switching groups has no effect, close the app's existing connections or reopen the app and test again. There's no need to restart every network service right away. For the basics of each mode, see the proxy modes guide.

Managing Rules with Providers

Rules determine order; providers supply match data

rules defines the processing order; rule-providers holds reusable match data. After moving a large set of domains into a provider, the main configuration still needs to reference it with RULE-SET and specify the matching policy. Declaring a provider doesn't automatically add it to traffic routing. The core typically checks rules from top to bottom and applies the first match, so the order of local exceptions, service rules, and the final catch-all matters more than how many files you split the rules across.

Start with a small number of clearly named sets, such as development services, local network addresses, and services that need a specific exit. Don't maintain the same domains in multiple sets just to make the categories feel complete. If sets overlap, state which rule takes priority and why. Every new exception should answer three questions: What does it match? Which policy handles it? Why is it here? If those answers aren't clear, it'll be hard to know whether the rule can be removed later.

Match behavior to the file format

Use behavior: domain for domain entries, ipcidr for address ranges, and classical for classic rules that include rule types. These aren't interchangeable labels. Putting full DOMAIN-SUFFIX syntax in a domain set, or bare domains in a classical set, can cause loading errors or unexpected matches. Check the file format before choosing the behavior; don't guess based on the filename.

The format must also match the actual data. YAML rule sets typically use a payload array; text files are read line by line; binary rule sets have their own generation requirements and can't be created by simply changing a file extension. If the same domain source is available in multiple formats, choose one the core explicitly supports and use a file extension that reflects its actual contents. Parsing errors in the logs are more informative than whether a browser can open the download URL.

# Merge into the main configuration; adjust the position of rules to fit existing rules
rule-providers:
  development:
    type: file
    behavior: domain
    format: yaml
    path: ./rules/development.yaml

rules:
  - RULE-SET,development,PROXY
  - MATCH,DIRECT
# Save as rules/development.yaml in the core's configuration working directory
payload:
  - '+.github.com'
  - '+.githubusercontent.com'

Move from local testing to remote updates

The example assumes a policy named PROXY already exists. Relative paths are usually based on the core's working directory, not the directory of the file open in your editor. Test behavior and matching with a local file first, then switch to a remote provider to separate format issues from network issues. For testing, start a new connection to a domain in the rule set and confirm in its connection details that the provider rule matched—not just a catch-all rule that happens to use the same exit.

For a remote source, set type: http, the source URL, a cache path, and an update interval. Use the URL provided by the maintainer; a webpage displaying the rules isn't necessarily the raw rule file. Set the update frequency to match how often the source changes. Fetching a list every few minutes when it changes only every few days usually adds requests and troubleshooting noise. Keep URLs containing account information in your local configuration, not in public screenshots, shared repositories, or bug reports.

When a rule update fails, first distinguish a download failure from a parsing failure or a reference error. For download failures, check that the source is reachable and that the download uses a working outbound route. For parsing failures, check whether the response is a webpage, an error message, or a different format. For reference errors, confirm that the provider name matches the name used by RULE-SET. Cached data may keep traffic working temporarily, but that doesn't mean updates are healthy; also check the last update time and loading logs.

Put domain rules that require resolving the target address ahead of geographic or network-range rules. For address rules that should not trigger an additional lookup, use no-resolve where appropriate; it isn't a universal suffix for every rule. Connections with a real address can still match address rules. Connections with only a domain and no resolved address may skip those checks. Before changing this setting, identify which lookup you want to avoid.

Keep a validated local set of exceptions, and treat subscription content as external input rather than the sole source of your personal rules. After an update, test a few representative connections before using the new rules more broadly. If traffic is routed incorrectly, note the matched rule and target policy before deciding whether to edit the set or change rule order. Replacing MATCH with a different exit may hide the issue, but it will also change many connections that were working correctly.

DNS Configuration

Trace each type of DNS request separately

DNS troubleshooting starts with identifying who is querying, what they're looking up, and where the request goes. An app may use the system resolver or issue encrypted DNS requests itself; the core also needs to resolve proxy server domains. Even if all three use the same upstream, they may take different paths. Trace the app-to-core, core-to-upstream, and core-to-proxy-server paths before changing fields, so bootstrap lookups don't get confused with regular DNS traffic.

default-nameserver is primarily used to resolve DNS upstream hostnames and establish a starting point for encrypted DNS. nameserver lists the upstreams for regular queries, while proxy-server-nameserver lets you choose a resolver for proxy server hostnames. The latter is especially useful for avoiding startup dependencies before a proxy is available. If resolving the proxy's domain also requires using that proxy, you can create a loop: the configuration loads, but no outbound connection can be established.

Start with a minimal, easy-to-understand DNS setup

The snippet below shows a basic setup with a local listener and Fake-IP. A regular UDP upstream and an HTTPS upstream take different network paths, and the former does not encrypt traffic in transit. This example illustrates the roles of bootstrap and regular DNS; it isn't a one-size-fits-all setup. First confirm that your chosen resolver is reachable on your network, then consider encryption, policy routing, and fallback options. Adding more upstreams doesn't automatically make results more reliable.

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

Listening on 127.0.0.1:1053 means the core provides a local DNS service; it doesn't mean the system will automatically use it. Standard system DNS settings generally can't specify an arbitrary port, so using this listener requires DNS interception by the client, TUN redirection, or another explicit forwarding path. If the system is still querying its original resolver, it's no surprise that changing nameserver has no visible effect. Confirm that queries actually reach the core before comparing upstream results.

Choose resolvers by domain, and add fallback logic carefully

nameserver-policy assigns resolvers based on conditions such as the domain, which is useful for internal company domains, home network devices, or services with specific DNS requirements. Send internal domains to a resolver that can return internal addresses, not a public service. Domain-based DNS policies decide which resolver to use; they don't determine the final network exit. After confirming that DNS returns the right address, verify the connection's rules and proxy group separately.

fallback isn't simply a second address used only when the primary resolver times out. It works together with fallback-filter to evaluate results and may trigger additional queries. Filters that don't suit your network can replace a usable result with an unsuitable one. Add this layer only when you can explain which responses need to be replaced. Otherwise, start with a small number of reliable upstreams to make the source of problems easier to identify.

With respect-rules enabled, DNS upstream connections can follow routing rules, but you also need to handle startup dependencies such as resolving proxy server domains. Don't force every DNS request through a proxy group that isn't available yet. When testing, record the exit used for upstream DNS and the exit used for regular traffic. They can differ, and often should. For a closer look at this field and DNS fallback, see DNS Fields Explained.

Troubleshoot encrypted DNS failures by symptom. If the error is a name resolution failure, check bootstrap DNS first. If a hostname resolves but the handshake fails, check the system clock, certificate trust, and connection path. If the upstream connects but returns unexpected results, check the domain policy and server response. Don't disable certificate verification to mask network or time problems, and don't swap several upstreams without evidence. Change one variable at a time and keep the query reproducible.

Caching can make changes appear to have no effect. The system, browser, and core may all cache DNS results, and apps may reuse existing connections. Before testing, close the target app's old connections, clear relevant caches using the client-provided controls, and query again. A command-line query to the local listener and opening a webpage in a browser test different paths. If results differ, check whether the browser uses its own resolver before concluding that the core configuration isn't working.

Finally, check the address family. Disabling IPv6 DNS responses doesn't disable IPv6 across the whole system; apps may still use cached addresses or resolve names themselves. Conversely, allowing IPv6 responses requires a working IPv6 route. If some sites take a long time to load, compare IPv4 and IPv6 connection results before deciding which layer to change. The goal is to return results suited to the network path, not to populate every available field.

TUN Traffic Interception and Fake-IP Mapping

Fake-IP links domains to connections; it isn't a remote proxy exit

In Fake-IP mode, the core can return a mapped address to an app and keep the association between that address and the domain. When the app connects to the mapped address, the core restores the domain and applies routing and outbound handling. A mapped address is neither the destination server's public IP nor a proxy server address. If you see a result in the 198.18.0.0/16 range, don't assume DNS is broken. Check whether the core captured the connection and restored the expected domain.

Fake-IP and TUN are two separate components. Fake-IP handles resolution and domain mapping; TUN receives traffic through a virtual network interface. They are often used together, but neither replaces the other. Enabling Fake-IP alone doesn't route every app through a proxy; enabling TUN alone doesn't guarantee that every connection has domain information. Verify the DNS path, virtual interface, and rule processing together rather than treating one switch as a complete traffic interception solution.

Enable TUN with permissions, routes, and DNS in mind

TUN often requires administrator privileges, a service component, or system authorization. Setup and permission handling vary between clients such as Clash Plus, Clash Verge Rev, and FlClash, so install any required components using the documentation for your client. enable: true in the configuration only asks the core to turn TUN on. If the system refuses to create the interface or add routes, traffic still won't be intercepted. Check the logs for interface and route creation results instead of repeatedly toggling the setting.

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

Use this snippet alongside an enabled dns configuration. auto-route asks the core to set up the relevant routes, auto-detect-interface helps identify the outbound interface, and dns-hijack sends matching regular DNS traffic to the core. It doesn't automatically intercept all encrypted HTTPS DNS; encrypted DNS built into an app needs separate investigation. Check the runtime logs and current core documentation for actual support on your platform and network stack.

system, gvisor, and mixed are network stack options, not a ranking of quality. They involve different trade-offs in protocol handling, system integration, and compatibility. If a specific app has issues, compare stacks while leaving other settings unchanged. Don't also change DNS, routing, and MTU at the same time. Changing one variable makes it possible to tell whether the network stack or another setting made the difference.

Handle LAN, VPN, and mapping exceptions

LAN devices usually need direct access to their real addresses, including printers, casting devices, and internal admin pages. fake-ip-filter can prevent matching domains from receiving mapped addresses, but it doesn't automatically make their connections direct. The resolver must also be able to return the correct internal address, and a rule must select the right exit. Adding a filter without a working internal DNS resolver often removes the mapped address but still leaves the device unreachable.

SymptomCheck firstHow to verify
All network access stops when enabledInterface, default route, proxy loopDisable TUN and compare with the baseline network
Internal devices are unreachableInternal DNS, direct rules, route conflictsTest the real address and device domain separately
Some apps aren't interceptedConnection address family, app-specific DNS, excluded routesCheck whether the app appears in connection records
Problems start when another VPN is enabledOverlapping subnets, interface priorityEnable each one separately, then compare route tables

Corporate VPNs, virtual machines, containers, and other proxy software may all add routes. Before running them alongside TUN, note each one's subnets and check for overlap with the Fake-IP range. Automatic interface detection may also pick the wrong outbound interface on a multi-NIC system. Adjust settings based on the actual interfaces and routes instead of copying interface names from another device. Follow your organization's device management requirements before changing corporate network settings, and avoid disrupting existing access controls.

Some apps use resolved addresses for protocol validation, LAN discovery, or displaying addresses, and can't work with mapped results. Keep compatibility fixes narrowly scoped: identify the affected domain, add the necessary filter, then check that other domains are still mapped as expected. Filtering every domain may seem simpler, but it changes the entire domain recovery mechanism and can force connections that previously matched by domain to rely on real addresses and sniffing instead.

A useful verification order is: confirm the system proxy works with TUN off; enable TUN; check the interface and routes; confirm DNS requests reach the core; then test apps that don't follow the system proxy. If something breaks, roll back in reverse order. A webpage opening in a browser doesn't prove that all system traffic is intercepted—the browser may still use the system proxy. Likewise, one mapped-address result doesn't prove that all traffic reaches the core.

Domain Sniffing and Rule Matching

Sniffing supplements DNS; it doesn't replace it

When a connection reaches the core, it may have only a destination address and no usable domain. This can happen when an app uses its own resolver, traffic is transparently intercepted, or the app connects to a cached address. Domain sniffing attempts to extract host information from the initial data of certain protocols, giving the core a chance to apply domain-based rules. It's useful for filling in missing information, but it can't identify domains in every kind of traffic or read all the contents of encrypted connections.

HTTP can include a host field, and a TLS handshake may expose a server name when conditions allow. QUIC requires the core to recognize relevant handshake data. If the client hides the server name, uses a protocol the core doesn't support, or provides too little data to identify the host, sniffing may not return a result. In that case, let rules fall back to an address-based match or catch-all policy; a failed sniff doesn't mean the proxy exit is unavailable. Expanding the port range can't reveal information the protocol doesn't expose.

Start with a limited range of ports

The snippet below enables sniffing for common HTTP, TLS, and QUIC service ports, while disabling destination rewriting based on the sniffed domain. This lets you observe detection results before deciding whether to intercept destination resolution as well. When merging it, check whether the client has already generated a sniffer field; don't duplicate a top-level key. Test one or two known web requests first, check how the domain appears in the logs, then expand to more apps.

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 connections that use only an IP address. This can help with some traffic that lacks a domain association, but doesn't guarantee detection. force-dns-mapping relates to continuing sniffing attempts in relevant DNS mapping scenarios; it doesn't replace DNS listening and forwarding configuration. Don't infer from the field name that it forces every app to use the core's DNS. Whether a request reaches the resolver still depends on the actual network path.

Evaluate override-destination separately. When enabled, the core can use the sniffed domain to change how the connection's destination is handled, rather than merely adding information for rule matching. This may alter the connection path for apps that use custom DNS, fixed addresses, or a specific entry point. Leaving it off reduces the number of variables. Enable it only when you have a clear need and understand the effects on resolution and routing; then limit it carefully by domain or protocol.

Compare domain sources to see whether sniffing is needed

For testing, close the target app's existing connections, start a new one, and check the domain, destination address, and matched rule in the connection details. Existing connections don't perform a new handshake just because sniffing was enabled. If the domain was already restored from a Fake-IP mapping, it's normal for the matched rule to stay the same. In that case, sniffing may add little value; there's no need to enable every option just to fill out the configuration.

If enabling sniffing breaks a particular service, first compare its behavior with sniffing disabled rather than changing the entire DNS setup. Use supported skip-domain or similar scope settings to narrow what gets processed, but base exceptions on domains you've actually observed instead of copying a block from another configuration. An overly broad forced scope makes more traffic wait for protocol detection; an overly broad skip scope may send connections that need domain rules back to address-based routing.

A port number doesn't uniquely identify a protocol. Some apps run custom protocols on common web ports, while some services offer TLS on nonstandard ports. Port restrictions help control scope, but don't guarantee that every connection within that range can be identified. Confirm the actual protocol before including a custom service. Adding every port usually just expands the troubleshooting surface; it won't reveal hidden handshake data or enable unsupported detection.

QUIC is commonly associated with UDP, and some apps fall back to TCP when conditions aren't met. If you test only whether a webpage opens, you may miss a protocol change. Check the connection record to see which transport was used, then compare sniffing results and rule matches. Don't block all UDP just to make the logs look tidy; voice, real-time communications, and some apps may depend on it. Handle the specific service, not the appearance of the logs.

Sniffing also raises privacy and debugging considerations. Extracted domains may appear in connection records or debug logs, so check for internal service names before sharing screenshots or reports. Routine troubleshooting usually needs only the rule type, policy chain, and an anonymized description of the destination—not a full browsing history. More extensive logs don't automatically make issues easier to solve; a clear record of what changed often helps more.

Local Overrides and Merging Subscriptions

The runtime configuration is what matters

Graphical clients often merge subscription content, global settings, and local overrides before passing the result to the core. The editor shows the inputs; the runtime configuration is the result. The same DNS field may appear in both a subscription and the client settings, with the merge order deciding which one takes effect. Before troubleshooting, find the client's runtime configuration preview or export option and inspect what the core actually received. Otherwise, you may keep editing a file that gets overwritten later.

A useful division of responsibilities is: subscriptions provide proxies and required provider details; local settings manage service groups, rule priorities, DNS, and device-specific options. Device-specific fields include listen addresses, ports, TUN, and the controller, so they shouldn't be copied unchanged between systems. Before syncing, separate reusable routing intent from settings tied to a particular device. A file importing successfully doesn't mean its routes and permissions will work on another device.

Don't assume every merger follows the same rules

Different clients may merge maps, arrays, and scalar values differently. Maps may merge recursively or be replaced wholesale; arrays may be appended, prepended, or overwritten. The core doesn't standardize client-side merge behavior. Pay particular attention to the rules array: if local exceptions are appended after the original MATCH, they'll never take effect. Check the final order instead of assuming the change worked because the interface says it was saved.

The snippet below shows local intent that could be applied through an override: use a fixed local listener and rule mode, and request that selections be saved. It's not a universal override file format; place these fields in the YAML merge entry point supported by your client. If that entry point requires a script or a dedicated structure, follow its format—don't paste YAML into a script editor. Verify the effect of profile by checking the actual state after a restart.

mixed-port: 7890
allow-lan: false
mode: rule

profile:
  store-selected: true
  store-fake-ip: true

Duplicate keys in the same YAML map should be removed. Some parsers report an error; others may keep only the last value. Don't rely on this inconsistency to implement overrides. Indent with spaces, and quote strings that might otherwise be interpreted as special syntax. Run a syntax check before loading the file into the runtime. Successful YAML parsing confirms only that the syntax is valid; policy references, file paths, and rule behavior still need separate verification.

With multiple subscriptions, isolate sources before handling names and references

Multiple sources may contain proxies, groups, or providers with the same name. Concatenating them directly can cause conflicts or make a rule reference the wrong object. A safer approach is to give each source its own clearly named provider namespace, then let local groups select members with use. If you need to rename a proxy, update every reference as well. Changing only its displayed name while leaving group references untouched can cause startup errors or empty groups.

Merging multiple sources doesn't mean copying full DNS and rule sections from each one. Decide which source has final control, then treat the others as proxy data. If a subscription includes rules that must be retained, review them individually and place them deliberately rather than letting them override all local policies. The more sources you use, the more important it is to know how to remove or disable each one. Before disabling a provider, make sure every group that references it will still work.

In a terminal environment, use the core's configuration test before deployment. Replace the directory in the command with your actual configuration working directory; the command below assumes the current directory contains the configuration and its dependencies. A test can't replace real network access, but it can catch field, reference, and file-loading issues in advance. If your graphical client has a built-in configuration checker, use it before reloading rather than making an unverified configuration the startup default.

mihomo -t -d . -f ./config.yaml

After automatic subscription updates, spot-check the final configuration's listen ports, the first few rules, the final catch-all, and key group members. These are the most likely places to reveal a changed merge order. If an update causes problems, revert to the last working input and compare the generated results; don't simply disable automatic updates indefinitely. Keep an understandable change log—for example, which domain exception was added or where a group now gets its members—to make future troubleshooting easier.

When syncing across devices, sync only the files you need and exclude logs, caches, and temporary configurations generated by each device. Subscription URLs and proxy credentials are sensitive and don't belong in public repositories. See Syncing Configurations Across Devices for details. If a port is already in use, you may need to update the system proxy and app settings as well as the local override. For troubleshooting steps, see How to Fix a Port Conflict.

External Controller and Verification

Keep the controller port separate from the proxy port

external-controller exposes the core's management API, allowing a dashboard to check status, switch policies, and perform other management tasks. It doesn't replace mixed-port for regular proxy traffic. Enter the proxy listen port in your browser's proxy settings, and the controller address in the dashboard's connection settings. Mixing them up often leaves the browser without internet access or the dashboard unable to connect, even though the core is still running.

The controller can affect real network behavior, so restrict it to the local loopback address whenever possible. The configuration below shows a local controller endpoint and a local dashboard directory for a basic single-device setup. Put the dashboard files in the ui directory under the core's working directory; the core won't generate a webpage from this path. If your client already includes controller and dashboard management, use its built-in settings instead of creating duplicate listeners by hand.

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

Binding to loopback blocks remote access, but doesn't complete every security measure. Other processes on the same machine may still reach the port. Set a dedicated secret for the controller using a method supported by your client, then enter the same value in the dashboard's connection settings. Don't put the actual secret in public files or examples, share dashboard links containing authentication details, or reuse your proxy account password as the controller secret. Reconnect after changing it and confirm that the old credentials no longer work.

Verify the API before troubleshooting the browser dashboard

If the dashboard won't open, first confirm that the core is running and the controller port is listening; then check the static dashboard directory. In a basic local setup without authentication, you can use the command below to see whether the API responds. If authentication is enabled, use a supported client option or include credentials in a local request. Don't expose the controller on every network interface just to test it. A rejected response and a port that can't be reached are different issues.

curl --noproxy '*' http://127.0.0.1:9090/configs

If the API is reachable but the dashboard isn't working, check the controller address and authentication details saved in the dashboard, along with browser errors. A page opened over HTTPS connecting to a local HTTP API may run into mixed-content or browser local-network restrictions. Cross-origin requests may also be affected by the controller's origin policy. Don't allow every origin as a generic fix; prefer a client-provided dashboard or a same-origin local page, and restrict allowed origins to those you actually need.

For remote management, changing the listen address to all network interfaces isn't a complete setup. You also need to plan authentication, network access controls, encrypted transport, and firewall rules. If a controlled local forward or management network can do the job, there's usually no need to expose the controller directly to the public internet. A dashboard page loading successfully doesn't prove the management connection is secure: the page and API may use different addresses and transport methods, so verify each one.

Close the loop with connection records

The dashboard is most useful for tracing how a new connection is handled: the source app, destination domain or address, matched rule, policy chain, and final exit. For testing, choose a specific target and make one new request instead of guessing based on a large number of concurrent connections. Seeing a group name doesn't mean it is the final exit; expand it to see the selected member. If the right rule matched but the connection failed, check the actual proxy and DNS next instead of changing the rule order again.

The policy selection shown in the dashboard may differ from the default member in the configuration file. With selection persistence enabled, reloading the configuration may restore the previous selection; changing member order doesn't necessarily change the current exit. Record the actual dashboard state before switching manually. Reloading the configuration also doesn't close every existing connection, so base tests on new connections. Before closing connections for an app that needs to stay online, consider whether doing so will interrupt a task.

Follow a consistent order for a full check: validate configuration syntax and references; confirm that the mixed proxy port and controller port are listening; establish a connection in regular mode; confirm DNS reaches the expected module; check the rule match; expand the proxy group to the actual exit; then enable TUN and sniffing if needed. Record the result after adding each module. If a regression appears, you can return to the last known-good stage instead of undoing the entire configuration at once.

Keep troubleshooting reports concise but complete: include the operating system, client name, whether TUN is enabled, the type of destination that fails, the matched rule, and key error details. Don't publish full subscriptions, authentication details, or complete browsing records. For basic issues, see the FAQ. If you're connected but webpages won't load, follow the step-by-step troubleshooting checklist from system proxy settings through DNS and firewall checks. A maintainable configuration makes it possible to explain why a connection was handled a certain way—and where to roll back when something fails.