Clash System Proxy Is On but Not Working: Troubleshoot Browsers and Terminals

Browser extensions, system proxy settings that weren't applied, and terminals that ignore system proxy settings are the most common causes. Follow separate browser and command-line checks, including environment variable setup.

First, determine whether the request reached the core or a rule sent it DIRECT

Open the client's connections page, then visit the target site again. A system proxy is a proxy setting provided by the operating system, and only apps that read this setting will use it. The client's “Enabled” status does not mean your browser, terminal, and background services are all using the proxy.

First, understand the two roles. The GUI client toggles system settings and displays connections; the Clash or mihomo core listens on ports, matches rules, and forwards requests. mihomo is the renamed Clash Meta core. A request reaches the core through this route only if all three conditions are met: the core is running, the system proxy is configured correctly, and the app is set to use it.

What you seeCheck firstNext step
No new connection appears after browsingSystem proxy, extensions, and browser-specific settingsCheck the proxy address and port, then temporarily disable proxy extensions
Browser works, but no new connection appears for terminal requestsThe command-line tool isn't using the system proxyTest with curl and an explicit proxy
A connection appears, with DIRECT as the exitA rule matched DIRECTCheck the matched rule and full policy chain
A connection appears, but the proxy chain times outNode connectivity or remote DNS resolutionCheck the logs instead of repeatedly toggling the system proxy

Close and reopen the target page, or run a new command-line request. Browser caches, background connections, and filters on the connections page can all affect what you see. No new entry is a clue, not proof. If you're using TUN mode, note its current state first. TUN routes traffic through a virtual network interface, so tests may no longer reflect system proxy behavior alone.

Check the local port: 7890 is only an example

Check the client's HTTP or mixed port, then verify the system settings. A mixed port accepts both HTTP and SOCKS proxy connections on the same port. This article uses 127.0.0.1:7890 as an example; if your port is 7897, replace it in the commands below too.

# mihomo config snippet, not a complete subscription config
mixed-port: 7890
allow-lan: false
mode: rule

Don't mistake the controller port for a proxy port. external-controller provides a control interface; even if it responds, it can't replace an HTTP proxy listener. Don't enable “Allow LAN” just to connect from a browser on the same machine, either. A loopback address is usually all you need.

Check whether the port is actually listening

Run the following command in Windows PowerShell. A listening entry only tells you that something is using the port; verify that the process belongs to the core for your current client.

Get-NetTCPConnection -LocalPort 7890 -State Listen |
  Select-Object LocalAddress, LocalPort, OwningProcess

# Enter the process ID from the previous output at the prompt
Get-Process -Id (Read-Host "Enter OwningProcess ID")

Use lsof on macOS and ss on Linux. If there's no output, check the core startup logs, the actual port, and whether startup failed before changing browser settings.

# macOS
lsof -nP -iTCP:7890 -sTCP:LISTEN

# Linux
ss -lntp 'sport = :7890'

Browser troubleshooting: check system settings, then rule out extension overrides

Step 1: Check that the system proxy settings were applied

In Windows 11, go to Settings → Network & internet → Proxy → Manual proxy setup → Edit. With manual proxy enabled, the address should point to the local loopback address and the port should match the client. If the client uses PAC (a Proxy Auto-Configuration script), check “Use setup script” and its script address instead; you don't also need to enable the manual proxy toggle.

On macOS 13 and later, go to System Settings → Network → your current network service → Details → Proxies. Check Web Proxy (HTTP) and Secure Web Proxy (HTTPS). “Secure Web Proxy” doesn't mean the local port needs TLS; it usually connects to a local HTTP proxy port, which then establishes the HTTPS tunnel.

  • Quit other clients that automatically change the system proxy to prevent them from overwriting the settings as soon as they're applied.
  • Check the proxy exceptions list. If the target domain is listed as an address to bypass, the browser may connect directly.
  • Check the settings again after switching between Wi-Fi, Ethernet, or a VPN. On macOS, pay particular attention to whether the active network service has changed.
  • If your device is managed by an organization, check for policy restrictions first. Don't repeatedly change settings that a managed policy will overwrite.

