用 WSL 开发的人,大概率都遇到过这个破事:Windows 上 Clash 一开,WSL 里的终端该连不上还是连不上,就算开启了网络镜像模式以及自动代理也非得 wsl --shutdown 重启一遍,代理才能够生效,一天折腾几回,心态真的会崩。

后来搞明白了,autoProxy 这东西只在 WSL 启动的那一瞬间读一次 Windows 的代理设置,它不是动态同步,就是个启动快照,只要 Clash 比 WSL 后启动,WSL 里就还是无代理状态。

那怎么办?思路很简单:自己写个后台小脚本,盯着 Clash 的端口,通了就把代理环境变量写到一个文件里,然后让 shell 自己去读。这样不管 Clash 什么时候开,WSL 这边都能跟上。

前提

1. WSL 是否启用 systemd

编辑 /etc/wsl.conf:

1
2
[boot]
systemd=true

改完在 PowerShell 里 wsl --shutdown 重启一次。

**2. Clash Verge 的 Allow LAN 是否打开

设置 → Clash 设置 → 允许局域网连接,打开。

3. Windows 防火墙放行端口

以管理员身份开 PowerShell,把 Clash 的混合端口放行。比如你的混合端口是 7890:

1
New-NetFirewallRule -DisplayName "WSL Clash Proxy" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 7890

4.开启镜像模式

WSL开发网络模式选择:NAT与镜像模式详解

5. 确认装了 nc

脚本用 nc 检测端口,Ubuntu 默认可能没有:

1
sudo apt install netcat-openbsd

操作步骤

代理脚本

这个脚本只干一件事:检测 Clash 端口通不通,通就把代理变量写到当前用户的 ~/.config/wsl-proxy.env,不通就清空。

创建 /usr/local/bin/proxy-refresh.sh

1
sudo nano /usr/local/bin/proxy-refresh.sh

内容如下,记得把 7890 换成你自己的混合端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
PROXY_PORT=7890
ENV_FILE="$HOME/.config/wsl-proxy.env"

mkdir -p "$(dirname "$ENV_FILE")"

if nc -z 127.0.0.1 "$PROXY_PORT" 2>/dev/null; then
cat > "$ENV_FILE" <<EOF
export http_proxy="http://127.0.0.1:$PROXY_PORT"
export https_proxy="http://127.0.0.1:$PROXY_PORT"
export HTTP_PROXY="http://127.0.0.1:$PROXY_PORT"
export HTTPS_PROXY="http://127.0.0.1:$PROXY_PORT"
export all_proxy="socks5://127.0.0.1:$PROXY_PORT"
export ALL_PROXY="socks5://127.0.0.1:$PROXY_PORT"
export no_proxy="localhost,127.0.0.1,::1"
EOF
else
cat > "$ENV_FILE" <<EOF
unset http_proxy
unset https_proxy
unset HTTP_PROXY
unset HTTPS_PROXY
unset all_proxy
unset ALL_PROXY
EOF
fi

给所有用户执行权限:

1
sudo chmod +x /usr/local/bin/proxy-refresh.sh

systemd 托管

创建 /etc/systemd/user/proxy-watcher.service,配置systemd服务实现开机自启

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=WSL Clash Proxy Watcher
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash -c 'while true; do /usr/local/bin/proxy-refresh.sh; sleep 3; done'
Restart=always
RestartSec=5

[Install]
WantedBy=default.target

启动服务并设置开机自启:

1
2
3
sudo systemctl --global enable proxy-watcher.service
systemctl --user daemon-reload
systemctl --user start proxy-watcher.service

shell 自动加载代理

脚本只是在后台更新 ~/.config/wsl-proxy.env,shell 得自己去读才行。

默认的 bash

编辑 ~/.bashrc,末尾增加:

1
2
3
4
5
6
[ -f "$HOME/.config/wsl-proxy.env" ] && source "$HOME/.config/wsl-proxy.env"

_proxy_refresh() {
[ -f "$HOME/.config/wsl-proxy.env" ] && source "$HOME/.config/wsl-proxy.env"
}
PROMPT_COMMAND="_proxy_refresh${PROMPT_COMMAND:+; $PROMPT_COMMAND}"

执行以下命令让配置生效:

1
source ~/.bashrc

zsh

编辑 ~/.zshrc,末尾增加:

1
2
3
4
5
6
7
[ -f "$HOME/.config/wsl-proxy.env" ] && source "$HOME/.config/wsl-proxy.env"

_proxy_refresh() {
[ -f "$HOME/.config/wsl-proxy.env" ] && source "$HOME/.config/wsl-proxy.env"
}
autoload -Uz add-zsh-hook
add-zsh-hook precmd _proxy_refresh

执行以下命令让配置生效:

1
source ~/.zshrc

这样新开的终端会自动加载代理,已经开着的终端也会在每次回车前自动刷新一遍。Clash 什么时候开,这边最多 3 秒后就跟上,不用再重启 WSL。

验证一下

新开个终端,先看变量:

1
echo $http_proxy

应该输出 http://127.0.0.1:7890。

再测连通性:

1
curl -s -o /dev/null -w '%{http_code}' https://www.google.com

这套东西的核心就一句话:让一个后台进程持续盯着 Clash 的端口,把最新代理写进文件,shell 自己读。

操作就这些,希望能帮你少重启几次 WSL。