First, check whether the request reaches Clash
The system proxy toggle only indicates that an attempt was made to change the system proxy settings. It does not mean every app is routing through Clash. A browser extension may control the browser's proxy, terminals usually need a proxy specified separately, and PAC rules may send a domain directly. Even when a request reaches the core, its rules may still select DIRECT. First determine whether the app is bypassing the proxy or whether the request is being routed directly after reaching Clash. That's more useful than repeatedly switching nodes.
- Check the current configuration and local listening ports in the client. This guide uses
127.0.0.1:7890as an example HTTP or mixed proxy address; use the values from your actual configuration. - Open the client's Connections page and look for new requests in Logs. If needed, temporarily set the log level to
info. - Note the current time, visit a page in your browser that is certain to make a network request, then check the destination domain, matched rule, and proxy chain.
- Then use the explicit proxy command below to access the same destination. If the command succeeds but the browser does not, focus on browser and system settings; don't change your subscription yet.
| Observed result | Check first | Next step |
|---|---|---|
| Explicit proxy connection refused | The core isn't running, the port is wrong, or nothing is listening | Check the local port and process |
| Explicit proxy works, but no matching browser connection appears | Extension, separate proxy, PAC, or bypass list | Check browser and system settings |
| Connection shows DIRECT | Current mode and rule order | Check the matched rule and policy group |
| Connection selects a proxy node but times out | Node, remote DNS resolution, or destination connection | Check the specific error; the system proxy toggle is no longer the likely cause |
Check the local port: the system proxy address must match a port the core is listening on
The controller port shown in the client is not the proxy port. The external-controller option is for the control API and must not be used as the browser's HTTP proxy address. port usually provides an HTTP proxy, socks-port provides a SOCKS proxy, and mixed-port accepts both HTTP and SOCKS requests.
For example, 7890 and 7891 are common configuration values, not fixed standards. This YAML snippet illustrates how ports map to proxy types. It does not include nodes, subscriptions, or complete rules, so it is not a complete working configuration:
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
Windows: Check listening ports and system settings
Run these commands in PowerShell. The first checks whether a port is listening. To view the current user's proxy settings in Windows, open Settings manually:
Get-NetTCPConnection -State Listen -LocalPort 7890
Start-Process "ms-settings:network-proxy"
Go to Settings → Network & internet → Proxy. Check that the manual proxy address is 127.0.0.1, that the port matches the client, and note whether “Use setup script” is enabled. If the first command returns no entries, check whether the client core is running. If another process owns the port, identify it rather than assuming it's Clash.
macOS and Linux: Check listening ports instead of guessing defaults
# macOS
lsof -nP -iTCP:7890 -sTCP:LISTEN
# Linux
ss -lntp 'sport = :7890'
On macOS, go to System Settings → Network → select the active network service → Details → Proxies, and check HTTP, HTTPS, and automatic proxy configuration. Wi-Fi and Ethernet are separate services, so check again after switching networks. Linux desktop proxy settings vary by environment, and not every app reads the desktop proxy toggle.
Browser troubleshooting: Check extensions, separate settings, and PAC independently
Chrome and Edge: First rule out extension-controlled proxy settings
In Chrome, go to Settings → System → Open your computer's proxy settings to check the system proxy. In Edge, the equivalent option is usually under Settings → System and performance → System. Menu labels may vary slightly by release; you can also search for “proxy” in Settings.
- Check the current mode of any proxy-switching extension. It may be set to a different port or have some domains on a bypass list.
- Temporarily disable all extensions that change proxy settings, quit every browser process, and restart the browser to test. Incognito mode doesn't guarantee that extensions are disabled; extensions allowed to run in incognito can still take effect.
- If the device is managed by an organization, check proxy policies at
chrome://policyoredge://policy. A device administrator must change settings locked by policy. - Check the browser's launch arguments for
--no-proxy-server,--proxy-server, or--proxy-pac-url, which can change how proxying works.
Firefox: Make sure it isn't using a separate proxy
Go to Settings → General → Network Settings → Settings. Select “Use system proxy settings” and test again. If “Manual proxy configuration” is selected, check the HTTP, HTTPS, or SOCKS address and port. Also check the “No proxy for” list, especially domain suffixes added for a development environment.
PAC: The browser decides whether to send requests to Clash
In a PAC script, FindProxyForURL selects a route based on the URL and hostname. If it returns DIRECT, the request won't go through the local HTTP proxy. If it returns PROXY 127.0.0.1:7890, the request goes to that port. If the result is PROXY 127.0.0.1:7890; DIRECT, the app may fall back to a direct connection if the proxy is unavailable; the exact behavior depends on the app.
PAC bypass and a Clash rule selecting a direct connection happen at different stages. PAC decides whether to use a proxy; Clash rules decide where a request goes after it reaches the core. Temporarily disable automatic configuration and keep only the correct manual HTTP proxy to narrow things down. Note the original settings and restore them afterward. Don't casually override an organization-managed PAC script on a work device.
Terminal troubleshooting: Establish a baseline with an explicit proxy
Many command-line tools don't read system proxy settings. If a browser works but curl still connects directly, that doesn't mean Clash is broken. First eliminate ambiguity from environment variables by explicitly specifying the local proxy in the command.
Test in Windows PowerShell
Use curl.exe to avoid the Windows PowerShell 5.1 curl alias, which points to a different command. This command accesses a sample site through the local HTTP proxy and uses the command-line bypass list to override any NO_PROXY setting:
curl.exe -v --connect-timeout 10 --max-time 30 --proxy http://127.0.0.1:7890 --noproxy localhost https://example.com/ --output NUL
Here, --noproxy localhost bypasses the proxy only for localhost; the test destination example.com isn't on that list. This also avoids differences in how some older PowerShell versions pass an empty-string argument. The domain is only an example for demonstrating the request path; whether it is reachable doesn't indicate whether other sites will work.
Test on macOS and Linux
curl -v --connect-timeout 10 --max-time 30 \
--proxy http://127.0.0.1:7890 --noproxy "" \
https://example.com/ --output /dev/null
In the verbose output, check the local connection address and HTTPS tunnel negotiation. CONNECT example.com:443 means curl is asking the HTTP proxy to open a tunnel. A 200 Connection established response doesn't guarantee that the subsequent TLS handshake or web request will succeed; check the final result and the client's connection log.
Connection refused: Check the local port and whether the core is listening.- The tunnel is established, then TLS fails: Check the system clock, certificate trust, and any HTTPS inspection software. Don't treat disabling certificate verification as a fix.
- The client reports a node connection timeout: The request has entered the proxy chain; continue by checking the node and remote connection.
Environment variables and app settings: Changes only affect the right processes
After the explicit proxy test succeeds, set environment variables for the terminal processes that need a proxy. For curl, HTTPS destinations can use https_proxy; the http:// in the variable value describes the connection from the client to the proxy, so it doesn't need to be changed to https://. Supported variables and precedence differ across tools.
Check the current values first
# PowerShell: list proxy-related environment variables for the current process
Get-ChildItem Env: | Where-Object Name -Match '^(http_proxy|https_proxy|all_proxy|no_proxy)$'
# macOS / Linux
env | grep -iE '^(http_proxy|https_proxy|all_proxy|no_proxy)='
Look for stale ports, old proxy addresses, and NO_PROXY or no_proxy. For example, NO_PROXY=* bypasses all proxies in tools that support this convention. Check each tool's documentation for domain-suffix matching rules. curl handles HTTP proxy variables specially for security; in POSIX shells, prefer lowercase http_proxy and don't set only uppercase HTTP_PROXY.
Set variables for the current terminal only; verify them before making them persistent
# PowerShell: applies to the current process and subsequently launched child processes
$env:http_proxy = "http://127.0.0.1:7890"
$env:https_proxy = "http://127.0.0.1:7890"
# macOS / Linux: applies to the current shell and subsequently launched child processes
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
These settings don't automatically affect IDEs, background services, or other terminal windows that are already running. To verify environment variables, launch the target program again or run it directly from the current terminal. sudo may filter the environment. In WSL, containers, and remote SSH sessions, 127.0.0.1 doesn't necessarily refer to the host machine; first check the network boundaries and the address that's actually reachable.
Git may also have its own proxy settings. Run these commands to find where the settings come from. Inspect them before changing anything to avoid overriding repository or organization requirements:
git config --show-origin --get-regexp 'http\..*proxy|https\..*proxy'
After a request reaches the core: Check Rule, DIRECT, and policy groups
Find the request in Connections and check its destination domain, matched rule, rule payload, and proxy chain. Field names vary by client, but the logic is the same: if the chain is DIRECT, this request was routed directly. If a policy group and actual node are shown, continue troubleshooting with that node.
- Check the mode:
Ruleroutes traffic according to rules,Directconnects directly, andGlobaluses the global policy. The system proxy toggle is separate from these three modes. - Check rule order: Rules are generally evaluated in order. Earlier domain, IP, or rule-set entries may match first; the final
MATCHrule won't override an earlier match. - Check the group selection: Even if a rule points to a policy group named “Proxy,” that group may have selected
DIRECT. The group name doesn't guarantee the actual egress route. - Check domain information: Direct IP connections, DNS caches, or different traffic interception methods can change the information available to the core for matching. A domain rule failing to match doesn't by itself mean the rule set is broken.
If needed, temporarily switch to Global and select a known-working node for comparison. If Global works but Rule mode connects directly, focus on the rules and group selection. Restore the original mode after testing. Existing TCP or HTTP/2 connections may not be recreated after you change nodes or rules; the app must start a new connection to test the new route.
Consider TUN for traffic the system proxy can't handle
A system HTTP proxy doesn't capture all UDP traffic and may not cover games, command-line tools, or other apps with their own networking stacks. Clash Meta (mihomo) TUN mode routes traffic through a virtual network interface, covering different traffic from the system proxy. Its behavior still depends on platform permissions, routes, DNS settings, and core configuration.
Don't enable TUN, change DNS, and switch to Global all at once before confirming the local port. Even if the result changes, you won't know which step made the difference. If the target app truly doesn't support proxies, follow the client's instructions for TUN service or administrator permissions, and check for conflicts with VPNs or other virtual network interfaces. Browser secure DNS affects DNS resolution; it isn't the same as bypassing the HTTP proxy.
Retest and record results: Compare before and after using the same destination
- Record the client name and exact version, core version, OS version, and HTTP or mixed proxy port; don't just write “latest.”
- Change one thing per test. Keep the test domain, request tool, and selected node the same, and record the test time.
- Save the browser result, explicit-proxy curl result, matched rule, and actual proxy chain from the Connections page.
- If you need to check your exit IP, use a trusted service and compare it with the connection logs. The location shown by a single site may be outdated and isn't a substitute for evidence from the connection path.
- Before sharing troubleshooting details, remove subscription URLs, access tokens, node credentials, and personal browsing records. Review verbose command output as well.
You should be able to pinpoint the issue: the local port isn't listening, the app isn't using the proxy, PAC or an exception list is bypassing it, a rule selects a direct connection, or the proxy chain can't connect. When the explicit proxy test, browser settings, and core logs all agree, there's no need to guess by repeatedly reinstalling the client. For the basic setup sequence, see the Getting Started guide. For details on rules and DNS, see Advanced Config.