Step 2: Check where the browser gets its proxy settings

In the Chrome or Edge extensions manager, temporarily disable extensions with permission to control proxy settings, then test in a new regular window. Proxy extensions can override system settings. Incognito mode isn't a reliable comparison on its own: extensions may be allowed in incognito, and browser policies still apply.

In Firefox, go to Settings → General → Network Settings at the bottom of the page → Settings. To follow client changes, select “Use system proxy settings.” For an isolated test, temporarily choose manual proxy configuration and enter the actual address. Restore the original setting afterward to avoid leaving a stale port in place when you switch clients.

If only one browser fails, visit the same address in another browser for comparison. If the other browser appears on the connections page, check the original browser's extensions, profile, and enterprise policies first; there's no need to reinstall the core.

Terminal troubleshooting: use an explicit proxy command as a baseline

Don't rely on environment variables yet; pass the proxy directly to curl. Many command-line tools don't automatically use the desktop system proxy, so a working browser doesn't mean your terminal should work too. The commands below work in common macOS and Linux shells and use https://example.com/ as the test URL.

curl -q -v --connect-timeout 10 --max-time 30 \
  --noproxy "" \
  --proxy http://127.0.0.1:7890 \
  https://example.com/ -o /dev/null

In Windows PowerShell, call curl.exe explicitly to avoid the curl alias in Windows PowerShell 5.1, which points to a different command. Use NUL to discard the response body:

curl.exe -q -v --connect-timeout 10 --max-time 30 --noproxy "" --proxy http://127.0.0.1:7890 https://example.com/ -o NUL
  • Put -q first to prevent your user-level curl config file from affecting this test.
  • --noproxy "" clears the bypass list for this request so the target address isn't excluded from the proxy.
  • --connect-timeout 10 limits the time spent connecting; --max-time 30 limits the total transfer time. Both values are in seconds.
  • In the verbose output, first confirm the actual port used to connect to 127.0.0.1, then check the HTTPS CONNECT tunnel and the response that follows.

If you see Connection refused, check the local listening address and port. For 407 Proxy Authentication Required, check whether local proxy authentication is enabled. If the request times out after the tunnel is established, investigate the policy group and node. A site returning 403 doesn't mean the proxy wasn't used; the destination may be restricting access.

Don't judge by whether a web page opens. A successful explicit-proxy request, together with a matching entry on the client's connections page, confirms the app-to-core path is working. Then check whether the rules selected the expected exit.

Set terminal proxy environment variables: HTTP vs. SOCKS

macOS and Linux: start with the current shell

Run these settings in the current terminal, then test with a command that doesn't include --proxy. https_proxy specifies the proxy to use for HTTPS destinations. Its value can still start with http://, because that describes the protocol used by the local proxy service.

export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export no_proxy="localhost,127.0.0.1,::1"

curl -q -v --connect-timeout 10 --max-time 30 \
  https://example.com/ -o /dev/null

Once confirmed, you can add the settings to a file your current shell actually reads, such as ~/.zshrc or ~/.bashrc. Don't start by adding them globally: after the client exits, the terminal would keep trying to connect to a closed port. Environment variables usually affect only the current process and any child processes started afterward; they don't change programs that are already running.

If your tool explicitly supports SOCKS, you can make a one-off call as shown below. The h in socks5h means the proxy resolves the target domain; with socks5, the local machine usually resolves it first. This works only if the port actually has a SOCKS or mixed listener enabled.

curl -q --proxy socks5h://127.0.0.1:7890 \
  --noproxy "" --connect-timeout 10 --max-time 30 \
  https://example.com/ -o /dev/null

Windows PowerShell: set environment variables for the current process

Use $env: in PowerShell; don't copy the shell export syntax. These settings apply to the current PowerShell process and child processes started afterward, not to other terminal windows that are already open.

