Network Guide Tags: Clash terminal proxy npm Git macOS Linux

npm and git Still Bypass Clash?Terminal Proxy Env Vars on macOS and Linux

You already enabled system proxy or TUN in a Clash client, and Safari or Chrome loads foreign sites—yet npm install stalls, git clone over HTTPS times out, and curl to GitHub never finishes. That is normal: many desktop clients patch the macOS network stack or route packets at layer three, while POSIX shells and CLI tools only pick up traffic when you give them explicit forwarders through environment variables such as http_proxy, HTTPS_PROXY, and ALL_PROXY, plus optional per-tool settings for Git and npm. This guide walks through choosing the correct localhost port, exporting variables in zsh and bash, shaping no_proxy for LAN and registry mirrors, verifying with curl, and knowing when the problem is rules or DNS instead of missing terminal proxy configuration.

Approx. 22 min read
Clash Editorial

1. Why the Browser Works but the Terminal Does Not

Graphical browsers on macOS consult the system-wide proxy dictionary that your Clash client updates when you toggle Set as system proxy. They may also honor PAC files or per-profile settings managed by the operating system. Command-line programs are not required to read those dictionaries. Unless a tool explicitly integrates with macOS network extension APIs—which git, stock npm, and most language package managers do not—it will open outbound TCP connections using whatever default route and resolver the kernel exposes, which is exactly the path that was failing before you installed Clash.

TUN mode is different: it can redirect many processes transparently once the virtual interface owns the right routes. Even then, edge cases appear. Some binaries bind to specific interfaces, corporate VPNs fight over routing metrics, or systemd-resolved on Linux still forwards DNS queries outside the tunnel. Developers therefore keep terminal proxy variables as a portable baseline: they make intent explicit, work across shells and CI-like workflows, and pair cleanly with split outbound policies inside Clash because the forwarder is always 127.0.0.1 and a known port.

If you are running the core as a service on Linux, our systemd-oriented Linux install guide covers directory layout and listening ports before you wire shells. On macOS, when the GUI claims the system proxy is on but apps misbehave, read Clash Verge on macOS: system proxy and Network Extension to separate permission issues from missing CLI exports.

2. Find the Right Clash Port

Clash-family cores expose one or more local listeners. The names differ slightly by client, but the idea is stable: you need the integer that accepts HTTP CONNECT or SOCKS5 from localhost. Common patterns include a dedicated HTTP port, a mixed port that speaks both HTTP and SOCKS on one socket, and sometimes a separate SOCKS port. Open your client’s settings screen and note the values while Clash is running.

For HTTP-style proxies, schemes look like http://127.0.0.1:7890. For SOCKS5, use socks5h://127.0.0.1:7891 when you want the proxy to perform DNS resolution for remote names—often preferable with split DNS or fake-IP setups. If you only have a mixed port, you can still point http_proxy at http://127.0.0.1:<mixed> and ALL_PROXY at socks5h://127.0.0.1:<mixed> on cores that multiplex protocols on the same listener; when in doubt, test with curl as shown later.

Tip: Write the port on a sticky note the first time you set up a machine. Typos like 7980 instead of 7890 produce identical “hang forever” symptoms as a firewall block, but logs stay silent until you probe manually.

When you share a proxy to other devices on the LAN, the forwarder address may be your gateway IP instead of loopback; that scenario is closer to our Windows-focused mixed-port article. On a single-user Mac or Linux laptop, loopback is the default and avoids exposing the forwarder unnecessarily.

3. Environment Variables That Actually Matter

Unix programs conventionally read both lowercase and uppercase forms. Setting both reduces surprises when a library checks only one spelling. The table below summarizes the trio most tutorials mention plus the catch-all that tools like curl and many Rust or Go binaries respect.

Variable Typical value What it affects
http_proxy / HTTP_PROXY http://127.0.0.1:PORT Plain HTTP and many HTTPS stacks that tunnel via HTTP CONNECT
https_proxy / HTTPS_PROXY Same as HTTP or explicit http:// forwarder Libraries that distinguish TLS origins even though the forwarder URL stays http://
all_proxy / ALL_PROXY socks5h://127.0.0.1:PORT Fallback for tools that prefer SOCKS or need remote DNS
no_proxy / NO_PROXY localhost,127.0.0.1,::1,.local Hosts that must never be sent through the tunnel

Example export block

Replace 7890 with your real mixed or HTTP port. Keeping both HTTP and SOCKS lines makes Git, npm, and curl agree without micromanaging each binary:

export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
export all_proxy="socks5h://127.0.0.1:7890"
export ALL_PROXY="$all_proxy"
export no_proxy="localhost,127.0.0.1,::1"
export NO_PROXY="$no_proxy"

Some teams append internal registry hostnames to no_proxy so private npm mirrors stay direct while public registries use Clash. Maintain that list deliberately—over-broad exemptions weaken the point of split routing, while under-broad lists break installs that must reach a server on your LAN.

4. macOS and Linux Shell Setup

Apple ships zsh as the default login shell on modern macOS; many Linux distributions default to bash. Persist exports in the file your shell actually reads on startup: ~/.zshrc for interactive zsh, ~/.bashrc for bash, and sometimes ~/.profile for login shells that do not source rc files. After editing, run source ~/.zshrc (or the equivalent) in an existing terminal so new variables apply without logging out.

IDE-integrated terminals inherit the environment from the parent process. If you launch Visual Studio Code or JetBrains tools from the Dock, they may not see the same variables as a Terminal.app session started after your rc file loaded. Launching the editor from a shell where exports already exist—or using the GUI’s environment settings—keeps npm inside the IDE consistent with npm in iTerm.

