WSL 网络与代理
WSL2 的网络问题很容易让人混淆,因为它既不是“和 Windows 完全隔离”,也不是“和 Windows 完全同一台机器”。如果先不把网络关系想清楚,后面你会在 localhost、Windows 主机 IP、WSL IP 之间反复试错。
先分清三个地址
在默认的 WSL2 NAT 网络下,通常会同时出现这三类地址:
127.0.0.1:当前环境自己的回环地址- Windows 主机 IP:对 WSL 来说,通常是默认网关地址
- WSL IP:Linux 发行版自己的虚拟网卡地址
最常见的结论是:
- 在 Windows 访问 WSL 服务 时,很多服务可以直接用
localhost - 在 WSL 访问 Windows 上的代理或服务 时,通常应该使用 Windows 主机 IP
- 在 局域网其他机器访问 WSL 时,通常不能直接用 WSL IP,而是要经过 Windows 转发
如何在 WSL 中拿到 Windows 主机 IP
最稳妥的做法是取默认路由的下一跳:
ip route show default | awk '{print $3}'
很多机器上你也会在 /etc/resolv.conf 里看到同一个地址:
grep nameserver /etc/resolv.conf
如果两者一致,通常就说明你拿到的是 Windows 主机在 WSL 虚拟网络中的地址。
临时设置代理
下面以 Windows 上已有本地代理程序,且 HTTP 端口为 7890 为例。
先取 Windows 主机 IP:
export HOST_IP=$(ip route show default | awk '{print $3}')
再设置环境变量:
export http_proxy=http://$HOST_IP:7890
export https_proxy=http://$HOST_IP:7890
export all_proxy=socks5://$HOST_IP:7890
验证是否生效:
curl -I https://www.google.com
git ls-remote https://github.com/git/git.git HEAD
如果你主要是为了 apt、pip、git 这类命令走代理,这种临时方式已经足够。
持久化为可开关的函数
与其把代理变量直接硬编码进 ~/.bashrc,我更建议写成显式的开关函数。这样切换网络环境时不会反复手改文件。
把下面内容加入 ~/.bashrc:
set_wsl_proxy() {
local host_ip
host_ip=$(ip route show default | awk '{print $3}')
export http_proxy="http://$host_ip:7890"
export https_proxy="http://$host_ip:7890"
export all_proxy="socks5://$host_ip:7890"
}
unset_wsl_proxy() {
unset http_proxy
unset https_proxy
unset all_proxy
}
alias proxy-on='set_wsl_proxy'
alias proxy-off='unset_wsl_proxy'
重新加载 shell:
source ~/.bashrc
之后需要代理时执行:
proxy-on
不需要时执行:
proxy-off
sudo 命令不走代理怎么办
有时普通用户下 curl 能通,但 sudo apt update 还是失败。常见原因是 sudo 没有继承当前环境变量。
可以先临时试一下:
sudo -E apt update
如果你希望 apt 本身固定走代理,也可以单独写配置文件:
sudo nano /etc/apt/apt.conf.d/95proxies
写入:
Acquire::http::Proxy "http://<WINDOWS_HOST_IP>:7890";
Acquire::https::Proxy "http://<WINDOWS_HOST_IP>:7890";
这里的 <WINDOWS_HOST_IP> 需要替换成你当前查到的主机地址。因为 WSL IP 可能变化,这个文件更适合在你的网络环境比较稳定时使用。
什么时候不该继续折腾 WSL 里的代理变量
如果你已经设置了变量,但还是完全不通,优先检查 Windows 侧,而不是继续在 WSL 里盲改:
- 代理程序是否真的在 Windows 上运行
- 代理程序是否允许局域网或来自其他网卡的连接
- 端口号是否真的是你配置的那个
- Windows 防火墙是否拦截了对应端口
很多时候问题不在 WSL,而是 Windows 上的代理软件只监听了 127.0.0.1,没有对 WSL 所在的虚拟网卡开放。
最小排错顺序
我自己通常按这个顺序排:
ip route show defaultecho $http_proxycurl -I https://www.google.comsudo -E apt update- 在 Windows 上确认代理程序监听地址和端口
如果第 3 步都不通,先不要急着改 git、pip 或 conda 的单独配置,因为底层链路大概率还没通。
常见问题
1. 为什么昨天能用,今天不能用
WSL2 重启后虚拟网络可能变化,Windows 主机 IP 也可能随之变化。只要你不是把 IP 写死到文件里,而是每次通过 ip route 动态获取,这类问题会少很多。
2. 为什么浏览器能上网,但命令行不行
浏览器可能使用的是 Windows 自己的代理配置;WSL 命令行不会自动继承这一层,所以仍然需要你在 WSL 里显式设置环境变量。
3. 为什么 localhost:7890 在 WSL 里不通
这是因为 localhost 指向的是 WSL 自己,不是 Windows 主机。默认 NAT 网络下,访问 Windows 上的代理更应该用主机 IP。