Policies and egress
Proxy group types and practical use
Proxy groups sit between rules and proxy nodes. Rules decide which egress handles a connection; a proxy group decides which node that egress uses. If rules point directly to individual nodes, renaming a node means updating multiple rules. Pointing them to stable group names lets subscriptions change without breaking the rules. Start by listing the egress options your setup needs, such as manual selection, automatic selection, and a default fallback. Then decide which candidates belong in each group instead of creating a long list of region-specific groups first.
Choose a group type by how it selects nodes
select keeps a manual choice and suits traffic that needs an explicitly controlled egress. url-test periodically probes candidates and selects based on the results; it measures reachability and response time to a particular URL, not whether every site will be faster. fallback checks candidates in configured order and suits primary/backup setups. load-balance distributes separate connections according to a strategy; it does not combine multiple nodes' bandwidth for a single download.
Nested groups can reduce duplicated configuration, but every additional layer makes troubleshooting harder. If a service group points to a manual group, which then points to an automatic group, the name shown at the first level in the dashboard may not be the final node. Expand the selection chain and confirm the actual egress. For services sensitive to logins or long sessions, prefer a stable egress. Automatic switching may send new connections through a different address while existing connections stay on the original node, so both can be active briefly.
| Type | Best for | Key limitation |
|---|---|---|
select | Manually selecting an egress | Choose another candidate if the current one becomes unavailable |
url-test | Selecting based on probe results | The probe target may not reflect the service you use |
fallback | Switching between primary and backup in order | Candidate order matters |
load-balance | Distributing separate connections | Connections for the same service may use different egresses |
Use a proxy provider to isolate subscription changes
The snippet below assumes a local proxy provider file already exists and contains a top-level proxies list. The file path is relative to the core's working directory, not the browser's download folder. The automatic group references the provider with use; the outer proxy group references only the automatic group and the built-in direct route. Export nodes from an existing subscription to this file, or use a subscription-management feature that generates a provider file. A regular web page saved as YAML cannot be referenced as one.
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
lazy: true
- name: Proxy
type: select
proxies:
- Auto Select
- DIRECT
interval is measured in seconds, while tolerance sets the threshold for switching and helps avoid frequent changes when candidates perform similarly. lazy can reduce probing when a group is unused. Don't set an extremely short interval to create the illusion of a “best node in real time”; frequent probes add requests and drain mobile devices. If all candidates fail their probes, first check whether the test URL is reachable through those nodes, then check the nodes themselves. The dashboard alone doesn't prove that every subscription has failed.
Filtering, naming, and verification
When filter is used to select provider nodes, it generally matches names with a regular expression; it does not infer geographic locations. Renames, changed symbols, or differences in capitalization can leave the filter with no matches. First check whether the provider has loaded any nodes in the dashboard, then test the filter expression, and finally check that candidates appear in the proxy group. Group names must exactly match the targets in your rules. Watch for nonbreaking or full-width spaces, lookalike punctuation, and invisible characters introduced by copying and pasting.
For verification, manually select a node you know works, then visit the target site in rule mode. In the connection details, check the matched rule, proxy group, and final node rather than relying on the client's master switch. If manual selection works but the automatic group doesn't, investigate the test URL, filter, or automatic selection behavior. If every group fails, check the subscription and network path. For subscription fetch and parsing issues, see Subscription Update Failure Checklist so you don't mistake an import problem for a routing problem.
Rules and maintenance
Managing rules with providers
Rule providers move domains, IP ranges, or complete rules out of the main configuration. The main file then keeps only the references and match order. This reduces maintenance overhead but doesn't change the basic rule that the first match determines the egress. A provider can contain thousands of entries and still never run if a broader rule matches earlier. Plan the order first: LAN and explicit exceptions, then service-specific providers, geographic rules, and a final catch-all. Avoid using duplicate rules to compensate for incorrect ordering.
Choose the format after identifying what the content means
behavior describes the semantics of a rule provider. Use domain for a list of domains, ipcidr for a list of IP ranges, and classical for entries that include rule types. This is separate from the file extension: a file called YAML could be a node subscription or a complete configuration. Inspect the source and check its top-level structure and entries before importing it. A URL's file extension alone doesn't establish compatibility.
The format must match the content. YAML rule providers typically use a top-level payload array; text providers read entries line by line; MRS is a compiled rule format whose supported features depend on the core. If the file contains complete rules such as DOMAIN-SUFFIX,example.org, use suitable classical semantics rather than putting them in a plain domain list. When switching sources, check both behavior and format; don't just change the URL.
| Semantics | Example content | Use |
|---|---|---|
domain | +.example.org | Manage domain matches in one place |
ipcidr | 192.168.0.0/16 | Manage IP ranges in one place |
classical | DOMAIN-SUFFIX,example.org | Keep different rule types |
Test locally before enabling remote updates
Start by testing with local files. The main configuration below references two local rule providers: Business Domains contains a domain list, and Local Networks contains IP ranges. Both files must actually exist on disk. Define the Proxy group in advance. no-resolve prevents address-based rules from triggering an extra lookup to match a domain; it doesn't skip DNS in every case or prevent later rules from resolving names when needed.
rule-providers:
Business Domains:
type: file
behavior: domain
format: yaml
path: ./rules/business.yaml
Local Networks:
type: file
behavior: ipcidr
format: yaml
path: ./rules/private.yaml
rules:
- RULE-SET,Local Networks,DIRECT,no-resolve
- RULE-SET,Business Domains,Proxy
- MATCH,Proxy
For example, business.yaml could use the structure below. The reserved example domain is for illustrating syntax only; it doesn't route any real business traffic. Replace it with a domain you actually need, check that the core can load the file, and then observe a request to the target. Domain rules don't include URL paths, so don't enter a full address with a scheme, port, and page path. Plain domain routing cannot distinguish paths on the same domain.
payload:
- "+.example.org"
- "example.net"
To switch to an HTTP provider, add a trusted-source url, a local cache path, and an update interval. Give each source a distinct cache path to prevent files from overwriting one another. Set the update interval according to how often the rules change; it doesn't need to match the node-probe interval. Whether a cached file remains usable after a failed download depends on the cache's validity and the core's state. Before deploying to a new device, verify that the first download can reach its source.
Check update status and rule matching separately
A provider reporting a successful update only confirms that the file was fetched and parsed; it doesn't prove that a target request matched it. Troubleshoot by checking the provider's entries, its position in the main rule chain, and whether the connection carries a domain name or only an IP address. Browser caches, existing long-lived connections, and app-specific DNS can all make test results differ from expectations. After changing rules, close the target app's existing connections and make a new request. This usually gives you more useful, comparable logs than repeatedly restarting the entire client.
When maintaining multiple sources, document what each provider is for and keep only a few explainable local exceptions. Avoid subscribing to several large sets that cover the same services and guessing which one wins based on order. Before removing a source, check every RULE-SET reference. When combining sources, consider licensing, update reliability, and differences in content. If a rule doesn't match as expected, temporarily add an exact rule for the target domain to verify the egress, then remove it. Don't let a temporary fix permanently mask the existing logic.
Resolution paths
DNS configuration
DNS configuration involves at least three questions: which resolver receives app queries, which resolver looks up destination domains, and how the proxy server's own hostname is resolved. Sending all three through the same upstream may look simple, but can create a dependency loop. For example, resolving the proxy server may require connecting through the proxy, while connecting to the proxy first requires resolving its hostname. Before optimizing, map out these three paths and confirm bootstrap resolution works independently. Then consider encrypted upstreams, per-domain resolver policies, and caching.
Separate bootstrap DNS from normal lookups
default-nameserver is mainly for bootstrap lookups, such as resolving the hostnames of DNS upstreams, and usually uses explicit IP addresses. nameserver specifies the regular DNS upstream; nameserver-policy assigns resolution paths to specific domains or rules; proxy-server-nameserver resolves proxy node hostnames. Whether the client preserves a field depends on the generated runtime configuration, not just what you entered in the subscription editor.
This basic snippet illustrates what each field does. It uses explicit upstream addresses to avoid introducing extra hostname dependencies into the example. The listener uses a nonstandard local port, but that doesn't mean the system is sending DNS queries to it. Before enabling it, make sure the port is available. If TUN will intercept queries, connect the traffic to the core's DNS module as described in the next chapter. Upstream reachability depends on your network; the example addresses aren't a performance guarantee for every region or route.
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
default-nameserver:
- 223.5.5.5
- 1.1.1.1
nameserver:
- https://1.1.1.1/dns-query
proxy-server-nameserver:
- 223.5.5.5
nameserver-policy:
"+.lan":
- 192.168.1.1
Replace the LAN resolver in the example with a router or internal DNS server that actually works on your network. If you don't need internal domains, remove the corresponding policy. Sending corporate hostnames to a public resolver will usually return no record. Conversely, sending all public domains to a server that only resolves internal records will cause widespread failures. To determine whether a resolver is suitable for a domain, check the returned address and connection path, not just whether a record was returned.
Fallback is not a catch-all fix for every failure
fallback with fallback-filter determines which set of DNS results to use in certain cases. It is not a primary/backup proxy group for network egress. Filters can use geographic data, IP ranges, or domains. A filter that's too broad sends many queries to the backup upstream; one that's too narrow may continue using unsuitable results. If the selection criteria aren't clear, first use a straightforward nameserver-policy for the domains that need it. Consider fallback only if there's a real need.
When using respect-rules to route DNS upstream connections according to routing rules, resolve proxy server hostnames independently first. Otherwise, DNS resolution and proxy connections can end up waiting on each other. Encrypted DNS changes how queries are transported; it doesn't automatically route them through a proxy or guarantee that the returned address suits the current egress. If a domain resolves but the connection times out, check that the result fits the network path, then check policies and routing. Don't keep adding upstreams indiscriminately.
Troubleshoot queries, responses, and connections separately
First confirm that the app's query reaches the core, then check whether the core sends a request to the expected upstream, and finally compare the address used by the destination connection. You can use the system's DNS query tool to specify the local listener address and port. If the tool can't set a custom port, don't mistake a result from the system resolver for one from the core. Test one internal domain, one public domain, and one proxy node hostname. This usually reveals the break point more quickly than repeatedly refreshing a single page.
After a DNS change, the OS, browser, and core may each retain cached results. Close existing connections in the target app first, clear the DNS cache if the client supports it, then make a new request. If you see IPv6 addresses but the network has no working IPv6 route, distinguish a DNS response from actual routing capability. Toggling a single DNS setting may not affect every app. Check the system routes, core configuration, and node support before enabling IPv6; one site loading doesn't prove it works end to end.
DNS handling and rule routing depend on each other, but they're not the same setting. Domain rules can match while the hostname is still available; IP-based rules may trigger a lookup, and no-resolve limits that step. Record the request's domain, returned address, matched rule, and egress to understand how the configuration behaved. For more on combining DNS fields and the limits of DNS hijacking, see DNS Settings and Hijacking Guide.
Traffic interception
TUN and Fake-IP
The system proxy relies on apps honoring the OS proxy settings. TUN uses a virtual network interface to receive traffic routed to the core. These options determine how traffic enters the client; they don't determine whether it must use a proxy. With TUN enabled, rule mode can still send LAN traffic and selected services direct. Global proxy mode also doesn't mean every system connection is intercepted. To verify coverage, start with the target app's connection records and the routing table, not a single toggle.
Check permissions and routing prerequisites first
Desktop clients may need a service component, administrator privileges, or specific system permissions to create interfaces and routes. On mobile platforms, the system VPN interface provides traffic interception, and the setup differs from desktop. Before enabling TUN for the first time, note your current system proxy and DNS settings, pause other VPNs that may control routing, then use the client's TUN switch. Don't run another core instance manually at the same time; ports, virtual adapters, and default routes may conflict.
This is a common partial Mihomo configuration. auto-route configures relevant routes automatically; auto-detect-interface identifies the outbound interface; dns-hijack sends matching traditional DNS requests to the core. This snippet must be used with the DNS module enabled. If the client manages these fields through its UI, use those settings first and inspect the final configuration to avoid conflicts between subscription fields and UI state.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
stack selects the network stack implementation; there's no single best option for every system. To troubleshoot compatibility, change only this setting at a time and retest the same service. Record whether the connection starts, stays active, and handles UDP correctly. Don't change the stack, MTU, DNS, and node all at once; if the issue disappears, you won't know which change fixed it. If automatic interface detection fails, check the system's actual outbound interface, especially after switching between wired and wireless connections.
Fake-IP preserves domain mappings, not real service addresses
Fake-IP mode returns a virtual address from a reserved pool to the app and records its mapping to a domain. When the connection reaches the core, the mapping is used to match rules and establish egress. Don't use an app's virtual address directly on another device that doesn't share the mapping. It also doesn't mean the remote service is actually on that IP range. When troubleshooting, check both the mapped domain and the final egress; the destination address shown by a system tool alone can't tell you whether routing is correct.
Some LAN discovery, device management, and other services that require real DNS addresses may need to bypass Fake-IP. Use fake-ip-filter for specific domains. These domains will then resolve to real addresses, and whether later rules retain the domain depends on app behavior and sniffing. Don't exclude every domain to fix one device; identify the exact request domain and test the smallest possible scope. If the address pool conflicts with an existing VPN or test network, adjust it within the core's supported range and rebuild the mappings.
| Environment | Check first | Common conflicts |
|---|---|---|
| Desktop | Service permissions, outbound interface, routes | Other VPNs and virtual adapters |
| Mobile device | System VPN permission, background operation | Another VPN intercepting connections |
| Linux | TUN device, routing permissions, firewall | Policy routing and container networking |
| Router | Forwarding path, DNS entry point, subnets | Loopback, secondary routers, upstream interception |
Verify interception with a reversible process
For testing, keep a known-working rule and node, and enable only TUN. Choose a target app that didn't previously follow the system proxy, create a new connection, and check whether it appears in the connection list. If the connection appears but access fails, interception is likely working; next check the rules, DNS, and egress. If there's no record, check whether the app bypasses the current network path, whether interface routes are in place, and whether another network tool took control first.
Traditional DNS hijacking doesn't automatically intercept every encrypted DNS lookup. App-level DoH and other encrypted protocols look like ordinary encrypted connections; they aren't sent to the local resolver just because they use a nonstandard DNS port. If domain information is missing, first check the app's secure DNS settings, then consider the sniffing features in the next chapter. Enabling dns-hijack doesn't prove that all resolution paths have been unified.
If the network goes down, turn off TUN first and check whether routes and DNS recover before investigating the conflicting software. If the problem persists after exiting the client, check for a leftover system proxy, other VPNs, and system network settings. Don't keep adding routes. When maintaining a remote server, keep a separate recovery path so you don't lose access after intercepting its management connection. For a full explanation and a comparison with the system proxy, see TUN Traffic Interception Guide. For first-time setup, follow the Quick Start Guide.
Restoring domain information
Domain sniffing
Domain rules need the destination hostname, but a connection reaching the core may contain only a destination IP. An app may connect to a cached address or resolve the name itself, bypassing the core's DNS. Sniffing attempts to recover the hostname from supported protocol handshakes or request data, making it available for rule matching or destination handling. It adds connection metadata; it doesn't decrypt all content or replace a sound DNS setup and well-designed rules.
What can be identified and where the information comes from
HTTP sniffing typically uses host information in the request; TLS sniffing typically uses the server name in the handshake. QUIC requires core support for the relevant traffic. The domain may be unavailable if a protocol isn't supported, handshake information is hidden, or a mechanism conceals the server name. A missing domain in the dashboard isn't necessarily a client bug; the traffic may simply contain no usable information. In that case, keep IP-based rules and a clear fallback instead of expanding the sniffing port range indiscriminately.
The snippet below starts with common web ports and includes TLS and QUIC. It configures sniffing capabilities; it doesn't guarantee that every connection will yield a domain. parse-pure-ip allows attempts to handle connections whose destination is only an IP, while force-dns-mapping affects sniffing behavior in DNS mapping scenarios. When testing for the first time, add only sniffing settings. Don't rewrite DNS and rules at the same time, so you can compare domains and match results before and after.
sniffer:
enable: true
force-dns-mapping: true
parse-pure-ip: true
override-destination: false
sniff:
HTTP:
ports:
- 80
- 8080-8880
override-destination: false
TLS:
ports:
- 443
- 8443
QUIC:
ports:
- 443
Make port ranges match the traffic you actually handle. Sending every port through every protocol parser adds unnecessary processing and can complicate handling for unrelated traffic. For a self-hosted service on a nonstandard port, confirm its protocol, then add the port only to the relevant setting. QUIC typically uses UDP, and successful proxying also depends on node protocols, the server, and the network path. Enabling QUIC sniffing doesn't mean UDP egress is available.
Distinguish matching from rewriting the connection destination
override-destination determines whether the sniffed domain replaces the connection's destination. Using a domain for rule matching and reconnecting to the domain are different behaviors. Some services depend on a particular IP, internal DNS result, or address binding; rewriting the destination can change how they work. The example disables overrides first, so you can observe domain recovery with minimal impact. Enable them only when needed for a specific protocol or service, and check how your core inherits global and protocol-level values.
One IP may host multiple domains, and one domain may resolve to multiple addresses. A changed IP alone doesn't show whether sniffing worked. Check the original destination, sniffed domain, matched rule, and final egress. If the app sends requests through another proxy, the sniffed information may describe only that intermediate connection. Analyze traffic as close as possible to the target app's entry point; don't assume every name in the connection list is the complete website the user is visiting.
Limit the scope and preserve compatibility exceptions
If only a few services fail after enabling sniffing, first disable destination overrides and retest. Then consider using skip-domain to exclude specific incompatible domains. Evaluate force-domain only when a particular domain needs to be handled explicitly; it isn't a general-purpose allowlist. Document why each exception exists so you don't end up with an unexplained list of domains months later. For internal systems, pay particular attention to private certificates, nonstandard handshakes, and fixed-IP access; don't apply public website assumptions without checking.
Test with a new connection. Browser connection pools, HTTP/2 reuse, and long-lived app connections may mean there's no new handshake to inspect after a configuration change. Close the target app's existing connections, open a page you can test repeatedly, and check the logs for the expected domain. Don't clear all system network settings at once or you'll lose the baseline for comparison. If you save debug logs, keep only the relevant time window and hide personal information such as domains and node addresses.
A different rule match after sniffing isn't automatically a better result. Check that the new rule serves your actual needs; a broad domain-suffix rule may override a precise IP exception. Temporarily add an explicit rule for the target domain to verify the result, then incorporate what you learned into the long-term rule design. If a DNS adjustment gives you stable domain information without sniffing, prefer the simpler path with fewer dependencies rather than adding another feature switch for every issue.
Handle traffic that remains unidentified by address, port, or reliable process information. Process rules depend on the platform, permissions, and core capabilities, and support differs between mobile and desktop. Route uncertain traffic to a clearly defined fallback group so the final egress is still explainable. If you need help with the terminology, see the DNS, rules, and network stack entries in the Glossary, then compare them with the connection details. Don't assume that “no domain” means “the proxy isn't working.”
Configuration generation and updates
Local overrides and multiple subscriptions
Subscription configurations are regenerated when updated, so direct edits to ports, DNS, or rules in a subscription file may be lost next time. Local overrides keep user-maintained settings separate from remote content. Let the subscription manage nodes, and keep personal rules, listener scope, and necessary DNS policies in a local layer. First check whether the client merges fields, prepends rules, appends rules, or runs a script. These are not all simple text additions.
Establish configuration ownership and processing order first
A configuration typically passes through subscription download, parsing, client conversion, overrides, and core runtime. A field present in the editor but absent from the runtime configuration may have been overwritten in a later stage; it doesn't necessarily mean the YAML is invalid. Clash Plus and other compatible clients may use different labels for these controls. Check the actual UI for local configuration, overrides, or runtime configuration. Don't conclude that a client lacks a core capability just because another client's menu is different.
Clients may merge mapping fields by key, but arrays may be replaced wholesale or handled by dedicated prepend and append mechanisms. rules, proxy-groups, and nameserver all involve lists; don't assume adding one item preserves all remote entries. When first using overrides, make a small, easy-to-observe change, inspect the runtime result, and confirm the merge behavior before moving other settings.
| Configuration | Where to maintain it | What to check |
|---|---|---|
| Nodes and remote subscriptions | Subscription or proxy provider | Update reachability, node names |
| Personal rule exceptions | Local rules placed before remote rules | Ordering and proxy group references |
| DNS and TUN | Client settings or an explicit local layer | Effective values, permissions |
| Control interface | Local security settings | Listener address, access credentials |
Keep subscriptions separate by source, then use shared egress groups
Don't merge every node from every subscription into one undifferentiated list. Sources may contain duplicate node names, proxy group names, or provider identifiers, and override order can vary between clients. A more reliable approach is to keep each source as a separate provider, create a group for each source, and have shared egress groups reference those groups. The snippet below assumes both local files are valid proxy provider files. A complete subscription must first be converted using a feature supported by the client; renaming the file doesn't turn it into a node list.
proxy-providers:
Source A:
type: file
path: ./providers/source-a.yaml
Source B:
type: file
path: ./providers/source-b.yaml
proxy-groups:
- name: Group A
type: select
use:
- Source A
- name: Group B
type: select
use:
- Source B
- name: Proxy
type: select
proxies:
- Group A
- Group B
This structure decouples rules from subscription sources, but you still need to handle duplicate node and group names. If the client can prefix node names by source, use a stable, short, recognizable prefix. If a script renames nodes, update every name-based reference and filter expression as well. Before removing a source, remove its reference from the shared egress group, then delete the provider. If a group has no candidates after an update, check that the source loaded before changing filters or rebuilding the whole configuration.
Remote subscriptions may include rules, DNS settings, and control interface fields as well as nodes. Decide explicitly which content is allowed into the runtime configuration; don't concatenate two complete configurations and expect the core to resolve their priority. In particular, manage external-controller, allow-lan, and listener addresses locally under a consistent policy. If you use a subscription conversion service, consider link confidentiality and what the service can access. Prefer a processing path you control.
Change one layer at a time and keep a rollback copy
Keep separate copies of the original subscription, local overrides, and final runtime configuration; don't repeatedly overwrite the same file. Check the final configuration syntax before loading it in the client, then verify connections. When using the Mihomo CLI independently, run the configuration test below. It checks syntax and related configuration relationships, but doesn't verify the subscription server, rule downloads, or every service connection. Continue checking logs at runtime.
mihomo -t -f ./config.yaml
If the client crashes or won't start after an override change, first undo the most recent local change and restore a known-working configuration. Then decide whether the client itself needs attention. The line number in an error may refer to the generated file, not the remote source. Open the correct runtime file and check indentation, duplicate keys, invalid references, and replaced lists. For more startup troubleshooting, see Client Startup Crash Troubleshooting.
Backups also contain subscription URLs, node passwords, and control credentials; don't attach them to public support requests. Before sharing a configuration, remove sensitive data, keep only the smallest structure needed to reproduce the issue, and replace real values with obvious examples. When moving to another device, check local providers, rule sets, controller directories, and relative paths in addition to the YAML. Identical configuration text can still fail if the working directory differs, leaving files missing or causing stale caches to be read.
Runtime monitoring and control
External controller
An external controller lets a dashboard read proxy groups, connections, rules, and logs, and perform actions such as switching groups. It's an interface for controlling the core, not another proxy egress and not a tool for creating TUN routes. If the dashboard won't connect, the browser may still have normal internet access. Conversely, an open dashboard doesn't prove the proxy path works. Check page resource loading, controller reachability, authentication, and service connections separately.
Keep the listener local by default
For local use, bind the controller to the loopback address and use a dedicated credential. The your-password value below is only an example; replace it with a long, randomly generated string that isn't shared with a subscription or another service. external-ui points to the local dashboard resource directory, which must contain the dashboard entry file. The path is relative to the core's working directory. If you don't have dashboard files yet, test the API first and configure the UI later.
external-controller: 127.0.0.1:9090
secret: "your-password"
external-ui: ./ui
A loopback listener is accessible only from the local device. When a phone browser connects to a computer's loopback address, it connects to the phone itself; it won't reach the computer. If remote administration is necessary, prefer a controlled private channel and restrict its sources, identities, and access scope. Don't expose the controller directly to the public internet for convenience. allow-lan for proxy ports and the controller listener are separate settings. Enabling LAN proxy access doesn't configure or secure the controller.
Test the API before troubleshooting the dashboard
Start by sending a request to the controller API from the device running the core. The command below reads basic configuration details; the credentials shown are examples only. If the response is unauthorized, check the credentials in the active runtime configuration. If the connection is refused, check the listener address, port, and process status. For a timeout, also check routing and the firewall. Reinstalling dashboard files won't help if the controller service isn't reachable.
curl --fail \
-H "Authorization: Bearer your-password" \
http://127.0.0.1:9090/configs
If the API works but the browser dashboard doesn't, check the backend address, protocol, and port entered in the dashboard. A browser may block a page loaded over HTTPS from connecting to an HTTP backend due to mixed-content security rules. Cross-origin requests may also be restricted. Prefer a clear, consistent path between the local dashboard and the controlled API. If cross-origin access is necessary, configure specific allowed origins according to core support; don't allow every origin as a generic fix.
Dashboards may save backend addresses and credentials in browser storage. If you switch browsers, you'll need to configure them again; clear saved data after using a shared device. Hide connection domains, subscription sources, node addresses, and credentials in screenshots. When copying debug information, include only fields relevant to the issue. Check the log contents before sharing, not just the filename; connection details can reveal specific browsing activity more readily than the main configuration.
Complete the verification loop with connection details
Use the policy page to confirm the selection chain, the connections page to check matched rules and final egress, and the logs page to investigate resolution failures, provider updates, and routing errors. When adjusting rules, note the time and target of a test request, then find that connection. This helps avoid mistaking another process in a constantly refreshing list. Connections established before a change may not be rerouted immediately. If needed, close only the relevant connection and make a new request to minimize disruption to other services.
Treat automatic dashboard probes and real service tests separately. A successful probe means only that the test request completed at that time. Whether a node can reach a service also depends on the protocol, port, UDP support, service-side restrictions, and egress path. For a site that isn't working, temporarily pin a manual node to remove automatic switching as a variable, then check DNS, the matched rule, and connection errors. Frequent probes aren't a substitute for recording the actual failure, and one result isn't a reason to reorder every rule.
Changes made through a controller may not persist in the same way as changes to a configuration file. Some dashboard actions change only in-memory state; some selections may be cached by the core or client. Whether they survive a reload depends on the implementation. Save long-term settings in the local configuration or client settings, then verify them after reloading. For temporary diagnostics, record the change and revert it promptly so future troubleshooting doesn't start from a runtime state that differs from the files.
After an advanced change, verify it in a consistent order: the configuration parses, providers load, DNS behavior is explainable, the target connection reaches the core, the expected rule matches, and the final egress is correct. Change only one major factor at a time and keep a working rollback copy. For everyday installation and first-time connections, see the Quick Start Guide. To switch platforms or clients, choose one from the download page. For configuration concepts, continue with the Glossary.