Windows 上装 Linux 已经不是“装个虚拟机”的量级:wsl --install 一条命令就有完整内核、能跑 systemd、能开 GUI。但真正让人卡住的从来不是安装,而是装完之后的三件事——Windows 和 Linux 的路径怎么互访、localhost 到底通不通、以及那个悄悄涨到几十 GB 的 ext4.vhdx。
这篇按“装 → 配 → 通 → 收”的顺序,把 WSL2 的关键开关和它们的边界讲清楚。
1. 两种安装路径
新系统直接一条命令:
> wsl --install
> wsl --install -d Ubuntu-24.04
> wsl --update
> wsl --version
wsl --install 会启用所需功能、装 WSL 内核、并把默认发行版一起装好。旧系统(Windows 10 2004 之前,或功能被策略禁用)要手动来:
> dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
> dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
# 重启后
> wsl --set-default-version 2
| 步骤 | 新版一条命令 | 旧版手动 |
|---|---|---|
| 启用 Linux 子系统功能 | 自动 | Microsoft-Windows-Subsystem-Linux |
| 启用虚拟化平台 | 自动 | VirtualMachinePlatform |
| 安装内核 | 自动 | 需装 WSL2 内核更新包 |
| 装发行版 | -d 指定 |
wsl --install -d 或商店安装 |
2. WSL1 与 WSL2:不是版本号,是两套实现
| 维度 | WSL1 | WSL2 |
|---|---|---|
| 实现方式 | 系统调用翻译层 | 轻量 Hyper-V 虚拟机 + 真 Linux 内核 |
| 内核 | 无独立内核 | 微软提供的 Linux 内核,uname -r 带 microsoft 字样 |
/mnt/c 性能 |
较快(同一文件系统语义) | 明显慢(跨 VM 的 9p/virtiofs) |
| 本机 ext4 性能 | 一般 | 接近原生 |
| 网络 | 与 Windows 共享栈,直接 localhost |
独立 NAT 网段,IP 每次重启变 |
| 内存 | 随用随取 | 有上限,默认约宿主一半 |
| systemd | 不支持 | 支持([boot] systemd=true) |
| Docker | 基本不可用 | 可用 |
切换已有发行版用 wsl --set-version Ubuntu-24.04 2,转换会重打包文件系统,几十 GB 的实例要等很久,先备份。
3. 发行版管理:五条命令够用
> wsl -l -v # 列出所有发行版与版本、状态
> wsl -d Ubuntu-24.04 # 进入指定发行版
> wsl --set-default Ubuntu-24.04
> wsl --terminate Ubuntu-24.04 # 停掉单个实例
> wsl --shutdown # 停掉整个 WSL 与虚拟机
| 命令 | 作用 | 常见误用 |
|---|---|---|
-l -v |
看发行版、WSL 版本、运行状态 | 用 wsl -l 看不到版本号 |
-d NAME |
指定发行版执行 | 忘了 -d 就进了默认那个 |
--set-default |
改默认发行版 | 与 --set-default-version 混为一谈(后者改 WSL 版本) |
--export / --import |
备份/迁移到指定目录 | 导出的是 tar,不是可直接运行的目录 |
--unregister |
删除发行版与它的磁盘 | 不可恢复,先 --export |
wsl --shutdown 是所有“改了 .wslconfig 没生效”的必备动作:全局配置只在虚拟机启动时读取,不重启实例就不生效。
4. 路径互访:/mnt/c 与 \\wsl$
$ ls /mnt/c/Users/YG/Desktop
$ cd /mnt/c/Users/YG && cmd.exe /c dir # 在 Linux 里调 Windows 程序
$ explorer.exe . # 用资源管理器打开当前目录
> cd \\wsl$\Ubuntu-24.04\home\yg\project
> cd \\wsl.localhost\Ubuntu-24.04\home\yg
| 方向 | 路径 | 性能 | 注意 |
|---|---|---|---|
| Windows → WSL | \\wsl$\<发行版>\... 或 \\wsl.localhost\... |
中等 | 新版推荐 wsl.localhost |
| WSL → Windows | /mnt/c、/mnt/d |
慢(跨 VM 文件系统) | 大量小文件读写会明显卡 |
最实用的性能建议只有一句:代码放 ext4(~/ 下),别放 /mnt/c。node_modules、target/、.git 这类小文件密集的目录放在 /mnt/c 上,构建时间能差出数倍。需要 Windows 侧访问,就从 \\wsl$ 进,而不是把项目挪到 C 盘。
权限映射也有坑:/mnt/c 上的文件默认全部显示为 0777,chmod 改了不生效。要在 Windows 盘上保留权限位,得开 metadata:
# /etc/wsl.conf
[automount]
options = "metadata,umask=22,fmask=11"
5. 两个配置文件:wsl.conf 与 .wslconfig
它们长得像,作用域完全不同。
| 文件 | 位置 | 作用域 | 典型键 |
|---|---|---|---|
/etc/wsl.conf |
发行版内部 | 单个发行版 | [boot] [automount] [interop] [user] [network] |
.wslconfig |
Windows 用户目录 %UserProfile%\.wslconfig |
所有发行版(虚拟机级) | [wsl2] [experimental] |
# /etc/wsl.conf —— 发行版级
[boot]
systemd=true
command = "mount -a"
[automount]
enabled = true
root = /mnt/
options = "metadata,umask=22,fmask=11"
[interop]
enabled = true
appendWindowsPath = false
[user]
default = yg
# %UserProfile%\.wslconfig —— 虚拟机级
[wsl2]
memory = 8GB
processors = 4
swap = 2GB
localhostForwarding = true
[experimental]
autoMemoryReclaim = gradual
sparseVhd = true
| 需求 | 写在哪 | 键 |
|---|---|---|
| 开 systemd | wsl.conf |
[boot] systemd=true |
| 限制内存上限 | .wslconfig |
[wsl2] memory=8GB |
| 去掉 Windows PATH 提速 | wsl.conf |
[interop] appendWindowsPath=false |
| 磁盘自动回收 | .wslconfig |
[experimental] autoMemoryReclaim |
改完都要 wsl --shutdown 再进,否则读的还是旧值。systemd=true 需要较新的 WSL,开启后 ps -p 1 才会显示 systemd。
6. 网络互通:localhost 什么时候通
WSL2 默认是 NAT 模式:WSL 有独立虚拟网卡,IP 每次启动都变。
$ ip route show default | awk '{print $3}' # 宿主机(Windows)在 WSL 视角的地址
$ cat /etc/resolv.conf | grep nameserver
> wsl hostname -I
> netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 `
connectport=8080 connectaddress=(wsl hostname -I).Trim()
> netsh interface portproxy show v4tov4
> New-NetFirewallRule -DisplayName "WSL 8080" -Direction Inbound -LocalPort 8080 -Protocol TCP -Action Allow
| 方向 | 默认是否通 | 前提 |
|---|---|---|
Windows → WSL 的 localhost:PORT |
通 | localhostForwarding=true(默认),且服务监听 0.0.0.0 |
WSL → Windows 的 localhost:PORT |
新版通 | 需要 Windows 侧服务监听非回环地址,或走宿主 IP |
| 局域网其它机器 → WSL | 不通 | 必须 portproxy + 防火墙放行 |
| IPv6 | 视版本 | 早期版本不支持,按 wsl --version 核对 |
服务只听 127.0.0.1 时,localhost 转发依然有效;但要从局域网访问,服务必须绑 0.0.0.0,且 Windows 侧要有 portproxy。三个条件缺一个都不通,别只盯防火墙。
7. 磁盘膨胀:ext4.vhdx 只涨不缩
WSL2 磁盘是一个动态扩展的 VHD,删了文件它不会自己变小。
> wsl --shutdown
> diskpart
DISKPART> select vdisk file="C:\Users\YG\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu24.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx"
DISKPART> attach vdisk readonly
DISKPART> compact vdisk
DISKPART> detach vdisk
DISKPART> exit
| 步骤 | 作用 | 注意 |
|---|---|---|
wsl --shutdown |
释放 vhdx 占用 | 不关就 attach 会失败 |
attach vdisk readonly |
只读挂载 | 必须 readonly,否则可能损坏 |
compact vdisk |
压缩空洞 | 耗时随体积增长 |
detach vdisk |
卸载 | 之后正常 wsl 启动 |
sparseVhd=true |
让新释放空间自动回收 | 需较新版本,按 wsl --version 核对 |
先在发行版里把空间真正释放掉(docker system prune、清 ~/.cache、journalctl --vacuum-size=200M),压缩才有意义。
8. GUI 与 systemd
$ ls /mnt/wslg # WSLg 存在即有 GUI 支持
$ echo $DISPLAY # 通常为 :0
$ ps -p 1 -o comm= # systemd 是否接管 PID 1
| 能力 | 前提 | 验证方式 |
|---|---|---|
| GUI 应用 | Windows 11 或装过 WSLg 更新的 Win10 | xclock、gedit 能弹窗 |
| systemd | wsl.conf 里 systemd=true + 较新 WSL |
systemctl status 可用 |
| GPU | 装对应驱动(DirectX 透传) | nvidia-smi |
GUI 不需要装 X Server 也不需要配 DISPLAY,WSLg 已经安排好;远程场景才要显式设 DISPLAY。
9. 常见坑:六种“明明配了却不对”
| 现象 | 原因 | 处理 |
|---|---|---|
| 时间跳变、TLS 证书报过期 | 宿主休眠后 WSL 时钟漂移 | sudo hwclock -s 同步;或配 chrony 指向宿主 |
| Docker 起不来 / 端口冲突 | Docker Desktop 的 WSL 后端与发行版内原生 docker 抢 socket | docker context use default,二选一 |
| 内存被吃满不释放 | 默认上限高且缓存不回收 | .wslconfig 设 memory=,开 autoMemoryReclaim |
.wslconfig 改了没效果 |
虚拟机没重启 | wsl --shutdown 后重进 |
ping 不通但 HTTP 通 |
WSL 默认禁 ICMP 回显 | 正常现象,用 curl/nc 验证 |
| DNS 解析失败 | 自动生成的 resolv.conf 被覆盖或 VPN 干扰 |
[network] generateResolvConf=false 后手写 |
时钟漂移值得单独说:WSL2 的时钟跟随宿主,宿主长时间睡眠后可能偏差几分钟,表现为 apt update 报证书未生效/已过期。sudo hwclock -s 从硬件时钟同步,是最快的修法。
10. 边界:这些事不适合交给 WSL
| 需求 | 更合适的方案 | 理由 |
|---|---|---|
| 生产级 Linux 行为验证 | 真机 / 云主机 / 完整虚拟机 | WSL 内核是微软定制版,行为有差异 |
| 需要固定 IP 对外服务 | 云主机 + 安全组 | WSL 的 NAT 地址每次变 |
| 内核模块开发 | 完整虚拟机 | WSL 不能加载任意模块 |
| 高性能磁盘 IO 基准 | 原生 Linux | /mnt/c 与虚拟磁盘都不代表真实性能 |
| 多用户隔离测试 | 独立 VM / 容器 | WSL 是单用户的开发环境 |
一句话收口:WSL2 是一个跑在 Hyper-V 里的开发用 Linux,不是 Windows 的子系统补丁。 把它当“另一个 Linux 主机”来对待——路径、网络、磁盘、时钟四件事各自独立配置,才不会在 /mnt/c 的性能和 NAT 的 IP 上反复踩坑。
11. 自测
wsl --set-default与wsl --set-default-version分别改什么?- 为什么项目目录不该放在
/mnt/c? /etc/wsl.conf与.wslconfig的作用域差别是什么?- Windows 的
localhost:8080能访问 WSL 服务,需要哪两个条件? ext4.vhdx只涨不缩,正确的压缩顺序是什么?- 宿主睡眠后 WSL 里 TLS 报证书过期,先做什么?