Typical symptom: Windows browses fine, WSL2 apt and git “see no proxy”
When Clash is healthy on Windows, the browser often follows the OS proxy table or a TUN adapter without you thinking about ports. WSL2, however, sits behind a lightweight virtual machine and virtual switch. Your mental model of “localhost” does not transfer verbatim. If you export https_proxy=http://127.0.0.1:7890 inside Ubuntu on WSL, the TCP connection targets the Linux distro’s own loopback interface, not the Windows process that owns port 7890. Symptoms include connection refused, long hangs, or traffic that still leaves as direct when you expected an upstream rule on Clash to apply.
apt and git add another layer. They do not always inherit whatever you typed in an interactive shell: sudo may strip environment variables; apt honors /etc/apt/apt.conf.d/ directives such as Acquire::http::Proxy; git prefers http.proxy and https.proxy for HTTPS remotes. Until host reachability, Clash listen scope, and persistent config locations agree, you will keep seeing “it works in the browser but not in the terminal,” which is frustrating but predictable.
Mental model first: who owns 127.0.0.1 in WSL2
Under the classic WSL2 NAT design, the Linux instance has its own network stack. 127.0.0.1 refers to that Linux environment, not to Windows. To reach Clash on the host, the destination IP must be something routable from WSL toward Windows—commonly the default gateway seen from Linux, or in many builds the address published as nameserver in /etc/resolv.conf (behavior can change across WSL releases, so re-verify after major updates). Another reliable probe is ip route show default: the “via” address is often the host from WSL’s perspective.
Throughout this article we write <WIN_HOST> for that address. Replace it with whatever you measure on your machine. A quick sanity check beats editing five files blindly: run curl -v --proxy http://<WIN_HOST>:<PORT> https://www.example.com from WSL before touching apt or git. If that fails while ping-style reachability to <WIN_HOST> works, the problem is almost certainly on the Clash side (listen address, Allow LAN, or Windows Defender Firewall inbound rules).
On Windows: mixed port, Allow LAN, and bind address
Even with the correct <WIN_HOST>, Clash may refuse the connection if it only listens on 127.0.0.1 and disallows LAN, or if Windows Firewall blocks the WSL virtual subnet. In most GUI clients, toggle Allow LAN (or equivalent) so the mixed HTTP port accepts traffic from interfaces beyond loopback. When Windows shows a firewall prompt, allow the app at least on private networks. If you administratively lock down inbound rules, add an explicit allow rule for the TCP port Clash exposes (commonly in the 789x range—always confirm in your profile).
A mixed port serves both HTTP CONNECT and SOCKS-style traffic, which keeps ALL_PROXY configuration simpler. If you split HTTP and SOCKS across two ports, match each tool: HTTP-style proxies use http:// URLs; SOCKS uses socks5:// or socks5h:// when you want remote DNS. Remember that Clash rules still execute on the Windows path; WSL2 is simply sending requests into Clash’s inbound. That is different from expecting WSL processes to be hijacked by WinTun without any explicit proxy settings.
If you run TUN on Windows for the whole desktop, you can still keep this explicit-proxy workflow for WSL2. TUN does not magically transparently proxy every Linux syscall. For a fuller comparison of modes, read the desktop TUN article and return here once you know which path your browser is actually using.
Shell variables: http_proxy, HTTPS_PROXY, ALL_PROXY, and no_proxy
Most CLI tools accept both lowercase and uppercase spellings. To avoid “it works in bash but not in tool X,” set pairs: http_proxy and HTTP_PROXY, https_proxy and HTTPS_PROXY. The proxy URL for HTTPS traffic through an HTTP proxy is still typically http://<WIN_HOST>:<PORT> because the client speaks HTTP CONNECT to the proxy first. For tools that truly need SOCKS, set ALL_PROXY=socks5h://<WIN_HOST>:<PORT> plus the uppercase duplicate.
no_proxy (and NO_PROXY) should list hosts that must never leave the machine for a corporate proxy hop: localhost, 127.0.0.1, ::1, RFC1918 LANs you use for registries, and internal Git hostnames. Without it, a request to a private Nexus or a Kubernetes API server might get dragged through Clash and fail in confusing ways. If you also route Node, pnpm, or IDE traffic through Clash, the same NO_PROXY discipline applies inside WSL; see the Cursor and npm split-routing guide for parallel ideas on registry and IDE endpoints.
Persist exports in ~/.bashrc or ~/.zshrc after you validate them in a single session. Keep in mind that sudo apt is a special case—covered next—so do not assume global shell exports alone fix package management.
# Replace <WIN_HOST> and <PORT> with your values (example mixed port: 7890) export HTTP_PROXY="http://<WIN_HOST>:<PORT>" export http_proxy="$HTTP_PROXY" export HTTPS_PROXY="$HTTP_PROXY" export https_proxy="$HTTP_PROXY" export ALL_PROXY="socks5h://<WIN_HOST>:<PORT>" export all_proxy="$ALL_PROXY" export NO_PROXY="localhost,127.0.0.1,::1" export no_proxy="$NO_PROXY"
apt: sudo, Acquire::http::Proxy, and why drop-in files win
Debian-family apt reads /etc/apt/apt.conf and snippets under /etc/apt/apt.conf.d/. Environment variables you export as a normal user often do not survive sudo apt update unless you deliberately preserve them. The robust pattern is a small file such as /etc/apt/apt.conf.d/95proxy containing Acquire::http::Proxy and Acquire::https::Proxy pointing at http://<WIN_HOST>:<PORT>/. Apt will use HTTP CONNECT toward HTTPS mirrors; that is normal.
Let Clash decide direct versus relay for each mirror domain instead of hardcoding multiple apt proxies. If you mix domestic mirrors and overseas origins, policy groups and rules on the Windows profile are the right place to express that complexity. When something still fails with “Could not resolve” or odd TLS messages, bring DNS mode into the picture: fake-ip versus redir-host interacts with resolver chains, as discussed in the fake-ip versus redir-host guide.
# File: /etc/apt/apt.conf.d/95proxy (example) Acquire::http::Proxy "http://<WIN_HOST>:<PORT>/"; Acquire::https::Proxy "http://<WIN_HOST>:<PORT>/";
Remove or comment the file when Clash is off so apt does not point at a closed port during your commute or on another network. Operational hygiene matters more than one-off copy-paste snippets.
git: http.proxy, https.proxy, and the SSH caveat
For remotes that use https:// or http://, git respects http.proxy and https.proxy. A straightforward global setup:
# Git uses http(s).proxy for HTTPS remotes git config --global http.proxy http://<WIN_HOST>:<PORT> git config --global https.proxy http://<WIN_HOST>:<PORT>
[email protected]:org/repo.git over SSH does not automatically follow http_proxy. You need ProxyCommand or an SSH-aware tunnel if you insist on SSH through SOCKS. Many teams stick to HTTPS remotes plus the proxies above for simplicity. If only GitHub needs the tunnel while a self-hosted Git sits on LAN, combine git URL-specific config with no_proxy entries so internal remotes stay direct.
Mirrored networking: when localhost on WSL matches Windows
Recent WSL releases on Windows 11 introduce mirrored networking (networkingMode=mirrored in %UserProfile%\.wslconfig). With mirroring enabled and supported by your build, loopback and certain localhost semantics align more closely between WSL and Windows, which often means you can aim at http://127.0.0.1:<PORT> for Clash’s mixed inbound without deriving <WIN_HOST> every boot. Availability and exact semantics evolve; always cross-check Microsoft’s current documentation after a feature update.
# %UserProfile%\.wslconfig (snippet — verify field names in official docs)
[wsl2]
networkingMode=mirrored
After editing, run wsl --shutdown and reopen the distro. If you coexist with third-party VPNs or other virtual adapters, mirrored mode can introduce new interactions; fall back to the explicit host-IP method if your team hits instability. Document both paths in internal runbooks so newcomers are not blocked on one Windows build skew.
Verification order: narrow failure in five minutes
Work top down. First, from WSL, confirm basic reachability to <WIN_HOST> (ping or short TCP test—ICMP alone is not always definitive). Second, run curl -I --proxy http://<WIN_HOST>:<PORT> https://example.com. Third, in a non-root shell, confirm your exports with env | grep -i proxy. Fourth, exercise apt either via the apt.conf.d file or sudo -E apt update if you insist on environment inheritance. Fifth, run git ls-remote https://github.com/... to validate HTTPS git without cloning a huge tree.
If step two fails but step one passes, revisit Clash bind scope and firewall before touching YAML rules. If the browser works while curl without --proxy fails, you are simply seeing “browser uses system proxy, shell does not”—a different class of bug than WSL loopback confusion. Separating those narratives saves hours.
Quick symptom matrix
| What you see | Likely cause | What to try |
|---|---|---|
127.0.0.1:7890 connection refused |
Proxy lives on Windows; WSL’s 127 is local Linux | Use <WIN_HOST> or enable mirrored networking |
User curl works; sudo apt ignores proxy |
sudo sanitizes environment | Use apt.conf.d or sudo -E with care |
| git HTTPS still direct-fails | No http.proxy / https.proxy |
git config --global to host proxy |
| Host IP “moves” after sleep or VPN | Route or resolver churn | Script gateway detection; or mirrored localhost |
| Allow LAN on but still refused | Firewall or bind address too narrow | Check Defender inbound; widen listen if safe |
Closing: treat Windows Clash as an explicit upstream for WSL2
Once you stop expecting WSL2 to inherit browser proxy state automatically, the architecture becomes simple: Linux tools forward to Clash’s inbound on Windows, and Clash applies the same policy groups, DNS, and logging you already curate for the desktop. Whether you reach that inbound via a stable <WIN_HOST> or via mirrored 127.0.0.1, the checklist is the same—prove connectivity with curl, persist apt and git separately, and keep no_proxy honest for private endpoints. Compared with many all-in-one clients, Clash’s transparent YAML, rule ordering, and multi-protocol inbounds make it a strong fit for developers who split browser, IDE, and subsystem traffic deliberately.
When you want to go deeper on policy design—GEOIP ordering, rule providers, and selective groups—continue with the YAML routing and rule-providers guide. For installers across platforms, use the site download center rather than hunting release pages while you are mid-debug.
http_proxy, ALL_PROXY, apt, and git using the steps above so updates and clones ride the same rules as your browser.
Browse more tutorials in the tech column index or open the help page if you need a broader starting point.