On Linux desktop sessions, display managers sometimes reset environments. If variables disappear after reboot, place guarded exports in ~/.profile or use systemd user environment drops only when you understand session scope. For headless servers, document the proxy alongside your Clash unit so operators know the expected localhost listener.

Note: Never commit real proxy URLs that embed credentials into public repositories. If a provider gives you http://user:pass@host:port, prefer local forwarders on 127.0.0.1 without passwords so secrets stay inside Clash’s encrypted profile store.

5. no_proxy and Local Traffic

no_proxy is easy to ignore until Kubernetes dashboards, Docker registries on 192.168.0.0/24, or company GitLab hostnames accidentally traverse a foreign exit node and break certificate pinning. Add comma-separated hostnames or suffix patterns your organization requires. IPv6 loopback ::1 belongs in the list when tools try dual-stack connects.

Remember that no_proxy matching rules vary slightly between libraries. Some require leading dots for suffix matches; others accept CIDR only through newer helpers. When something still detours through Clash, capture the exact URL your tool requests and compare it to the exemption list character by character.

6. Verify With curl and env

Before touching Git or npm, prove the forwarder works:

curl -I https://www.google.com
curl -x http://127.0.0.1:7890 -I https://www.google.com

If the first command hangs but the second returns headers, your shell environment was missing proxy variables even though Clash is healthy. After exporting, rerun without -x; success means curl picked up https_proxy automatically.

Use env | grep -i proxy to confirm spelling and duplication. Stray quotes or trailing spaces from copy-paste often produce values that look correct yet fail TLS negotiation. For deeper inspection, curl -v shows CONNECT attempts and certificate chains, which separates proxy auth errors from upstream outages.

7. Git HTTPS and SSH

Git’s transport layer respects environment variables for HTTPS remotes, but many teams still set explicit config entries for clarity across GUI clients and hooks:

git config --global http.proxy  http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890

To remove them later, use git config --global --unset http.proxy and the matching https key. For SSH remotes ([email protected]:), HTTP environment variables do nothing; you need a ProxyCommand or a tunneled SSH config stanza, or you switch the remote to HTTPS while testing. Mixed teams often standardize on HTTPS plus credential helpers so Git proxy settings behave the same on macOS and Linux laptops.

When clones still stall despite correct variables, domain-level rules may be missing. Cross-check with our GitHub-focused split routing guide so github.com and asset hostnames share the same outbound.

8. npm, yarn, and pnpm

Node’s package manager reads HTTP_PROXY and friends for registry traffic. You can also pin values inside user config:

npm config set proxy         http://127.0.0.1:7890
npm config set https-proxy   http://127.0.0.1:7890

Clear them with npm config delete proxy and npm config delete https-proxy when you return to a direct network. Yarn Classic mirrors these keys; Yarn Berry (v2+) and pnpm consult environment variables first, then their YAML settings. Because enterprise registries sometimes sit on private TLS, combine npm config with an accurate no_proxy list so internal tarballs stay on-LAN while public scoped packages exit through Clash.

Watch for tools that spawn child processes without inheriting the parent environment—certain task runners strip variables unless configured. In those cases, prepend exports inline: HTTPS_PROXY=... npm install confirms the diagnosis before you refactor build scripts.

9. TUN, System Proxy, and When Env Vars Still Help

TUN can make many CLI programs “just work” because the kernel routes their packets into the virtual adapter. Developers still export environment variables when they need predictable behavior inside containers, remote SSH sessions, or IDEs that spawn subprocesses with sanitized environments. CI pipelines running on the same machine as a developer shell also benefit from explicit proxy lines in .bashrc snippets sourced by build scripts.

Align expectations with your client mode: system proxy alone rarely fixes every CLI; TUN plus correct DNS might, until a tool opts out. Treat this article as the portable floor—what always works when you point tools at 127.0.0.1—and layer mode-specific tuning from the Clash documentation when you need fake-IP, sniffing, or advanced rule providers.

10. Troubleshooting Checklist

  1. Confirm Clash is listening. Use your client dashboard or ss -lntp on Linux to verify the port matches your exports.
  2. Match scheme to capability. Pointing https_proxy at a SOCKS-only port without a translating forwarder yields opaque failures.
  3. DNS leaks. If IP connectivity works but name resolution fails, try socks5h:// so the remote side resolves, or align systemd-resolved with the tunnel.
  4. Corporate MITM. Custom CAs must be trusted in Node and Git separately; symptoms mimic proxy failure.
  5. IPv6 dead ends. Test with curl -4 when dual-stack networks black-hole one family.
  6. Windows peers. If you develop across OS boundaries, review WSL2 with Clash on Windows because localhost semantics differ from native Linux.

Document the combination that worked—port numbers, SOCKS versus HTTP, and whether TUN was on—so the next kernel or client upgrade is a diff, not a treasure hunt.

11. Summary

The “GUI works, terminal does not” split is one of the most common Clash onboarding surprises on macOS and Linux. Browsers honor system proxy dictionaries; most CLI stacks honor explicit http_proxy, HTTPS_PROXY, and ALL_PROXY exports plus thoughtful no_proxy exemptions. Pair those with optional Git and npm config entries when you want identical behavior inside IDEs, hooks, and automation. After variables line up, quick curl probes tell you whether to keep debugging the shell or jump back to outbound rules and DNS.

Compared with opaque one-click VPNs, Clash keeps the data path legible: your shell forwards to loopback, the core applies policy, and logs show which outbound matched each connect. That transparency matters when npm registries, Git packfiles, and long-lived TLS sessions all hit different hostnames.

When you install or refresh the client, use the official site’s download page for verified builds—then apply the exports above on a reproducible baseline.

Download Clash for free and experience the difference