$env:http_proxy = "http://127.0.0.1:7890"
$env:https_proxy = "http://127.0.0.1:7890"
$env:no_proxy = "localhost,127.0.0.1,::1"

curl.exe -q -v --connect-timeout 10 --max-time 30 https://example.com/ -o NUL

Don't use setx for your first test. It writes persistent environment settings, which usually require a new process to take effect and can be confused with old values in the current window. Tools vary in which variable names they support and prioritize. For curl's HTTP proxy, use lowercase http_proxy; don't assume every tool reads uppercase HTTP_PROXY.

Check for stale variables and tool-specific proxy settings

If an explicit proxy works but a regular command doesn't, check whether ALL_PROXY, all_proxy, NO_PROXY, or no_proxy still points to an old port or includes the target domain. Tools such as Git also have their own settings. The commands below only show where settings come from; they don't modify any files:

git config --show-origin --get-regexp '.*proxy.*'

No output isn't necessarily an error; it means no matching setting was found. If you find an old setting, check which file it belongs to and whether another work environment still uses it before changing it. Before sharing terminal output, redact proxy usernames and passwords, subscription links, and URLs containing access tokens.

Request reaches the core but still doesn't use a proxy: check rules and policy groups

First, check the matched rule and final exit in the connection details. Rules are matched in configuration order. If a request matches DIRECT, the core chose a direct connection; the system proxy isn't failing. A policy group may also include DIRECT, so seeing the group name alone isn't enough—check the full chain.

  1. Test the same destination and record the current mode, matched rule, and policy chain.
  2. Check that the selected proxy group is using an available node, not the DIRECT option.
  3. If needed, briefly switch to Global mode, confirm the global policy group has a proxy node selected, then send the same request again.
  4. If Global mode works but Rule mode goes DIRECT, check the rule order. If both time out, investigate the node and logs.
  5. Restore Rule mode after testing to avoid changing how other apps are routed long term.

Remember: using a proxy and reaching the destination are two different things. An unavailable node, remote restrictions, or DNS resolution failures can all occur after a request reaches the core. Don't keep adding domain rules to fix a local connection refusal, and don't reinstall the client instead of checking which rule matched.

WSL, containers, and TUN: troubleshoot special environments last

First, confirm which system is running the command. In WSL, Docker containers, and virtual machines, 127.0.0.1 may not point to the host. WSL 2 behaves differently in NAT and mirrored networking modes, and the host address for Docker depends on the environment. If the host browser works but a container gets a connection refusal, investigate the network boundary instead of copying the loopback address directly.

Only evaluate listener addresses, Allow LAN, and firewall rules if a connection across network boundaries is actually needed. Exposing the proxy listener on additional interfaces makes it accessible to more devices, so restrict trusted sources and configure authentication as needed. Don't expose the port to the public internet just to troubleshoot a terminal.

Consider TUN mode only for apps that don't support proxy settings or read proxy environment variables. TUN typically requires system privileges and takes over routing and DNS; it isn't a shortcut for fixing a wrong port. Note the original state before enabling it to avoid making troubleshooting harder if another VPN or virtual network interface is also active.

Restore settings and keep a concise troubleshooting record

Restore temporary changes first, then test your usual workflow. If you didn't previously have proxy variables set, use the commands below to clear the variables added for this test. If they already had values, restore those values instead of deleting them.

# macOS / Linux: clear only the lowercase variables temporarily set in this article
unset http_proxy https_proxy no_proxy

# PowerShell: clear only the process variables temporarily set in this article
Remove-Item Env:http_proxy, Env:https_proxy, Env:no_proxy -ErrorAction SilentlyContinue

Keep a record of four things: the actual listening port, the explicit curl test result, the browser's proxy source, and the rule and exit shown in the connection details. This helps pinpoint whether the issue is with app settings, the local listener, or forwarding through the core—instead of just noting that the proxy was on but didn't work.

Download ClashChoose a client platform