为什么这件事和「在 Ubuntu 里装 Clash Meta」不是同一篇教程
很多开发者的真实工作流是:键盘与终端在 WSL2 里,浏览器与 IM 在 Windows;代理与订阅只在 Windows 的 Clash 系客户端里维护一份。此时在 Linux 发行版里再跑一个 Clash Meta 并非不可能,但会带来双份配置、双份更新与双份排障成本。更自然的诉求是:在 WSL2 里执行 sudo apt update、git clone、curl 拉安装脚本时,流量穿过虚拟网卡边界,落到 Windows 上已经开好的 mixed-port 入站,再走你熟悉的规则与策略组。
这与本站 原生 Ubuntu 上部署 Clash Meta 的侧重点不同:那篇解决的是「Linux 自己就是代理机」;本文解决的是「Linux 子系统只是终端环境,出口交给 Windows 宿主机」。也与 局域网共享 Wi‑Fi 不同:那篇面向手机/游戏机填「同一网段里的电脑 IP」;WSL2 与宿主机之间是虚拟交换机与 NAT,拿手机那套直觉硬套常会踩坑。
ALL_PROXY / no_proxy 与 apt、git 各自需要的额外一行。
Windows 侧:mixed-port、允许局域网与防火墙
Clash 系配置里常见的 mixed-port 表示在同一端口上同时接受 HTTP 代理与 SOCKS5(具体行为以你使用的内核与客户端为准)。对命令行而言,最省事的做法往往是让工具走 http://宿主机IP:端口,因为 apt 与许多脚本对 HTTP 代理支持最直观;若某工具只认 SOCKS,再改用 socks5://... 或单独拆开 HTTPS_PROXY。
关键点在于监听地址:若 Clash 只监听 127.0.0.1,从 WSL2 过来的连接并不是本机环回视角下的「自己」,通常会直接被拒。你需要在图形客户端里打开「允许局域网连接 / Allow LAN」一类选项,或在配置中让入站绑定到 0.0.0.0(具体菜单名因客户端而异,但语义一致:对虚拟网卡上的其他接口可见)。做完这步,仍建议在 Windows 防火墙里为对应端口放行入站,否则你会看到「WSL2 里超时、Windows 本机 curl 却正常」的割裂现象。
若你同时关心「系统里所有进程不经环境变量也走代理」,那是 TUN 模式 的故事;本文刻意保持在显式代理端口 + 环境变量层,避免把 WSL2、Hyper‑V 虚拟网卡与全局路由搅在同一锅粥里。
在 WSL2 里拿到「Windows 宿主机」的可达 IP
最常见的稳定写法之一,是读取默认网关地址:在 WSL2 中,指向 Windows 宿主机的那张虚拟网卡的默认路由下一跳,往往就是你能直连的宿主机 IPv4。你可以在 shell 里用一行命令得到它(不同发行版自带工具略有差异,思路是「默认路由的 gateway」):
# Example: print default gateway (often the Windows host from WSL2)
ip route show default | awk '{print $3}'
另一个历史上更常见、但在部分新版本中可能被自动化改写或附带注释的做法,是查看 /etc/resolv.conf 里的 nameserver 行:它常常同样指向宿主机,用于把 DNS 查询转发给 Windows。若你同时开启 IPv6 或遇到解析走 AAAA 的站点,偶发会出现「IPv4 通、IPv6 路径不通」或反过来;此时可以先用明确的 IPv4 地址验证 mixed 端口,再决定是否要在 no_proxy 或系统层收紧双栈行为。
不建议把「写死的 192.168.x.x」当作长期方案:热点切换、公司 VPN、Docker Desktop 与虚拟交换机顺序变化,都可能让地址漂移。更稳妥的是把上面取到的值赋给自定义变量,例如 export WINDOWS_HOST=$(ip route show default | awk '{print $3}'),再在代理 URL 里引用 $WINDOWS_HOST。
bash / zsh:ALL_PROXY、大小写与 no_proxy
现代 CLI 生态里,ALL_PROXY 适合作为「总开关」:许多工具会同时参考 http_proxy / HTTP_PROXY 与 https_proxy / HTTPS_PROXY,命名大小写在不同程序里并不完全一致。实践上更省心的组合是:对「明确支持 ALL_PROXY」的工具设 ALL_PROXY;对只认传统变量的工具补齐大写或小写两套里你实际用到的那套;并始终配置 no_proxy,把 127.0.0.1、localhost、内网段与大陆常用镜像域名排除出去,避免把不该出国的流量硬塞进隧道。
# Replace 7890 with your Windows Clash mixed-port
export WINDOWS_HOST=$(ip route show default | awk '{print $3}')
export HTTP_PROXY="http://${WINDOWS_HOST}:7890"
export HTTPS_PROXY="http://${WINDOWS_HOST}:7890"
export ALL_PROXY="http://${WINDOWS_HOST}:7890"
export NO_PROXY="localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
若你更偏好 SOCKS,可把 ALL_PROXY 写成 socks5://...,但要确认目标工具链对 SOCKS5 的支持是否完整(尤其是 TLS 与远程解析相关选项)。mixed 端口走 HTTP 形态通常更「朴素」,排障时也更容易用 curl -x 对照。
apt:环境变量之外的那一行 Acquire
Debian 系 apt 有时并不会完全跟随你在 shell 里 export 的 HTTP_PROXY,尤其在 sudo 场景下:sudo 默认会清理一部分环境变量,导致你以为「终端里已经 export」,实际 sudo apt 仍然直连。更稳妥的做法之一,是在 /etc/apt/apt.conf.d/ 下写入代理指令,或在命令前显式传入 -o 参数。下面示例展示用配置文件固定 HTTP/HTTPS 代理(请把主机与端口改成你的 Windows 侧 mixed-port):
# /etc/apt/apt.conf.d/95proxy (example; use sudo)
Acquire::http::Proxy "http://YOUR_WINDOWS_HOST:7890/";
Acquire::https::Proxy "http://YOUR_WINDOWS_HOST:7890/";
写入前仍建议先用普通用户身份 curl -x http://$WINDOWS_HOST:7890 https://deb.debian.org 或你实际使用的镜像源测通,以免把 apt 锁死在错误代理上。若你使用公司镜像或国内缓存域名,记得把它们加入 NO_PROXY,让这部分流量保持直连,既省节点也降低延迟。
git:http/https 与 ssh 两条路径
对 https:// 与 http:// 协议的远端,Git 会尊重 http.proxy / https.proxy,也会继承环境中常见的代理变量。你可以用仓库级或全局级配置固定下来,避免每次手输:
git config --global http.proxy http://YOUR_WINDOWS_HOST:7890
git config --global https.proxy http://YOUR_WINDOWS_HOST:7890
若你使用 [email protected]:... 这种 SSH 协议,流量并不走 HTTP 代理变量,而是走 SSH 自己的 TCP 连接;要让 SSH 也经宿主机出口,需要另配 ProxyCommand 或 nc/corkscrew 一类方案,这已经超出「填 mixed-port 就能好」的范围。对大多数「clone 公开仓库」场景,改用 https:// 远端往往更省事。
最小验证路径:curl、再 apt、再 git
建议严格按顺序验证:先用 curl -v -x http://$WINDOWS_HOST:端口 https://www.google.com/generate_204 或任意轻量测试 URL,确认 TCP 能建立、TLS 能握手;再跑 sudo apt update 的小流量;最后 git ls-remote 一个公开仓库。若第一步失败,不要急着改 WSL2 DNS,先看 Windows 侧 Clash 是否对该端口监听在正确地址、规则是否把来自虚拟网卡段的流量误判为直连或拒绝。
Clash 的连接日志与规则命中,是这一阶段最有价值的对照工具;若你对日志字段尚不熟悉,可先阅读 连接日志与规则命中排查,把「请求有没有到达内核」与「到达后被送去哪条规则」分开看。
常见坑:localhost、sudo、与「以为开了系统代理就够了」
把代理写成 127.0.0.1 却指向了 WSL 自己
在 WSL2 里,127.0.0.1 指向的是 Linux 网络命名空间的本机,而不是 Windows。除非你在 WSL 里另行做了端口转发,否则「指向 127.0.0.1 的 mixed-port」通常只会撞到空端口。请始终使用上文的宿主机 IPv4 或稳定解析名(若你的环境提供)。
sudo 与 systemd 服务里的环境变量丢失
把 export 写进 ~/.bashrc 只对交互 shell 友好;sudo、cron、或某些 CI 脚本不会加载它们。apt 用配置文件、git 用 git config、长期任务用 systemd Environment=,都是在「不依赖交互 shell」方向上更稳的选择。
只开 Windows「系统代理」但不暴露端口给 WSL2
系统代理 PAC 或 Windows 设置里的 HTTP 代理,解决的是 Windows 应用生态;WSL2 里的进程并不自动等价于「遵守 Windows 系统代理」。你仍需要让 Clash 在宿主机上有一个可达的代理端口,并在 WSL2 内显式指向它。
与 Windows 客户端安装教程的衔接
若你尚未在 Windows 上把 Clash 图形客户端装稳、订阅未导入、mixed-port 未确认,建议先按 Clash Verge Rev Windows 教程 完成基础路径,再回到本文把 WSL2 的变量与 apt 行补齐。这样排障时可以把问题空间清晰切成「Windows 侧是否已监听」与「WSL2 侧是否指对 IP」两块,而不是同时怀疑两套配置。
当你已经能用 curl -x 证明 WSL2 → Windows → 节点的链路可靠,日常开发里再叠加 Docker、pnpm、Go module proxy 等工具,只要它们尊重标准代理变量,就会自然继承同一出口。相比在 WSL2 里再维护一份内核与 config.yaml,把「代理的单一事实来源」留在 Windows,往往更符合真实桌面工作流的维护成本。
若你希望把同一套 Clash 习惯延伸到更多设备与场景,可从本站 Clash 客户端下载页 选择对应平台安装包,保持订阅与规则管理入口一致;需要查阅字段语义时,也可打开 使用文档中心 对照 YAML 段落。相比在 WSL2 里重复造轮子,让 Windows 上的 Clash 成为稳定出口,再用环境变量把 Linux 命令行「挂」上去,长期往往更省心。→ 立即免费下载 Clash,开启流畅上网新体验