Clash System Proxy Not Working on macOS: Troubleshoot Browsers and Terminal Separately

Safari and Chrome use the system proxy, but terminal commands don’t by default. Troubleshoot both paths: check macOS proxy settings, then set http_proxy for your shell.

Understand system proxy, terminal proxy, and TUN

When the Clash client says “System Proxy: On,” it means the client has attempted to write proxy settings to macOS—not that all app traffic is being routed through it. Safari typically uses the system proxy. Chrome does too by default, though extensions, launch flags, or organization policies can change that. Command-line tools in Terminal each have their own proxy options, so a browser’s ability to load a page doesn’t tell you whether they’re using a proxy.

The graphical client imports configuration, switches proxy groups, and manages system settings. The core listens on proxy ports, matches rules, and forwards requests. The core may fail to start because of a configuration error even while the client interface is running. Check separately that the proxy settings were applied and that the local port is actually accepting connections.

Connection methodWhat to checkScope
System proxyProxy settings for the active macOS network serviceApps must honor these settings
Explicit proxy in TerminalCommand-line options, environment variables, and tool settingsUsually affects only the specified process and its child processes
TUN modeVirtual interface, routes, DNS, and permissionsRequires client and core support; it’s a separate connection path

Check that the core is running and listening locally

Check the running configuration, not just the subscription file

In the client, first confirm that the current configuration loaded and check the actual HTTP, SOCKS, or mixed port. Menu names and override behavior vary between clients, so there’s no single set of steps that applies to all of them. Client settings may also override the port in the subscription file, so check the running configuration and startup logs first.

Cores that support a mixed port can accept both HTTP and SOCKS requests on the same port. This is a partial configuration example, not a complete subscription with nodes and proxy groups; there’s no need to overwrite your original file for troubleshooting:

mixed-port: 7890
allow-lan: false
mode: rule

allow-lan: false doesn’t prevent local access through 127.0.0.1. If you’re troubleshooting this Mac only, there’s no need to enable LAN access to make the system proxy work. To check for a listening TCP port, run:

lsof -nP -iTCP:7890 -sTCP:LISTEN
  • If you see a listening socket, check that it belongs to the expected client or core and that it’s bound to an address reachable through the local loopback interface.
  • If there’s no result, check that you have the right port, that the core started successfully, and that the configuration logs don’t show parsing errors. If needed, run the check with administrator privileges to verify that process visibility isn’t the issue.
  • If another program is using the port, resolve the conflict, then update both the client’s listening port and the system proxy port. Don’t change just one.

Test the proxy directly, without using system settings

curl -I -v --connect-timeout 10 --max-time 20 \
  --noproxy "" \
  --proxy http://127.0.0.1:7890 \
  https://example.com/

This command connects to an HTTPS URL through the specified HTTP proxy. --noproxy "" bypasses the current no-proxy list for this test. example.com is only a connectivity test target; replace it with the site that’s actually having trouble and test again. The response doesn’t have to be 200. The goal is to distinguish a local connection failure, a failed proxy tunnel, a TLS error, and an HTTP response from the remote server.

If you see an error connecting to 127.0.0.1:7890, fix the local listener first. If the connection to the local proxy succeeds but then times out, check the client’s connection logs, matched rules, and node logs. If an explicit proxy works but the browser still fails, focus on how macOS proxy settings are being applied.

Browser proxy not working: check the active network service’s proxy settings

Confirm which Wi-Fi or Ethernet service you’re using

On macOS versions with System Settings, go to “System Settings” → “Network” → the active network service → “Details” → “Proxies.” For Wi-Fi, you can also go to “System Settings” → “Wi-Fi” → “Details” for the connected network. On older versions, open System Preferences and go to “Network” → the active service → “Advanced” → “Proxies.” Follow the labels shown on your Mac.

