Why WSL2 ignores the Windows system proxy toggle

When newcomers install Clash on Windows through a polished GUI, the first win is usually the browser: flip system proxy on, refresh a test page, and the world looks reachable again. Then they open an Ubuntu shell inside WSL2, run sudo apt update, and watch the mirror handshake crawl or fail as if the tunnel never existed. That mismatch is not a bug in Clash; it is a consequence of how WSL2 virtualizes networking. Your Linux distribution runs with its own interfaces, its own default route, and its own resolver story. It does not automatically inherit WinINET proxy settings, nor does it read whatever magic the GUI applied for Edge.

Another trap is vocabulary. People say WSL shares localhost with Windows in casual conversation, but the precise behavior changed over time. In the classic WSL2 layout, 127.0.0.1 inside Ubuntu points at the Linux side of the loopback adapter, not at the Windows service that bound 127.0.0.1:7890 for Clash. Unless you enable newer mirrored networking modes, you cannot aim apt at http://127.0.0.1:7890 and expect packets to land on the Windows listener. You need either a published Windows host IP that WSL can route to, or a configuration that truly mirrors loopback semantics. Once that mental model clicks, the rest is mechanical: expose the Clash mixed port on an address WSL can reach, then teach apt and curl to use an HTTP proxy URL pointed at that address.

This article stays in the application proxy lane. You will not need Linux-side TUN inside WSL for basic HTTP(S) package downloads. If you later decide you want Windows-wide capture that also drags stubborn binaries through mihomo, read Clash TUN on Windows for routing and firewall depth. Here the goal is narrower and extremely common: make apt, curl, and similar tools exit through the same policy groups you already configured on the Windows core.

Resolve the Windows host from inside Ubuntu

Before exporting variables, decide which connectivity pattern your machine uses. On recent Windows 11 builds, Microsoft ships optional mirrored networking for WSL. When networkingMode=mirrored is enabled in .wslconfig, many guides suddenly work because 127.0.0.1 inside WSL can refer to the same loopback plane as Windows for forwarded ports. That is the pleasant path: your Clash mixed port on Windows loopback becomes reachable as 127.0.0.1 from Ubuntu, provided Clash still listens on all interfaces or loopback forwarding is coherent with your build. Verify with curl -I https://example.com after you set proxy variables, not before, because unconfigured curl will still exit direct.

If you are on the older default NAT layout, you need the numeric address of the Windows host as seen from the guest. The traditional recipe is to parse the resolver that WSL injected: read /etc/resolv.conf, take the nameserver line, and treat that IPv4 value as the Windows endpoint. Automation looks like export HOST_IP=$(grep -m1 nameserver /etc/resolv.conf | awk '{print $2}'). That value is stable enough for scripting, yet it can change across reboots or VPN software, so shell scripts should recompute it instead of hardcoding yesterday address.

Some organizations replace /etc/resolv.conf with a corporate resolver that is not the Windows host at all. If your computed HOST_IP is not pingable from WSL or does not answer on the Clash port, open PowerShell on Windows and compare against ipconfig output for the vEthernet WSL adapter and default gateways. When in doubt, temporarily test with curl from Windows using curl.exe to confirm Clash is listening, then test from WSL with nc -vz $HOST_IP 7890 using your real mixed port number. A refused connection means the listener is loopback-only; a timeout means a firewall or wrong IP.

Clash on Windows: bind the mixed port where WSL can touch it

Many profiles bind the mixed listener to 127.0.0.1 only for sensible security defaults. That is perfect for local browsers and tight attack surfaces, but it is invisible across the WSL virtual switch unless mirrored networking makes the semantics line up. For the classic NAT case, enable Allow LAN (or the equivalent YAML knob that binds additional interfaces) so mihomo listens on 0.0.0.0:7890 or at least on the address that matches your HOST_IP interface. Our LAN proxy walkthrough covers firewall rules and bind addresses for Wi-Fi phones; the same mental model applies here: Windows Defender Firewall must allow inbound TCP to that port from the WSL subnet.

Pick a single numeric port and stay boring. Community defaults like 7890 are fine if nothing else occupies them. Read the actual value from your GUI ports panel; subscription bundles love to randomize ports for uniqueness, and screenshots on social media rarely match your machine. Prefer http:// scheme URLs aimed at the mixed listener for apt and curl unless you know you need SOCKS. Mixed ports exist precisely so one TCP port can speak both dialects to compatible clients.

After toggling Allow LAN, re-run your port check from WSL. If it still fails, collect evidence in layers: first ss -lntp on Windows side via PowerShell Get-NetTCPConnection, then WSL connectivity, then Clash logs. Jumping straight into YAML surgery before you prove a TCP SYN reaches the process wastes evenings.

apt: use Acquire::http::Proxy and friends

