Clash Advanced Setup Guide
Proxy groups, rule providers, DNS, and traffic routing. Look up fields by topic and verify results along the connection path.
For your first install, subscription import, and proxy mode selection, start with the quick start guide. This page is for users who are already connected: it explains configuration dependencies, common limitations, and rollback options. The tutorial gets your first connection working; this guide explains why settings work the way they do and how to confirm changes have taken effect.
Examples use mihomo fields. Unless noted otherwise, code blocks are configuration snippets, not complete standalone configs; merge them into the appropriate sections of your existing file. GUI client menus and override behavior vary, so check the loaded configuration and core logs.
For client comparisons, start with the downloads page. Compare Clash Plus first on Windows, macOS, Android, and iOS; on Linux, consider Clash Verge Rev and FlClash. A setting exposed in a client UI is not necessarily supported by the current core.
Proxy Group Types & Practical Setup
Proxy groups sit between rules and actual outbound connections. Instead of naming a specific node in every rule, point rules to a stable group name; the group then handles manual selection, automatic selection, or failover. When a subscription updates and node names change, routing rules can remain intact as long as group names and provider references stay consistent. Before designing groups, distinguish three components: proxies connect to remote servers, providers collect proxies, and groups select an outbound. Names are up to you, but every reference must match exactly, including spaces and capitalization.
Choose Between Manual Selection and Automatic Switching
Use select when a service needs a fixed outbound: choose a member on the proxy page, and the core routes traffic through it. url-test periodically probes a test URL and selects a responsive available member; tolerance helps prevent frequent switching over small latency differences, but is not a proxy quality score. fallback checks members in order and uses the first available one, making it suitable for primary and backup routes. load-balance distributes connections across outbounds; it does not combine their bandwidth for a single connection or guarantee that every request uses the same outbound.
For logins, payments, and services that need a stable session, prefer a manual-selection group over chasing the fastest probe result. When an automatic group switches, existing connections usually stay in place; only new connections use the new selection. As a result, resources on the same page may briefly use different outbounds. To troubleshoot, pin a node, close existing connections, and reload the page before checking whether the service itself restricts changes in source IP. Don't assume a failed page load means the rules are malformed.
Separate Everyday Selection from Automatic Candidates
This snippet assumes a proxy-providers provider named primary; see the Overrides chapter for import options. The automatic group draws members from the provider, while the manual group lets you choose between the automatic result and a direct connection. The test URL is for connectivity checks, not a subscription URL; success depends on the outbound, DNS, and the destination service. interval is measured in seconds. A very short interval generates more probes and is especially unsuitable for mobile devices with restricted background activity.
# Example config: uses the existing primary proxy provider
proxy-groups:
- name: Auto Candidates
type: url-test
use:
- primary
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 50
lazy: true
- name: Everyday Outbound
type: select
proxies:
- Auto Candidates
- DIRECT
rules:
- MATCH,Everyday Outbound
Groups can reference each other, but must not form a cycle. For example, if Everyday Outbound includes Auto Candidates and Auto Candidates references Everyday Outbound, there is no final outbound. Trace each route from its rule target through the groups to a real proxy or DIRECT. If a client shows an empty group, first check whether the provider loaded, then whether filters excluded every proxy; adding more nested groups won't fix missing members. Some clients remember the previous selection, but a renamed group may reset to its default member. After a subscription update, recheck groups used by important services.
Check Probe Results Separately from Real-World Access
A probe result on the proxy page only shows how an outbound reaches a specific test target. Real apps may use different domains, ports, or UDP, so a successful probe doesn't mean every service will work. To validate a proxy group, check the matched rule, final outbound, and destination host on the connections page. If the automatic group works but a video or game doesn't, pin a member and test protocol support and service-region requirements. For more UI steps, see the proxy selection tutorial. For groups that need a stable outbound, a clear manual-selection path is easier to maintain than multiple layers of automatic logic.
Managing Rules with Providers
Put rules in rule-providers to maintain rule data separately from routing decisions. A provider downloads or reads a list of domains, IP addresses, or classical rules; rules then uses RULE-SET to select an outbound for matches. A rule set doesn't decide whether traffic is proxied or sent direct; the same list can point to different groups in different configs. Focus on three things: whether the file parses correctly, whether updates are reliable, and whether the rule set's position in the full list matches your priorities. Providers reduce duplicate editing, but don't resolve conflicting rules automatically.
Match behavior and format to the file contents
behavior: domain identifies a domain rule set, ipcidr an IP range set, and classical a classical set containing rule types. format describes how the file is encoded; common options are YAML and plain text. YAML files usually need a payload section. A .yaml extension doesn't guarantee valid YAML, and a full subscription containing proxies and groups does not belong in a rule provider. If loading fails, inspect the actual file's first line, indentation, and entries instead of just changing its extension.
Start with a local rule set to create a minimal, testable setup. The two snippets below belong in the main config and a separate rules file, respectively. Paths are resolved relative to the core's config directory; check the client configuration or runtime logs to find its actual directory. The rule set lists document domains that should connect directly, while the main rules retain LAN bypasses and a final catch-all. The example reuses the Everyday Outbound group from the previous chapter; add that group first if it's missing. Don't import this snippet as a complete subscription.
# Main config snippet
rule-providers:
local-domains:
type: file
behavior: domain
format: yaml
path: ./rules/local-domains.yaml
rules:
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- RULE-SET,local-domains,DIRECT
- MATCH,Everyday Outbound
# Separate file: rules/local-domains.yaml
payload:
- '+.example.com'
- '+.example.org'
Keep a Local Fallback When Updating Remote Providers
Remote providers use type: http and configure url, path, and interval. Use a URL from a rule source whose format you can verify, and give each provider a separate cache path to prevent downloads from overwriting each other. At startup, a rule set may need a proxy to download, while establishing that proxy may depend on rules that haven't loaded yet. Ensure essential bootstrap domains have a clear path to the network, and keep a basic local rule set. Check logs and file status to see whether a failed update left the cache in use; don't rely only on the client's update notification.
An update interval says nothing about rule quality. Frequently fetching a list from an unknown source with unclear categories can send login endpoints and static assets through different outbounds. Before adding a rule set, define what traffic it should cover and check whether representative domains are included. For large classical rule sets, consider load time and device resources; on routers, account for storage writes and available space. After a remote update, test with a new connection on the connections page. A long-lived connection won't tell you whether new rules have taken effect.
Rule Order Determines Which Rule Wins
Rules are evaluated in order, and the first match usually ends the search. Put specific domain exceptions before broader sets, and place the catch-all MATCH last. An address rule with no-resolve won't actively resolve a domain to an IP for matching; if a connection only has a domain, that address rule may not match. Combine domain, geodata, and IP rules to suit the traffic; more rules don't automatically mean better coverage. For mainland China routing details, see practical routing rules.
DNS Configuration
DNS setup involves more than entering resolver addresses. A connection may require resolving a proxy node's hostname, the service domain, and the DNS upstream itself; these queries don't necessarily use the same outbound. First identify where the app sends its queries, then check how the core reaches its upstream, and finally confirm the returned address is suitable for routing. Browser Secure DNS, encrypted system resolvers, and app-specific DNS can bypass the client's DNS entry point. Changing only nameserver doesn't prove every app's queries go through the core.
Separate Bootstrap, Proxy Node, and Service DNS
default-nameserver is mainly used to resolve DNS upstream hostnames and should use addresses that can be reached directly. nameserver handles general service queries; proxy-server-nameserver can resolve proxy node hostnames separately, so connecting to a node doesn't depend on a proxy route that isn't up yet. nameserver-policy assigns specific resolvers to selected domains, which is useful for internal domains, particular network services, or clearly defined resolution boundaries. These fields handle different stages; don't simply copy the same addresses into every setting.
This DNS snippet can be merged into an existing config and uses Fake-IP to map service domains. The resolver addresses are examples, not a guarantee of access on every network; test connectivity before using them. The listener is bound to loopback and accepts requests only from the local device. If a router needs to serve LAN devices, design the listener, firewall, and access scope separately. Changing a desktop example to listen on all interfaces does not complete a safe deployment.
# Config snippet: excludes proxy and rules definitions
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
proxy-server-nameserver:
- 223.5.5.5
nameserver:
- https://dns.alidns.com/dns-query
- https://cloudflare-dns.com/dns-query
fake-ip-filter:
- '*.lan'
- '*.local'
Choose Resolvers for the Query, Don't Just Add More
Internal domains usually need a resolver provided by the local gateway or organization; public resolvers may not know those records. Once you identify the internal domains, use nameserver-policy to route them to an internal DNS server and set suitable Fake-IP exceptions. These are two separate decisions: whether to return a mapped address and which upstream provides the real answer. Adding a domain to the filter list only changes how enhanced mode handles it; it doesn't direct the query to the right internal resolver.
fallback and fallback-filter select and compare results from different upstreams; they aren't simply primary and backup servers in order. If you don't have a specific filtering goal, a small set of easy-to-explain upstreams is simpler to troubleshoot than a long list. respect-rules lets DNS upstream connections follow routing rules, but before enabling it, account for the separate path needed to resolve proxy nodes and configure an appropriate proxy-server-nameserver. Otherwise, you can create a loop: reaching the DNS upstream requires a proxy, but connecting to the proxy requires DNS.
Verify DNS Results and Query Routing Separately
You can run nslookup example.com 127.0.0.1 against the local listener, but this command queries the standard DNS port by default and won't directly test the 1053 port used above. With a tool that supports custom ports, run dig @127.0.0.1 -p 1053 example.com. Receiving a mapped address only confirms that this query went through Fake-IP processing; it doesn't show that all queries follow the same path. Check browser DNS settings, TUN DNS hijacking, and upstream connections in the logs to determine what the app actually does.
After changing DNS, old results may still be cached by the system, browser, or core. Start a new connection and clear caches if needed; restarting the client won't necessarily clear the browser's cache. If a domain resolves but the connection fails, check whether the mapping is still valid, whether the target group works, and whether IPv6 is creating a separate route. For testing methods and field combinations, see DNS leak testing and configuration. Describe the specific app and query path when troubleshooting; a single test site's result isn't a substitute for investigating the full setup.
TUN & Fake-IP
System proxy settings mainly affect apps that honor them. TUN uses a virtual network interface and routes to handle IP traffic, so its coverage is different; enabling the system proxy doesn't mean every app is covered. Fake-IP is a DNS domain-mapping method, not another name for TUN. They are often used together because the mapping lets the core recover the original domain from an IP packet and apply domain-based routing. But TUN also works with other DNS modes, and Fake-IP can be used in suitable non-TUN setups.
Check Permissions and Your Network Setup Before Enabling TUN
In a desktop client, check service mode or required system permissions in Settings before turning on TUN. Windows typically needs a service with permission to manage virtual interfaces and routes; macOS requires system authorization, and Linux needs the appropriate network permissions. Exact steps depend on the client. Android and iOS generally use the system VPN feature to route traffic, and another VPN on the same device may not be able to run at the same time. Corporate networks, security software, and existing tunnels can also change routing. Note the original state first, and don't add routes blindly if you can't identify their impact.
This snippet configures traffic interception. auto-route lets the core create the required routes, while auto-detect-interface helps identify the outbound interface; multi-NIC, bridged, and existing VPN setups still need testing. dns-hijack captures matching DNS traffic; it doesn't automatically detect every encrypted DNS connection. Apps using HTTPS to reach their own resolver generally won't turn into ordinary DNS queries to the core just because port 53 is listed here.
# Config snippet: requires DNS to be enabled separately
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
Understand the Limits of Stack Options and Mapped Addresses
stack determines which protocol stack path TUN packets use. Support and behavior for system, gvisor, and mixed depend on the core and platform; the option name alone doesn't tell you which is faster. Keep the client default unless you have a reproducible compatibility issue worth testing. Compare with the same app, outbound, and network, and check whether TCP, UDP, and LAN connections change. Changing the stack, DNS, and rules all at once makes the results hard to diagnose.
Fake-IP returns a mapped address, not the website's real server IP; don't use it for geolocation checks. The app's subsequent connection must pass through the core that holds the mapping, or that address won't work as a real destination on the regular network. If the client exits, mapping records are cleared, or an app keeps using an old cache, you may suddenly lose connectivity after a settings change. First close the app's old connections and resolve the domain again; clear caches if needed. Don't add the entire mapping range to direct-routing rules.
LAN Exceptions and Recovery
Printers, network storage, casting, and LAN discovery use different protocols, so domain filters alone may not be enough. First check whether the service uses an internal domain or fixed IP, then review subnet routing, DNS, and multicast discovery. Add domains that genuinely need real addresses to fake-ip-filter, route confirmed local subnets directly, and make sure TUN routes still allow access to the local interface. Avoid broad exclusions for entire domain categories; oversized exceptions can deprive domain rules of the information they need to match.
If enabling TUN cuts off all connectivity, check permissions, the virtual interface, default routes, DNS upstreams, and proxy node connectivity—in that order. First turn off TUN while keeping the system proxy enabled. If the system proxy works again, the issue is likely in the traffic interception layer; if both fail, check the subscription, groups, and basic network. Save the error logs and restore one setting at a time, reverting to the saved pre-TUN config if needed. For platform-specific steps, see the TUN setup guide; for general issues, browse Troubleshooting.
Domain Sniffing
Domain sniffing attempts to recover a hostname from supported protocol details when a connection lacks domain information. Common sources include the Host header in HTTP requests, the server name visible in a TLS handshake, and some QUIC handshake data. Sniffing doesn't decrypt traffic or let the core read all HTTPS content, and it can't identify every connection. Think of it as extra matching information: when an app connects to an IP directly or DNS bypasses the core, sniffing may still let domain rules take effect.
First Check Whether the Domain Is Actually Missing
If the connections page already shows the correct domain and expected rule, sniffing may not help. Find a stable, repeatable case and check whether it shows only an IP, matches an IP rule, or falls through to the catch-all. After enabling sniffing, compare new connections for the same service and confirm whether the hostname is now identified correctly. Sniffing isn't a universal fix for routing problems: incorrect rule order, empty groups, unreachable outbounds, and failed DNS upstreams must each be addressed at their own layer.
This snippet enables sniffing for HTTP, TLS, and QUIC. The string ranges in the port arrays are configuration syntax, not a port-scanning task. parse-pure-ip allows sniffing attempts for pure IP destinations; force-dns-mapping applies more aggressive sniffing in DNS-mapping scenarios. Before using these fields, confirm that your mihomo core recognizes them. If startup reports an unknown setting or unsupported protocol, check which core the client is actually running instead of adding more options.
# Config snippet
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
Domain Matching and Destination Rewriting Are Different
override-destination controls whether the sniffed hostname replaces the original destination. Leave it off for initial testing, and first observe how the added hostname affects rule matching. Enable it only if the service needs its destination determined again from the sniffed domain. An app may connect to a specific address for built-in load balancing, special DNS behavior, or a fixed server requirement. Rewriting the destination can change the route the app chose; even a correct-looking sniffed hostname doesn't guarantee that resolving it again will work.
One IP address can host multiple domains, so an address in the connection log doesn't identify the service by itself. Conversely, a hostname in the handshake may belong to a gateway, shared endpoint, or intermediary rather than the site shown in the app. For validation, record the original destination, sniffed hostname, matched rule, and final outbound. Changing sniffing settings won't reconstruct the handshake of an existing long-lived connection; disconnect and create a new one to get a comparable test.
Protocol Limitations and Compatibility
Connections using mechanisms such as encrypted client hello may hide the server name that would otherwise be visible. Non-standard protocols, unusual handshakes, and connections that fail too early may not provide enough information either. QUIC uses UDP, so success also depends on UDP support from the outbound and the network path; don't attribute every QUIC failure to sniffing. You can temporarily switch an app to a comparable TCP path to see whether domain identification changes, but that doesn't mean all apps should disable QUIC.
If only one service breaks after enabling sniffing, first disable destination rewriting, then narrow the protocol and port ranges. If a specific domain is confirmed to cause the issue, exclude it with the core-supported skip-domain setting and verify that the exclusion behaves as intended. Don't add an overly broad wildcard just because a keyword appears in the domain. Also check whether the issue is actually caused by the newly identified domain matching an earlier rule. If sniffing changes routing, it may mean a domain rule replaced a rule that previously matched by IP; adjust the rules rather than assuming sniffing failed.
For the differences between domains, IP addresses, and rules, see the quick glossary. Treat sniffing as a targeted addition, not the first switch to flip every time a connection fails. Being able to explain why a connection matched a rule matters more than enabling more detection options.
Local Overrides & Combining Subscriptions
Remote subscriptions deliver proxies or complete configs; local overrides preserve device-specific ports, DNS, rule exceptions, and group organization. Editing a downloaded subscription directly is risky because the next update may replace your changes. First find out which override method the client supports: YAML merging, configuration extensions, scripts, or a separate local config. Merge order can differ, and fields with the same name aren't always deep-merged. Don't assume steps for one client apply to another.
Find the Final Loaded Config
Select the active subscription in the configuration page, then open its extensions or overrides. Menu names vary by client. Save and reload, then inspect the runtime config, config preview, or core logs to see the final result. A source file with mixed-port: 7890 doesn't guarantee the running port is 7890; a client-wide setting may override it. Keep the remote source, local override, and final config separate. Don't assume a setting took effect just because it appears in the editor. If the client offers a core config check, run it before reloading.
For multiple subscriptions, organize proxy sources as multiple proxy-providers and have proxy groups reference them, rather than concatenating full YAML files. Full subscriptions may include dns, rules, and groups with duplicate names; simply joining the files can create duplicate top-level keys or conflicting references. The example below uses local proxy providers: each file must contain a valid proxies array, not a complete config with rules and settings. Store the files where the core can access them.
# Main config snippet: uses two local proxy files
proxy-providers:
primary:
type: file
path: ./providers/primary.yaml
backup:
type: file
path: ./providers/backup.yaml
proxy-groups:
- name: Multi-Subscription Outbound
type: select
use:
- primary
- backup
proxies:
- DIRECT
rules:
- MATCH,Multi-Subscription Outbound
Array Merging Can Change the Outcome
Scalar fields usually end up with one final value, but rules, proxies, and groups are arrays. An override tool may replace an entire array or append items to the end; these behaviors have very different effects on rules. A local exception appended after an existing MATCH won't work as expected. After saving, inspect the final rules list and confirm the exception is above the catch-all. Check proxy group arrays too: make sure existing references are still there, not just that the new group was added.
Proxies from different sources may share a name. Identical display names don't necessarily mean the same server and can make selection history and rule references ambiguous. If your client supports renaming or provider prefixes, keep the transformation consistent and note when it is applied. Avoid adding prefixes based on temporary conditions; updates may then break manual selections. Test filters on a small set first: matching every proxy or excluding them all can make groups behave very differently from what you intended.
Subscription Formats and Remote Provider Limitations
When using HTTP, a remote provider URL must return a proxy list that the core can parse. A generic Base64 list of links, a single protocol link, and a full Clash YAML config are different inputs; changing the URL in proxy-providers won't convert them automatically. For formats and conversion workflows, see the subscription format guide. Subscription URLs may contain credentials. Remove them before sharing logs, screenshots, or configs, and don't submit real links to online converters unless you know how they handle your data.
Keep a known-good final config and its override source. After each update, check provider member counts, confirm important groups have members, and review critical rules and DNS fields. If something fails, disable the most recently added override first and restore the previous subscription; don't remove every source at once. Script overrides need explicit error handling: if the input structure changes, fail clearly or preserve the original result instead of silently returning a config with missing proxies. For a few port changes and rule exceptions, a simple YAML override is usually easier to review than a complex script.
External Controller
The external controller API exposes runtime status, proxy group selection, connections, and configuration management. A controller dashboard is the web frontend for that API. It is separate from the proxy ports used by apps: opening the dashboard in a browser doesn't mean browser traffic is proxied, and a working proxy port doesn't mean the controller API is available. Before configuring it, decide whether the dashboard runs locally, on a LAN device, or on a server, then choose which addresses the API should listen on. For typical desktop use, binding to loopback is usually the easiest way to limit access.
Separate the API Address from the Static UI Directory
external-controller sets the controller API listen address; external-ui points to the dashboard's static files. The directory must contain an actual entry page and its supporting assets; creating an empty folder won't give you a working dashboard. You can place verified dashboard files in the core's working directory and configure a relative path. If the client already includes a dashboard, use its built-in management UI when possible instead of maintaining a second set of frontend files. Relative paths are resolved from the actual runtime directory.
# Config snippet: the ui directory must contain dashboard files
external-controller: 127.0.0.1:9090
external-ui: ./ui
secret: "your-controller-secret"
The example key only illustrates the field. For real use, set a sufficiently long, unique, private value. Don't put the secret in a publicly accessible article, screenshot, or repository, and don't embed it in a page URL to make the dashboard easier to share. The controller can change runtime state; don't deploy it as if it were a read-only status page. If the client manages secret automatically, connect using its authorization flow instead of overwriting the generated value and breaking the built-in UI.
Test Locally Before Enabling LAN Access
First check that the port is listening on the same device. Then open the configured static dashboard and enter the API address and secret. If the page opens but can't connect, the static assets and API are separate paths; check the address, authentication, and browser errors. The command below shows how to make an authenticated local request. Use the same example secret as your local config, and don't share command history containing the real secret.
curl --header "Authorization: Bearer your-controller-secret" \
http://127.0.0.1:9090/configs
When the dashboard is on another device, 127.0.0.1 refers to the device running the browser, not the host running the core. Enter an address the core host can actually be reached at, and define the listening address and firewall scope explicitly. allow-lan controls LAN access to the proxy service; it isn't a master switch for the controller API. Check the controller's listen address separately. Even if the proxy is local-only, an incorrectly bound API can expose administrative access.
Browser Security and Remote Access
An HTTPS dashboard connecting to an HTTP API may be blocked as mixed content; pages hosted on different origins may also run into cross-origin restrictions. Choose same-origin access or a secure reverse proxy for your deployment rather than disabling browser protections. If you need to change the controller's cross-origin settings, allow only trusted dashboard origins instead of opening access to every origin by default. The browser console can usually distinguish an unreachable network, failed authentication, and a security policy block.
Don't expose the controller API directly to the public internet. For remote management, use a private network with access controls or an authenticated secure gateway, restrict permitted sources, encrypt traffic, and keep a fallback access path. Secret-based authentication is only one layer, not a substitute for network boundaries. Before changing remote rules or groups, make sure the change won't cut off your management connection. On servers, keep local or alternate maintenance access so a config reload can't lock you out.
An external dashboard is useful when you need to inspect rules and connections, but isn't required for a basic connection. If you only need to import a subscription and choose an outbound, start with the client's built-in UI. For an overview of each area, see the client interface walkthrough. Troubleshoot the core first, then check dashboard assets, API access, and browser restrictions. Don't mistake a frontend connection issue for a proxy node failure.
Ports & Configuration Validation
A port is an entry point for apps to connect to a core service, not the server-side port of a remote proxy node. mixed-port accepts both HTTP and SOCKS proxy connections; port and socks-port provide those services separately. The controller API, DNS listener, and proxy entry point each serve a different purpose; they aren't interchangeable just because they use local addresses. Common mistakes include entering 9090 as a browser proxy port or treating 7890 as a DNS port. Identify the protocol first, then verify the address and port.
Map Each Field to the Service It Configures
| Configuration Field | Purpose | What to Check |
|---|---|---|
mixed-port | HTTP and SOCKS proxy entry point | App protocol, listen address, port availability |
external-controller | Core controller API | Authentication, access scope, browser restrictions |
dns.listen | DNS query entry point | UDP or TCP, actual query port |
allow-lan | Proxy LAN access settings | Bind address, firewall, access permissions |
For local use, keep allow-lan: false and let apps connect over loopback. To offer proxy access to LAN devices, explicitly configure the bind address, device permissions, and firewall rules. Sharing the proxy doesn't mean sharing the controller API; configure them separately. Router and desktop firewalls behave differently, so don't stop at confirming that a setting is enabled. Test the connection from a device that needs to use the proxy to verify the full cross-device path.
# Config snippet: local proxy listener
mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
Validate One Change at a Time
Save a working config before making changes, and note the current network, selected proxy group, and client mode. If the client can export its final runtime config, save that too; the subscription source may not include client-added settings. Check syntax and references before reloading. With the native core, run mihomo -t -f config.yaml from the relevant working directory to validate the config. This command doesn't test connectivity or prove that remote rule sources, proxies, or DNS upstreams are reachable.
Once the config loads, check that the port is actually listening. On Windows, use Get-NetTCPConnection -LocalPort 7890 to inspect the local TCP listener; on Linux, use ss -lntp; on macOS, use lsof -nP -iTCP:7890 -sTCP:LISTEN. Some commands require specific permissions or system tools. If another client has occupied the port, stop the conflicting process or choose a new port, then update system proxy and app settings too. Changing only the YAML while continuing to use the old port won't fix the connection.
An explicit proxy test can temporarily rule out system proxy settings as a factor. The command below specifies an HTTP proxy and requests an example domain. Success shows that this request worked through that entry point; it doesn't prove TUN, every rule, or UDP is working. For SOCKS testing, use a form that resolves the hostname remotely to help distinguish local DNS from proxy-side resolution. Replace the test target with a legitimate address relevant to your setup, and don't leave private access parameters in logs.
curl --proxy http://127.0.0.1:7890 --head https://example.com
curl --proxy socks5h://127.0.0.1:7890 --head https://example.com
Locate the Fault at One Layer of the Connection Path
If the client can't connect to the entry point, check the process, listen address, and port. If traffic reaches the core but the domain is wrong, check DNS, the app's resolution method, and sniffing. If the domain is right but the outbound is wrong, check rule order and group selection. If the outbound is right but the connection fails, check the proxy protocol, destination service, and network path. Temporarily increasing log verbosity can help, but restore an appropriate level when done to avoid collecting excessive connection data. Remove subscription URLs, credentials, and private domains before sharing logs.
Keep a fixed set of test cases for validation: a site that should connect directly, a service that should use a proxy, a LAN destination, and a UDP app you actually use. Change one category of fields at a time, confirm the result with a new connection, then move on. If the issue only occurs after startup, check service startup and config load order; see the launch at startup guide. If it affects only one app, see usage tips. A stable config isn't the one with the most fields; every field should have a clear purpose, and every exception should have a reproducible test.