First, distinguish the system proxy from the actual traffic path
The “System Proxy” option in a Clash client usually is not a global tunnel that covers every application. It writes the operating system’s HTTP and HTTPS proxy address as 127.0.0.1, with the port pointing to the local port Clash is listening on. Once the browser reads this setting, it hands requests to Clash; whether a terminal program reads it depends on the program, its launch environment, and the proxy protocol.
Common defaults are HTTP port 7890 and SOCKS5 port 7891. A single mixed-port: 7890 can also accept both HTTP and SOCKS5. Ports are not standardized. The configuration file, client version, or a user override may change them. Before troubleshooting, check the client’s “Settings” → “Port Settings” or the fields in the active configuration.
mixed-port: 7890
allow-lan: false
mode: rule
dns:
enable: true
enhanced-mode: fake-ip
When webpages open but curl, git, npm, or another command-line downloader still connects directly, the node is usually not completely down. More precisely, the browser path has entered Clash while the terminal path has not, or the terminal uses different DNS, protocols, or rules after entering Clash.
Path 1: How browsers read the system proxy
Confirm that Clash is listening on the local port
When the system proxy points to a port with no listener, the browser usually reports that the connection was refused. Windows PowerShell can check 7890; macOS and Linux can inspect the corresponding process. If the actual port is not 7890, replace the number in the command.
# Windows PowerShell
Get-NetTCPConnection -LocalPort 7890 -State Listen
# macOS
lsof -nP -iTCP:7890 -sTCP:LISTEN
# Linux
ss -lntp | grep 7890
The expected result should include a local listening address, such as 127.0.0.1:7890 or 0.0.0.0:7890. If there is no output, return to the client and check that the configuration is running, the proxy switch is enabled, and no other program is using the port. If there is a conflict, temporarily switch to 7897, then update the system proxy and terminal variables accordingly.
Check the operating system proxy address
- Windows 11: open “Settings” → “Network & internet” → “Proxy” → “Manual proxy setup”. The address should be
127.0.0.1, and the port should match Clash’s HTTP or mixed port. - macOS: open “System Settings” → “Network” → the current network interface → “Details” → “Proxies”. Check Web Proxy (HTTP) and Secure Web Proxy (HTTPS).
- Firefox: open “Settings” → “General” → “Network Settings”. If “Manual proxy configuration” is selected, it overrides the system proxy. To follow the operating system, select “Use system proxy settings”.
- Chrome and Edge usually read the operating system proxy, but extensions, enterprise policies, and browser startup parameters can still override this path.
For browser testing, check both the page result and Clash’s connection log. Open a site you have not visited before, then filter the client’s connection page by domain. If the target domain, matched rule, and exit node appear, the request has entered the core. A page loading by itself cannot distinguish proxy access from a cache hit or a direct connection.
Check whether the rules send browser traffic direct
Enabling the system proxy only means traffic enters Clash; it does not guarantee that a proxy node is used. In mode: rule, requests still go through rule matching. If the connection log shows DIRECT, check the domain rules, rule providers, and final rule. Temporarily switching to Global mode can provide a comparison, but restore Rule mode after testing.
rules:
- DOMAIN-SUFFIX,example.com,Proxy
- GEOIP,CN,DIRECT
- MATCH,Proxy
If Global mode works but Rule mode does not, the issue is with rule order, proxy group selection, or generated subscription content—not the system proxy switch. Clash matches rules from top to bottom and stops at the first match. A broad DIRECT rule placed early may intercept later domain rules.
Path 2: Why terminal programs do not follow the proxy
A terminal window does not forward network traffic automatically. The requests are actually made by curl, Git, Node.js, Python package managers, or other commands. Each program has its own proxy logic. Some read HTTP_PROXY and HTTPS_PROXY, some read lowercase variables, some accept only command-line options, and others use separate configuration files.
Use an explicit proxy with curl as a baseline test
First bypass environment variables and connect curl directly to Clash’s HTTP port. This separates “the terminal did not read the system setting” from “Clash’s local proxy is unavailable.”
curl -v -x http://127.0.0.1:7890 https://api.ipify.org
curl -v --connect-timeout 10 \
-x http://127.0.0.1:7890 \
https://www.example.com/
The output should first show a connection to 127.0.0.1:7890, followed by the HTTPS CONNECT exchange. If an explicit proxy works but the request fails without -x, the node, port, and Clash core are basically working; only the terminal configuration needs attention.
For a SOCKS5 test, use socks5h. The trailing h sends hostname resolution to the proxy, which helps rule out local DNS problems. With socks5, the hostname is usually resolved locally before the IP address is sent to the proxy.
curl -v --proxy socks5h://127.0.0.1:7891 \
https://api.ipify.org
Set environment variables for the current terminal
On macOS, Linux, Git Bash, and most Unix-like shells, you can export variables for the current session. It is recommended to set both uppercase and lowercase forms to support tools with different lookup rules. These temporary variables expire when the terminal window closes.
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
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 -v https://api.ipify.org
PowerShell can write variables to the current process environment. This affects only that PowerShell window and child processes launched from it; it does not automatically change an editor or another terminal that is 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 -v https://api.ipify.org
After testing, clear the test variables so programs do not keep trying to use an invalid local port after Clash exits.
# bash / zsh
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY NO_PROXY
# PowerShell
Remove-Item Env:HTTP_PROXY
Remove-Item Env:HTTPS_PROXY
Remove-Item Env:NO_PROXY
Separate configuration for Git, npm, and Python
Environment variables are useful for one-off troubleshooting. For long-term use, also check whether a tool has saved an old port. Git can read both global and repository configuration; repository-level settings take priority.
git config --global --get http.proxy
git config --global --get https.proxy
git config --local --get http.proxy
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
# Remove the global proxy
git config --global --unset http.proxy
git config --global --unset https.proxy
Use npm config get proxy and npm config get https-proxy to check npm. When a value is null, npm may continue to consult environment variables. If an old setting still points to 127.0.0.1:7897, npm will keep using that port even after the system proxy has been changed to 7890.
npm config get proxy
npm config get https-proxy
npm config set proxy http://127.0.0.1:7890
npm config set https-proxy http://127.0.0.1:7890
npm config delete proxy
npm config delete https-proxy
Python’s pip can read environment variables and can also be tested with command-line options. For a one-time installation, an option is easier to undo than permanently writing a proxy into the configuration.
python -m pip install --proxy http://127.0.0.1:7890 package-name
python -m pip config list
python -m pip config debug
DNS, IPv6, and UDP: traffic can still fail after entering the proxy
Distinguish resolution failures from connection failures
Keywords in terminal errors can narrow down the cause. Could not resolve host points to the hostname resolution stage; Connection refused usually means the local proxy port is not listening; Operation timed out may indicate the node path, rule exit, firewall, or a timeout from the destination. TLS certificate errors require checking the system clock, certificate store, and the TLS backend used by the program.
When using an HTTP proxy to access an HTTPS site, the client generally sends CONNECT to the proxy first. With SOCKS5, socks5h and socks5 resolve hostnames in different places. If regular socks5 fails but socks5h works, check local DNS first instead of immediately replacing the subscription.
Check IPv4 and IPv6 results
Some terminal programs prefer IPv6, while the current network may have incomplete IPv6 routing. Run curl -4 and curl -6 separately for comparison. If IPv4 returns within 2 seconds but IPv6 times out after 10 seconds, the problem is on the IPv6 path, not with the HTTP proxy variables.
curl -4 -I --connect-timeout 10 https://www.example.com/
curl -6 -I --connect-timeout 10 https://www.example.com/
curl -4 -I -x http://127.0.0.1:7890 https://www.example.com/
curl -6 -I -x http://127.0.0.1:7890 https://www.example.com/
Also note that a traditional HTTP system proxy mainly handles HTTP and HTTPS over TCP. QUIC, game traffic, voice applications, and custom UDP-based protocols may not use this entry point. A browser may fall back to TCP in a proxy environment, while another application may not, resulting in webpages working normally but a specific app timing out.
When to switch to TUN mode
TUN mode uses a virtual network interface and system routes to handle more IP traffic. It does not require every application to understand HTTP proxies or read HTTP_PROXY. TUN is usually a better fit when you need to cover multiple terminal tools or UDP applications, proxy-unconfigurable software, or want to reduce the need to maintain proxy variables individually.
When switching to TUN makes sense
- The browser reliably enters Clash, but multiple command-line tools ignore the system proxy.
- An application uses a custom TCP or UDP protocol and has no HTTP, HTTPS, or SOCKS5 proxy settings.
- The development environment includes containers, package managers, and background processes, making individual environment-variable configuration expensive.
- DNS queries and connection traffic should follow the same rules to reduce differences in local resolution paths.
- You want rules to determine
DIRECT, proxy groups, and the final exit even with the system proxy disabled.
Common mihomo core settings include tun.enable, stack, auto-route, and DNS hijacking. Available values depend on the core version bundled with the client and the operating system’s permissions. Before editing, keep a copy of the currently working Profile and enable TUN through the client’s provided settings. Do not manually create a second set of system routes at the same time.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
tun.enable: true · stack: mixed · auto-route: true
After enabling it, disable the system proxy and run a comparison test to prevent the same request from entering the system proxy first and then being taken over again by TUN routing. Most cores can handle this combination, but keeping one path during troubleshooting makes the results easier to interpret. Then test the browser, curl, Git, and the target app separately, and confirm the matched rule in the connection log.
System proxy and VPN paths on Android
Android clients typically create a local VPN interface through the system VpnService, rather than relying on the HTTP proxy settings common on desktop systems. The connection request shown on first launch is Android system authorization. After approval, the app can create the VPN interface and receive traffic routed to it.
If an Android browser works but commands in Termux do not, first check whether the client has enabled per-app proxying, app bypass, or proxying for selected apps only. Exact menu names vary by client; common locations include “Settings” → “Network” → “Access Control” or “Settings” → “Preferences” → “Per-app proxy”. If Termux is not included in the proxy app list, its traffic may go directly over the physical network.
- Search the connection log for the destination domain requested by Termux.
- Check whether Access Control is set to “Proxy selected apps only” or “Bypass selected apps”.
- Temporarily disable Private DNS for a brief comparison, then restore the original setting and record the result.
- Confirm that battery-saving policies are not terminating the VPN service after the screen turns off.
- Check whether DNS, TUN, and rule groups in the active Profile are actually taking effect.
Termux can still use export HTTPS_PROXY=http://127.0.0.1:port, but the loopback address and port must actually be exposed to local apps by the Android client. If the client works mainly through a VPN interface and does not expose a local HTTP listener, setting this variable will not create a usable connection. In that case, fix the VPN app scope first instead of copying desktop port settings.
Final checklist, in order
- In the Clash client, confirm that the Profile is running and the proxy group has a working node selected.
- Read the current
mixed-port,port, orsocks-port; do not assume it is always7890. - Use a listening command to confirm that the local port exists and rule out port conflicts.
- Open a new browser page while checking Clash’s connection log and matched rule.
- Run
curlwith-xto establish an explicit-proxy baseline. - After the explicit proxy succeeds, set proxy environment variables for the current terminal.
- Check saved proxy settings and old ports in Git, npm, pip, and other tools.
- Use
socks5h,-4, and-6to distinguish DNS and IP paths. - When you need to handle non-HTTP traffic, UDP, or many background processes, switch to TUN for a single-path test.
- After testing, clear temporary variables and restore Rule mode and the original DNS settings.
The key question is not whether the proxy switch is on, but which path the request actually takes. For browsers, check the system proxy and rules; for terminals, check command options, environment variables, and separate configuration; for complex applications, check TUN, routing, and DNS. Checking the listening port, explicit proxy, environment variables, tool configuration, and TUN in that order usually locates the problem without changing the subscription.