Debian-style apt does not consult HTTP_PROXY for its primary downloads in the way curl does. You configure it through apt directives, either as one-off command flags or as drop-in files under /etc/apt/apt.conf.d/. A minimal inline test looks like sudo apt -o Acquire::http::Proxy="http://HOST:PORT/" -o Acquire::https::Proxy="http://HOST:PORT/" update, replacing HOST with 127.0.0.1 when mirrored networking works for you, or with $HOST_IP when you are on the classic resolver pattern.

For persistence, write a small file such as /etc/apt/apt.conf.d/95clash-wsl owned by root with the same keys. Keep the trailing slash consistent; some mirrors concatenate paths in ways that get picky when the proxy URL is sloppy. If your organization uses an internal HTTP proxy that requires authentication, apt supports embedded credentials in the URL, but prefer injecting secrets through a safer mechanism than world-readable files when possible.

Remember apt talks to many hosts: security.ubuntu.com, archive.ubuntu.com, CDNs, and PPAs. A blanket proxy rule sends all of them through Clash, which is usually what you want for split routing. If certain mirrors must stay direct for speed, apt also supports per-host overrides with more verbose configuration. Start simple, confirm sudo apt update completes, then install a tiny package to force actual archive fetches, not only index refreshes.

curl, wget, and shell tools: standard environment variables

Once TCP connectivity to the mixed port works, most CLI tools respond to the usual exported variables: HTTP_PROXY, HTTPS_PROXY, and optionally ALL_PROXY when you explicitly want SOCKS. Uppercase names are widely recognized; lowercase duplicates are sometimes added for compatibility with picky scripts. A pragmatic session block is:

export HOST_IP=$(grep -m1 nameserver /etc/resolv.conf | awk '{print $2}')
export HTTP_PROXY="http://${HOST_IP}:7890"
export HTTPS_PROXY="http://${HOST_IP}:7890"
export NO_PROXY="127.0.0.1,localhost"

Swap 7890 for your mixed port, and swap ${HOST_IP} for 127.0.0.1 when mirrored networking is active and verified. Then run curl -I https://www.debian.org or another stable endpoint. If curl works while apt still does not, you have already proven Clash routing; return to apt-specific configuration rather than chasing DNS ghosts first.

wget honors similar variables in most builds. Git uses its own config keys; if you also develop from WSL, mirror the ideas from our Windows-focused companion piece on Git and npm through the Clash mixed port, adapting addresses for WSL host reachability instead of loopback-only assumptions.

Persist settings without breaking other users

Interactive exports disappear when the shell exits. For personal development boxes, append guarded lines to ~/.bashrc or ~/.profile: compute HOST_IP when an interactive shell starts, export proxy variables only if a TCP probe succeeds, and keep a manual override environment variable like CLASH_PROXY_OFF=1 that short-circuits the block when you need a direct path for a few minutes. That pattern prevents mysterious failures on airplanes when Clash is not running.

Avoid writing secrets into global /etc/environment unless your workplace mandates it. Shared machines and corporate compliance teams dislike surprises in machine-wide proxy defaults. Per-user scope matches how most developers actually use WSL.

DNS, HTTPS MITM, and the failure modes that look like Clash bugs

When apt reports certificate errors only behind the proxy, compare against curl verbose output. Corporate TLS inspection breaks trust stores differently on Windows and Linux. Clash itself may be fine while a middlebox rewrites chains. If you recently enabled aggressive Fake-IP modes on Windows, confirm that resolver behavior for WSL still makes sense; split-brain DNS between guest and host shows up as random timeouts.

UDP-heavy workloads are not the target of an HTTP mixed port. If you need game-shaped UDP or QUIC experiments from WSL, you are past the scope of apt-centric proxying and into TUN territory on Windows or different tunnel tooling.

Optional: wsl.conf interoperability notes

Microsoft continues to evolve interop switches for WSL. Settings under /etc/wsl.conf can change whether Windows binaries appear on the Linux PATH and how init behaves. Those knobs rarely replace proxy configuration for apt, but they matter when you try to invoke powershell.exe from Ubuntu to script host-side tasks. Keep host and guest responsibilities clear: let Clash route on Windows, let Linux tools speak HTTP to the mixed listener you intentionally exposed.

Closing thoughts

WSL2 is a wonderful development surface, yet it inherits almost none of the Windows GUI proxy state you already trusted for the browser. Treat the Linux side as a tiny remote machine that happens to share your keyboard: give it a reachable address for the Clash mixed port, open the firewall deliberately, configure apt with Acquire keys, and align curl with mainstream environment variables. After one clean pass, updates and one-off downloads stop feeling like lottery tickets.

Compared with ad hoc VPN clients that hijack entire routing tables, Clash on Windows plus disciplined per-tool proxying tends to stay predictable for developers who live in both PowerShell and Ubuntu daily. When you want a maintained installer and coherent documentation next to these guides, start from our download page rather than chasing random binaries. For broader routing topics beyond WSL, the documentation hub collects related articles. → Download Clash for free and experience the difference.

If you contribute patches or inspect upstream sources, the open repositories for mihomo and related cores remain the right place for protocol discussions; keep that separate from day-to-day client installs so newcomers are not forced through a GitHub maze just to fetch a stable build.