Check “Web Proxy (HTTP)” and “Secure Web Proxy (HTTPS).” The server should be 127.0.0.1, and the port should match the client’s HTTP or mixed port. The HTTPS proxy setting is for requests to HTTPS destinations; it doesn’t mean the local proxy address should be https://127.0.0.1.

macOS saves proxy settings per network service. If you’ve switched from Wi-Fi to USB Ethernet, correct settings on the old service don’t mean the new one is configured too. List your services, then check the one currently in use:

networksetup -listallnetworkservices
networksetup -getwebproxy "Wi-Fi"
networksetup -getsecurewebproxy "Wi-Fi"
networksetup -getproxybypassdomains "Wi-Fi"
networksetup -getautoproxyurl "Wi-Fi"
networksetup -getproxyautodiscovery "Wi-Fi"

If the service isn’t named Wi-Fi, replace it with the actual name from the first command and keep the quotes. The output below shows example fields, not results from your Mac. Check both HTTP and HTTPS separately:

Enabled: Yes
Server: 127.0.0.1
Port: 7890
Authenticated Proxy Enabled: 0

Check PAC, bypass lists, and browser overrides

  • Automatic proxy configuration: A PAC script can choose whether to use a proxy or connect directly based on the destination. Note the original settings, then temporarily leave only the proxy method you’re testing enabled. This helps prevent PAC routing from being mistaken for a broken manual proxy.
  • Bypass list: localhost, 127.0.0.1, and *.local are commonly used for local connections. Check that the destination domain or an overly broad wildcard hasn’t been added by mistake; there’s no need to clear all local bypass entries.
  • Browser extensions: Pause proxy-switching extensions in Chrome and test again. On organization-managed devices, check the applicable policies; don’t overwrite managed settings.
  • Multiple clients: Don’t let two proxy tools write to system settings at the same time. If the settings keep reverting to an old port, identify which process is still managing them.

After changing settings, try loading a page again. If needed, fully quit and reopen the browser. Test with a page that hasn’t already loaded to avoid misleading results from the cache. Also check the client’s connection log: no new connection suggests the app isn’t using the proxy. If a connection appears but the rule sends it to DIRECT, the issue is rule selection.

Browser works, Terminal doesn’t: set shell proxy variables

curl, Git, and package managers launched from Terminal don’t all follow the macOS system proxy. Some read environment variables, some use their own settings, and others use the system networking APIs. Test a single command first, then decide whether to configure your entire shell.

Set a proxy for a single command first

http_proxy=http://127.0.0.1:7890 \
https_proxy=http://127.0.0.1:7890 \
curl -I --connect-timeout 10 --max-time 20 https://example.com/

https_proxy still uses http:// because it specifies a local HTTP proxy endpoint. For HTTPS sites, tools typically establish a tunnel using HTTP CONNECT. Don’t change the variable to a TLS proxy URL just because the destination uses HTTPS.

Export variables for the current Terminal session

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"

env | grep -iE '^(http|https|all|no)_proxy='
curl -I --connect-timeout 10 --max-time 20 https://example.com/

These exports affect only the current shell and child processes launched afterward. They won’t change other open Terminal windows or automatically apply to every graphical app launched from the Dock. Tool support for variable capitalization varies. For example, curl uses the lowercase HTTP proxy variable http_proxy; setting only HTTP_PROXY isn’t enough.

If you use a SOCKS endpoint, you can test it with the command below. Use it only if the port supports SOCKS; the mixed port in this example supports both protocols. socks5h sends the destination hostname to the proxy for DNS resolution, helping distinguish local DNS issues from problems with the proxy route.

curl -I --noproxy "" \
  --proxy socks5h://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 20 \
  https://example.com/

Check for existing variables before making settings persistent

Once the temporary test works, add the required export lines to ~/.zshrc for interactive zsh, then open a new window or run source ~/.zshrc. For other shells, use the appropriate startup file. These variables will still point to the local port when the client is closed, so enabling them only when needed usually makes troubleshooting easier.

