Why WSL2 does not inherit the Windows system proxy

WSL2 is a lightweight virtual machine with its own network namespace. When Clash Verge Rev or another Clash-based client turns on the Windows system proxy, Edge and many Win32 apps follow suit automatically. Processes inside your Linux distribution, however, read their own environment and resolver configuration. They never see the Windows “Internet Options” dialog, so curl from Ubuntu may still try a direct path while Chrome on the host happily tunnels through Mihomo.

That mismatch is normal, not a bug. The fix is to treat Clash on Windows as a reachable HTTP or SOCKS endpoint from Linux, then teach apt, language package managers, and Docker how to use it. If you have not yet confirmed that Clash listens on the right port with a working profile, start with the Clash Verge Rev setup guide before you forward traffic from WSL2.

This article complements our native Linux Mihomo tutorial, which targets bare-metal or VPS Linux. Here the proxy stays on the Windows host, which many laptop workflows prefer because updates and tray UX remain on one side of the hypervisor boundary.

Find the Windows host IP from inside WSL2

WSL2 needs a stable way to address the Windows host. Two patterns dominate current releases.

Classic method. Open /etc/resolv.conf inside WSL and read the nameserver line. On many builds that address is the virtual gateway that also routes to the host. You can export it in your shell for reuse:

export WINDOWS_HOST=$(grep -m1 nameserver /etc/resolv.conf | awk '{print $2}')
echo "$WINDOWS_HOST"

Localhost forwarding. Recent WSL versions can mirror Windows localhost into the guest. If curl -I http://127.0.0.1:7890 (replace 7890 with your real mixed or HTTP port) succeeds from WSL without referencing the gateway IP, you can point tools at 127.0.0.1 directly. When it fails, fall back to $WINDOWS_HOST.

Always substitute your actual listener port. Clash-style configs often expose a mixed port that accepts both HTTP and SOCKS on one socket, or separate HTTP and SOCKS ports. Open your client UI or YAML and note the numbers before you export variables.

Prepare Clash on Windows: listeners, allow LAN, and firewall

By default some builds bind HTTP or mixed listeners to 127.0.0.1 only. WSL2 traffic arrives as if from another interface, so you must allow the proxy to accept connections from the virtual network. In YAML terms that usually means binding to 0.0.0.0 for the relevant listener or enabling an equivalent “allow LAN” toggle in the GUI. Our LAN proxy sharing guide walks through allow-lan and mixed-port thinking; the same knobs apply when the “remote” client is WSL2 rather than a phone.

Windows Defender Firewall must permit inbound TCP to that port from the WSL virtual switch. If tests from WSL time out while localhost on Windows works, create an inbound rule targeting your Clash executable or the specific TCP port. Restrict scope to private networks when possible so you do not expose the proxy to coffee-shop Wi-Fi.

Sanity check from WSL after adjusting bind addresses and firewall:

curl -I --proxy "http://${WINDOWS_HOST}:7890" https://www.google.com

Swap in 127.0.0.1 if localhost forwarding works on your machine, and swap the port to match your profile.

Configure apt to use the Windows Clash HTTP proxy

Debian-family apt respects proxy settings in configuration snippets under /etc/apt/apt.conf.d/. Create a file such as 95proxies (the exact name is arbitrary) with Acquire lines pointing at your host and port:

Acquire::http::Proxy "http://<HOST>:7890/";
Acquire::https::Proxy "http://<HOST>:7890/";

Replace <HOST> with either the gateway IP or 127.0.0.1 per your connectivity test. Use sudo and an editor you trust. After saving, run sudo apt update and confirm repositories refresh without connection resets.

If your provider requires an authenticated corporate proxy, embed credentials only if your security policy allows it; otherwise use a PAC-free split on the host. For public Clash nodes, authentication at the apt layer is rarely needed because the outbound tunnel already handles it.

When you need to disable the tunnel temporarily, rename the snippet or comment the lines—apt does not consult shell environment variables the way curl does, so leaving stale Acquire directives is a common source of “apt broke after I changed networks.”

Shell environment: http_proxy, git, npm, and Go

Most CLI tools honor lowercase http_proxy and https_proxy, with uppercase variants for compatibility. A pragmatic block for interactive shells:

export hostip=$(grep -m1 nameserver /etc/resolv.conf | awk '{print $2}')
export http_proxy="http://${hostip}:7890"
export https_proxy="http://${hostip}:7890"
export all_proxy="socks5://${hostip}:7891"
export no_proxy="localhost,127.0.0.1"

