在 WSL2 里 curl 一个墙外的地址不动,退出来在 PowerShell 里却正常——这是几乎每个用 WSL2 做开发的人都撞过的墙。原因不在代理软件,而在 WSL2 的网络模型:它是一台独立的虚拟机,有自己的网卡和 IP,127.0.0.1 指的是 WSL 自己,不是 Windows。
这篇把两种情况分开讲:老式的 NAT 模式和 Win11 22H2 之后可选的 mirrored 模式。两种模式下取宿主地址的方法完全不同,抄错一段配置就会一直连不上。
先确认你的 WSL2 用的是哪种网络模式
在 Windows 的用户目录下看 .wslconfig(路径一般是 C:\Users\你的用户名\.wslconfig)。如果文件不存在,或者里面没有 networkingMode 这一项,那就是默认的 NAT 模式。
只有显式写了下面这段,才是 mirrored:
[wsl2]
networkingMode=mirrored
改完 .wslconfig 必须执行 wsl --shutdown 再重新进入,配置才会生效。很多人改完没关机重启虚拟机,以为配置没起作用,其实是没生效。
NAT 模式:宿主 IP 就是 resolv.conf 里的那个 nameserver
NAT 模式下,WSL2 通过一个虚拟交换机上网,Windows 宿主在这张网卡上有一个固定段内的地址。取法很简单:
cat /etc/resolv.conf | grep nameserver
输出的那个 IP(常见形如 172.x.x.x)就是 Windows 宿主。假设你的代理客户端在 Windows 上监听 7890 端口,那么在 WSL 里:
export http_proxy=http://172.x.x.x:7890
export https_proxy=http://172.x.x.x:7890
注意两点。第一,Windows 上的代理客户端必须允许局域网连接,否则它只监听 127.0.0.1,WSL 从虚拟网卡过来会被拒绝。第二,这个 IP 在每次重启 WSL 后可能变化,所以不要写死,用命令动态取:
export hostip=$(grep -m1 nameserver /etc/resolv.conf | awk '{print $2}')
export http_proxy="http://$hostip:7890"
export https_proxy="http://$hostip:7890"
mirrored 模式:这里反而可以用 127.0.0.1
mirrored 模式让 WSL2 和 Windows 共享网络接口,Linux 里访问 127.0.0.1 会直接落到宿主上绑在回环的端口。这对代理非常友好——不用再算 IP。
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
但有个坑:部分代理客户端的 TUN / 虚拟网卡模式在 mirrored 下会和 WSL 打架,表现是 DNS 能通、TCP 不通,或者干脆整个 WSL 断网。遇到这种情况,先关掉 TUN 只用系统代理试试。
curl -v 卡在 Trying 172.x.x.x...,是路由或防火墙问题,和代理无关;如果卡在 Connected 之后的 TLS 握手,才是代理没转发出去。让 apt、git、npm 各自认代理
环境变量只管住一部分工具,这几个要单独配。
apt(Debian/Ubuntu):
sudo tee /etc/apt/apt.conf.d/95proxies <<EOF
Acquire::http::Proxy "http://$hostip:7890";
Acquire::https::Proxy "http://$hostip:7890";
EOF
git:
git config --global http.proxy http://$hostip:7890
git config --global https.proxy http://$hostip:7890
# 取消
git config --global --unset http.proxy
npm / yarn:
npm config set proxy http://$hostip:7890
npm config set https-proxy http://$hostip:7890
把环境变量写进 ~/.bashrc 或 ~/.zshrc 时,记得用命令动态取宿主 IP,不要写死。重启 WSL 后 IP 会变,写死的配置会悄无声息地失效。
验证到底通没通
别用 ping 判断,ICMP 和 TCP 走的不是一条路。直接看出口 IP:
curl -s https://api.ipify.org
返回的 IP 和你 Windows 上开代理时看到的出口 IP 一致,说明整条链路是通的。如果返回的是本地运营商 IP,说明代理没生效——先查 echo $http_proxy 有没有值,再查端口通不通:
curl -v --max-time 5 http://$hostip:7890
几个反复出现的问题
- 改完配置没重启 WSL:
.wslconfig的任何改动都需要wsl --shutdown。 - Windows 防火墙拦了虚拟网卡:把代理客户端加入允许列表,或者临时关掉防火墙验证。
- 公司电脑装了安全软件:部分终端防护会拦截 WSL 的出站连接,表现和代理失效一样。
- Docker Desktop 里的容器:容器走的是 WSL2 的网,同样需要这部分代理配置,或者给 Docker 单独设
HTTP_PROXY。
如果你需要的是整机、跨设备的稳定出口(比如同时给 WSL、虚拟机、手机热点用),而不是每个工具单独配一遍,可以考虑在网络层做加速。这类方案与本文的单进程代理不是一回事,配置前建议先读 KTP 协议是什么 和 全局模式与分流模式的区别。
下一步可以看:连接失败怎么排查、DNS 泄露怎么处理。