# Unset common proxy variables in the current shell
unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY

If you added variables to a startup file, remove or comment out those lines too, or they’ll be loaded again in new windows. Check whether all_proxy points to an old port and whether no_proxy includes the destination domain. Matching syntax and variable precedence vary by program, so avoid stacking multiple sets of proxy variables.

Only Git or a package manager fails: check tool-specific settings

If curl works in the same Terminal session but Git still fails, check where Git gets its configuration instead of repeatedly switching the system proxy. An outdated global proxy, a repository-specific proxy, or a URL-specific setting could send Git through a different route.

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

# Use a proxy only for this HTTPS repository request
git -c http.proxy=http://127.0.0.1:7890 \
  ls-remote https://github.com/git/git.git HEAD

The second command tests connectivity to a public repository and doesn’t change global settings. If the output includes an account name, password, or private address, redact it before sharing logs. Only if you’ve confirmed that the global http.proxy setting is wrong should you run git config --global --unset http.proxy. Handle repository-specific and URL-specific settings in their respective scopes.

  • Git requests to HTTPS URLs and SSH requests in the form git@host:repository use separate protocols and connection paths. An HTTP proxy test doesn’t tell you whether SSH is working.
  • Check npm’s separate proxy settings with npm config get proxy and npm config get https-proxy. Record the existing values before changing them.
  • sudo may remove environment variables. Don’t preserve every environment variable just to pass through the proxy; check which settings the tool actually needs.

Requests reach Clash: check rules, DNS, and TUN

If the connection log shows the destination request, that request has at least reached the core. In this case, “the system proxy isn’t working” may not accurately describe the problem. Check the matched rule, the selected proxy group, and the final outbound route. Rule mode typically checks rules in configuration order; the final MATCH rule handles only requests that didn’t match anything earlier. Selecting a proxy group also doesn’t guarantee that its current member is a proxy node.

  1. Rule outcome: Check which rule matched the destination and whether the final route is a node, DIRECT, or REJECT. A direct rule can send a request directly even after it passes through the core.
  2. Node and route: Try the same destination with a different working node. The client’s latency test only reports results for its test address; it doesn’t tell you whether the destination site is reachable.
  3. DNS: Distinguish between a local lookup failure, an upstream DNS failure in the core, and a remote connection failure. Enabling fake-ip isn’t a general-purpose fix; it also affects DNS handling and app compatibility.
  4. TUN: Check client support, permissions, routing, and DNS only if you need to handle apps that don’t honor explicit proxy settings. Clients based on mihomo may have different TUN controls, so don’t follow steps for another client’s interface.

Retest in order and restore settings when finished

After making changes, verify each path in order. Both the browser and Terminal need to pass for both connection paths to be configured correctly. Loading one web page doesn’t prove that every app will use the proxy.

  1. Use lsof to confirm that the actual port is listening.
  2. Run an explicit test with curl --proxy to confirm the local endpoint and destination are reachable.
  3. Check the HTTP and HTTPS settings for the active network service, then reload the destination page in your browser.
  4. Review shell variables and tool-specific proxy settings, then test curl and the command you actually need in the same Terminal session.
  5. Before quitting the client, turn off its system proxy management. After quitting, check the network settings to make sure the proxy doesn’t still point to a port that’s no longer listening.

If all web pages stop loading after the client quits unexpectedly, open the “Proxies” settings for the active network service. Note and disable any leftover local manual proxy, then unset Terminal proxy variables and test a direct connection. Restore organization-managed proxy settings and PAC as required; don’t remove them along with the local settings. If you still need help, share the actual port, service name, the failure stage from an explicit proxy test, and redacted connection logs. That’s more useful than simply saying the proxy isn’t responding.

For port and rule fields, see the YAML Reference. For platform-specific steps to import a configuration and enable TUN, see the Setup Guide. The key to troubleshooting is to check the app, local core, and remote connection path separately.

Download Clash