Adjust all_proxy only if you actually expose SOCKS on a distinct port; with a mixed port you can often omit SOCKS entirely and stay on HTTP CONNECT for HTTPS. Git respects these variables for remote operations; combine them with git config --global http.proxy only if you need repository-specific overrides.

npm uses npm config set proxy and https-proxy, or it inherits the environment when you run installs. Python pip honors HTTPS_PROXY. Go module downloads read HTTPS_PROXY as well. The pattern is the same: one consistent host IP or localhost and the correct port.

Persist the exports in ~/.bashrc or ~/.profile, or drop a small script into /etc/profile.d/ for all users—pick one approach so you are not debugging three conflicting definitions.

Docker Desktop for Windows: daemon.json and BuildKit

When Docker Desktop routes the engine through the WSL2 backend, image pulls and registry traffic originate from the Linux utility VM or the integrated distro, depending on the operation. Many teams still configure Docker’s HTTP/HTTPS proxy in the Docker Desktop UI under Resources → Proxies, which writes JSON the daemon understands.

Advanced users may edit daemon.json directly (path varies slightly by edition) to include a proxies block with http-proxy, https-proxy, and a sensible no-proxy list for local registries. After changes, restart Docker from the whale menu.

BuildKit-based docker build can pull base images during the build. If only interactive shells were proxied but the daemon was not, builds still stall. Align daemon-level proxy settings with the same host address you proved with curl from WSL. For air-gapped mirrors, extend no-proxy so internal artifact hosts bypass Clash.

Docker Engine inside WSL without Desktop

Some developers install docker.io from Ubuntu inside WSL and run the daemon with systemd after enabling userland systemd support. In that layout the Docker daemon is a native Linux process; it does not magically use Windows Clash unless you configure its service environment or daemon.json the same way you would on a standalone Linux box.

Point HTTP_PROXY at $WINDOWS_HOST:port in the systemd drop-in for docker.service, or rely on daemon.json proxies. Then restart Docker and verify with docker pull hello-world. This path trades Desktop conveniences for closer parity with production Linux, which is why our headless Linux guide remains relevant when you later move workloads off Windows entirely.

DNS, MITM, and corporate inspection edge cases

Clash handles DNS according to your YAML—fake-ip, redir-host, or a named resolver. WSL2 applications may use /etc/resolv.conf pointing at the Windows tunnel. If certain domains resolve on the host but fail in WSL, compare resolvectl status or dig output on both sides.

HTTPS interception appliances break TLS trust chains. You must import the enterprise root into the Linux trust store inside WSL, not only into Windows, or apt and curl will reject upstream certificates even though the browser works. That topic is orthogonal to Clash but shows up constantly in office networks.

Troubleshooting checklist

Connection refused from WSL

The listener is still bound to loopback on Windows only. Switch to 0.0.0.0 or enable LAN access, then retest.

Timeouts despite correct YAML

Firewall rule missing or overly broad “Public” profile blocking the virtual switch. Scope the inbound rule to the WSL subnet or mark the network as Private while testing.

apt works but Docker pull does not

Shell exports do not affect the daemon. Configure Docker Desktop proxies or systemd environment for the service account that runs dockerd.

Intermittent breakage after sleep or VPN

The gateway IP from resolv.conf can change across resume events. Wrap proxy exports in a small function you re-run when interfaces flap, or prefer localhost forwarding when your WSL release supports it reliably.

For broader Clash-specific failures—subscriptions, rules, or controller ports—continue with the Clash troubleshooting guide once network reachability to the host is confirmed.

Security and least privilege

Opening the mixed port to non-loopback interfaces increases blast radius. Combine allow-LAN style bindings with firewall rules, avoid exposing the external-controller port beyond localhost, and treat WSL filesystem access and Windows proxy exposure as part of one threat model. On shared PCs, prefer per-user firewall prompts and disable LAN access when you shut the laptop.

Putting it together

WSL2 and Windows Clash work well together once you stop expecting inherited system-proxy semantics. Pick the correct host address, prove it with curl, mirror those values into apt snippets and Docker daemon settings, and keep firewall policy explicit. The same Windows instance can still run a polished Clash Verge Rev tray workflow while Ubuntu builds and pulls images through the tunnel—no duplicate Mihomo install required inside WSL unless you want one for experimentation.

Compared with maintaining two separate proxy stacks, sharing the host Clash reduces configuration drift and keeps subscription updates in a single client. When you want that experience on the Windows desktop without retyping YAML by hand, the official build streamlines core updates and profile editing. → Download Clash for free and experience the difference