WSL2 算是 Windows 上跑 Linux 最顺手的方案了,没有虚拟机的开销,也不需要双系统来回切换。但真正动手装的时候,环境往往没想象中那么理想。我在企业内网环境接过不少离线安装 WSL2 的请求——开发机不连外网,或者终端机器在隔离网段,微软商店根本打不开,更别说在线拉 Ubuntu 镜像了。这篇文章就把我踩过的坑、试过的招都梳理一遍,从启用 Windows 功能、拿到离线安装包、装好后的网络和存储调优,到最常见的报错排查,整个流程串起来讲清楚。适合需要在断网、半断网或者受管控 Windows 环境里部署 WSL2 的运维和开发者参考。
1. 先理清思路:WSL2 离线安装到底在装什么
很多人一上来就找安装包,结果装到一半发现缺这个缺那个,其实就是没搞明白 WSL2 的组成结构。离线安装最忌讳的就是东拼西凑,先把整体框架讲清楚,后面每一步才有依据。
1.1 为什么 WSL2 值得离线折腾
WSL2 和第一代 WSL 最大的区别,是换成了真正的 Linux 内核。WSL1 靠的是 Windows 内核的翻译层模拟 Linux 系统调用,兼容性看着还行,但碰到 Docker、CUDA 这类对系统调用特别敏感的东西就露馅了。WSL2 干脆用虚拟化技术跑一个完整的轻量级虚拟机,里面就是原汁原味的 Linux 内核,所以绝大多数 Linux 软件都能直接跑,不会再有“明明在 Linux 环境里,却装什么都要编译半天”的尴尬。
离线环境恰恰更需要 WSL2。我之前接手过一个研发网项目,开发机全部在内网隔离区,没有外网权限,但团队又想把开发环境统一到 Linux 上。双系统不现实,虚拟机又太重,最后方案就是离线装好 WSL2,再把依赖的软件包一次性拷进去。这个套路跑通之后,几十台机器全部复用同一个镜像,效率比在线一台台配置高得多。
1.2 离线安装 WSL2 的三大部分
WSL2 的安装不是下载一个文件就完事的,它实际上由三个独立但必须组合的部分组成:
第一部分是 Windows 功能层。WSL2 依赖两个 Windows 功能:“适用于 Linux 的 Windows 子系统”和“虚拟机平台”。前者是 WSL 的基础功能,后者是 WSL2 跑虚拟机的支撑。这两个功能没启用,后面装什么都是白搭。在离线机器上,这两个功能可以通过 DISM 命令离线启用,不依赖外网。
第二部分是 WSL 运行时本身。包括 wsl.exe 命令行工具和 WSL2 使用的 Linux 内核。微软在较新的 WSL 版本里把运行时拆成了独立组件,可以通过 MSI 或 ZIP 包离线升级。这就是为什么有时候报错“WSL 内核版本太旧”时,直接在联网机器上下个内核安装包拷过去就能解决。
第三部分是 Linux 发行版。也就是你实际使用的 Ubuntu、Debian、Kali 等系统镜像,在 Windows 上表现为 .appx 或 .msixbundle 格式的安装包。这部分对离线安装来说是最容易出问题的,因为很多人以为只能从微软商店下载,其实微软提供了官方的离线直链,后面我会详细说。
搞清楚这三个层次之后,离线安装的思路就清晰了:先启用 Windows 功能,再准备 WSL 运行时,最后安装发行版镜像。一步都不能跳,也不能只装其中一部分就跑去开终端。
2. 环境准备:硬件和 Windows 功能层
这个环节最容易翻车,但也是步骤最固定的。按顺序走,基本十分钟内能搞定。
2.1 先确认机器能不能跑虚拟化
WSL2 必须在虚拟化开启的情况下才能运行。我最怕遇到的情况就是用户装了半天,最后卡在“无法启动,因为此计算机上未启用虚拟化”的报错上。其实这个报错在安装前就能提前发现。
最简单的确认方法:打开 Windows 自带的“任务管理器”,切到“性能”选项卡,点击“CPU”,看右下角“虚拟化”这一行。显示“已启用”,说明硬件虚拟化功能正常;显示“已禁用”,就需要进 BIOS/UEFI 设置里开启,一般是找 Intel Virtualization Technology(VT-x)或 AMD SVM Mode 这类选项,不同主板叫法不太一样,改完保存重启就行。
还有一个需要注意的场景是虚拟机里跑 Windows 再装 WSL2。这种情况下虚拟化是否可用取决于宿主机是否开启了“嵌套虚拟化”。以 Hyper-V 为例,需要在宿主机上对对应虚拟机执行Set-VMProcessor -VMName "你的虚拟机名字" -ExposeVirtualizationExtensions $true这条 PowerShell 命令,然后再重启虚拟机。VMware 和 VirtualBox 里也有类似的嵌套虚拟化选项,不打开的话里面就算显示支持也跑不了 WSL2。
2.2 通过 DISM 开启两个关键功能
确认虚拟化没问题之后,接下来就是启用 WSL2 依赖的 Windows 功能。图形界面操作路径是“控制面板 -> 程序和功能 -> 启用或关闭 Windows 功能”,然后勾选“适用于 Linux 的 Windows 子系统”和“虚拟机平台”。但离线环境我建议直接用 DISM 命令,速度更快,也方便批量执行。
用管理员身份打开 PowerShell 或命令提示符,依次执行下面两行:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart关键参数解释一下:/norestart是暂时不重启,两个功能一起启用完再统一重启,省得来回折腾。如果之前机器上从来没开过 Hyper-V 或虚拟机平台,执行完第一条命令可能会提示“操作成功完成,但重启计算机之前,这些更改不会生效”,这是正常的,说明功能已经加入系统,等重启就会真正激活。
另外如果你的 Windows 版本比较老,比如 Windows 10 1903 或更早,DISM 命令可能不认识VirtualMachinePlatform这个功能名,那就得先更新系统或者直接升级到 1909 以上的版本。微软官方要求是 Windows 10 2004 及以上版本才比较好地支持 WSL2,我实际测试下来,1909 勉强能用,但问题比较多,能升级就升级。
全部执行完之后,重启电脑。这一步别省,我之前偷懒不重启直接往下装,结果 WSL 提示功能不可用,白白排查了一个多小时。
3. 离线拿到发行版安装包:Ubuntu 的几种姿势
Windows 功能启用并重启之后,就到了最核心的环节——离线安装 Linux 发行版。这个环节水最深,也是大家问得最多的。
3.1 官方离线下发页面的用法
微软其实提供了一个专门的手动安装页面,不需要打开微软商店,直接就能下载各发行版的离线安装包。在联网的电脑上访问微软官方文档中 WSL 的手动安装说明,里面列出了 Ubuntu、openSUSE、Kali 等几个发行版的直链,点击下载得到的就是.appx或.msixbundle后缀的文件。
这个页面解决了一大半问题,因为很多人以为离线安装就得去别人机器上抠文件,其实官方一直在维护这个备用渠道。要注意的是,页面里的链接会随着版本更新变化,下载时看一眼文件名里的版本号,优先选最新的 LTS 版本,比如 Ubuntu 22.04。我一般习惯直接把文件重命名成容易记住的名字,比如Ubuntu.appx,后续命令写起来省事。
下载好之后,把这个 appx 文件拷贝到离线机器上,放在一个纯英文路径下,比如D:\wsl\packages\。路径里别带中文,后面命令行操作会少很多麻烦。
3.2 Add-AppxPackage 安装与依赖问题
拿到安装包后,安装命令非常简单。在离线机器上管理员身份打开 PowerShell,进入安装包所在目录,执行:
Add-AppxPackage .\Ubuntu.appx顺利的话,等进度条跑完就装好了。但离线的机器往往没那么顺利,最常见的报错是提示缺少“Windows 应用程序运行时”之类的依赖,尤其是Microsoft.VCLibs这个框架包。这个包在联网机器上会自动从商店拉取,离线环境就得手动准备。
解决办法是提前在联网机器上下载对应架构的 VCLibs 包,同样拷过来,先执行:
Add-AppxPackage .\Microsoft.VCLibs.x64.14.00.Desktop.appx之后再装 Ubuntu 就不会报依赖缺失了。这个细节特别容易忽略,我第一次离线装的时候就卡在这一步,当时还以为是 Windows 版本太老导致的,排查了半天才发现是缺依赖。
另外,如果你拿到的是.msixbundle后缀的包,直接 Add 可能会提示无法安装。网上有个技巧是把它改名成.zip,解压后从里面找到真正的.appx文件再安装。这个方法我实测过,可行。
3.3 不依赖商店的另类姿势:免安装解压法
除了正式的安装方式,还有一种非常适合批量部署的免安装姿势——直接从已经装好 WSL2 的机器上,拷贝发行版的完整目录。
具体做法是找到那台机器上 Ubuntu 的安装目录,一般位于%LOCALAPPDATA%\Packages\下面,文件夹名字类似CanonicalGroupLimited.Ubuntu22.04LTS_xxx,把这个文件夹整个拷到目标机器的相同位置。然后再把开始菜单里的启动入口(Ubuntu.exe)手动创建个快捷方式,或者直接进入目录运行ubuntu.exe完成初始化和默认用户设置。
这种方式的好处是不需要执行 Add-AppxPackage,也不用处理 VCLibs 依赖,因为运行时文件全是现成的。但前提是两台机器的 Windows 版本和 WSL 运行时版本不能差太远,否则可能出现内核模块不匹配的兼容问题。我一般只在批量部署同版本 Windows 的机器时用这招,省去每台机器下载安装包的麻烦。
4. 装完第一件事:网络与存储调优
发行版装好,第一次启动会让你设置用户名和密码,这一步完成后 WSL2 就能正常使用了。但还没到松口气的时候,离线环境里有两个问题几乎必定会碰到:网络不通和磁盘跑满。这两个问题不解决,WSL2 用起来会非常难受。
4.1 用 .wslconfig 限制内存和 CPU
WSL2 默认会吃掉物理内存的一半左右作为虚拟机内存,这个设计在配置高的机器上无所谓,但 8GB 内存的老机器就有点吃不消了。解决办法是在 Windows 用户目录下创建一个.wslconfig文件,专门用来限制 WSL2 的资源占用。
用记事本新建文件,填入以下内容,保存到C:\Users\你的用户名\.wslconfig:
[wsl2] memory=4GB processors=4 swap=2GB参数含义很简单:memory是最大内存,processors是最大 CPU 核数,swap是交换分区大小。没有这个文件时,WSL2 采用默认策略——内存取物理内存的 50% 或 8GB 中的较小值,CPU 则基本不限制。对于只想跑开发环境的场景,限制在 4GB 内存、4 核基本够用,还能给 Windows 留足资源。
修改完.wslconfig之后,需要执行wsl --shutdown让所有发行版停止运行,再重新进入 WSL 才能生效。这个文件只对 WSL2 有效,WSL1 不受它管理。
4.2 把发行版迁移到非系统盘
WSL2 的发行版默认安装在 C 盘,而且虚拟磁盘文件(ext4.vhdx)会随着使用越来越大,装几个 Linux 软件、跑几次编译,十几 GB 就出去了。C 盘空间紧张的话,建议装完立刻迁移到其他磁盘。
迁移最稳妥的方式是用 WSL 自带的导出导入功能。假设当前发行版叫Ubuntu,先执行:
wsl --export Ubuntu D:\wsl\backup\ubuntu.tar这个过程会把整个文件系统打包成一个 tar 文件,大小取决于当前使用情况。导出完成后,注销原来的发行版:
wsl --unregister Ubuntu注意--unregister会删除这个发行版的所有数据和配置,所以一定要确保上一步导出成功。然后重新导入到新位置:
wsl --import Ubuntu D:\wsl\distro\ubuntu D:\wsl\backup\ubuntu.tar --version 2第二个参数是新发行版的安装目录,第三个参数是刚才导出的 tar 文件路径。--version 2是明确指定用 WSL2。导入完成后进去 WSL,可能会发现默认用户变成了 root,这是因为导出导入过程中的用户配置没有自动带上。解决方法是在导入后的 WSL 里编辑/etc/wsl.conf,加入:
[user] default=你的用户名保存后执行wsl --shutdown再重进,就会恢复原来的普通用户环境了。
4.3 网络模式选择:NAT 还是镜像
WSL2 默认采用 NAT 网络模式,相当于 Windows 主机给 WSL2 分配了一个内部 IP。这种模式下,WSL 里访问外网没问题,但从局域网其他机器访问 WSL 里的服务就特别麻烦,因为它的 IP 不在局域网网段。比如我在 WSL 里跑了个 Web 服务,想拿手机测试,默认设置下基本没戏。
解决方法是改用镜像网络模式。在.wslconfig文件的[wsl2]节点下加入一行:
networkingMode=mirrored镜像模式下,WSL2 会直接共享 Windows 主机的网络接口和 IP,局域网里的设备能直接访问 WSL 里跑的服务,WSL 里也能访问 Windows 局域网里的其他设备,网络就通了。这个模式需要 WSL 版本在 2.0 以上,如果之前没有手动升级过 WSL,可以先在联网机器上把 WSL 最新的 MSI 包下载下来离线安装,再启用镜像模式。
还要提一嘴 DNS 问题。NAT 模式下偶尔会遇到“能 ping 通 IP,但域名解析失败”的情况,这是 WSL 的 DNS 配置和 Windows 不一致导致的。在 WSL 里查看/etc/resolv.conf,如果里面的 nameserver 还停留在老的内网地址,可以手动改成 Windows 主机的 DNS 地址,或者干脆启用镜像模式让网络配置彻底统一。
5. 离线环境下的常见报错与排查速查
这一节是实用性最强的部分。我按真实验到过的频率把问题排了个序,每个问题都给出排查路径和解决手段。
5.1 “虚拟化未启用”的三种可能性
开头提过的WslRegisterDistribution failed with error: 0x80370114,也就是“请确保计算机固件设置中虚拟机平台已启用”这类报错,我总结下来只有三种原因:
第一种是 BIOS 里真的没开虚拟化,而且任务管理器里也明确显示“已禁用”。这个只能进 BIOS 设置,没有别的办法。
第二种是开了 Hyper-V,但没启用“虚拟机平台”这个 Windows 功能。排查方式是执行systeminfo命令,看 Hyper-V 要求那一栏里,四项要求是否都显示“已检测到”。如果“虚拟机监控程序”那项显示“已检测到”,但“虚拟机平台”相关的功能缺失,就用前面提到的 DISM 命令把VirtualMachinePlatform补上。
第三种是在虚拟机里跑 WSL2,宿主机没开嵌套虚拟化。这种情况任务管理器里显示的虚拟化状态可能是“已启用”,但 WSL2 还是起不来,原因就是虚拟机没有把硬件虚拟化指令透传给内部系统。解决方法是回到宿主机虚拟机管理软件,开启嵌套虚拟化选项,然后重启虚拟机。
5.2 发行版安装失败或启动即崩
Add-AppxPackage装完 Ubuntu 后,第一次启动时提示“占位程序包错误”或者直接弹窗说找不到应用,这个问题很常见。排查顺序是先运行Get-AppxPackage *Ubuntu*,查看软件包状态,如果是“Staged”而不是“Installed”,说明安装没走完。手动再执行一次Add-AppxPackage试试,不行就先把所有 Ubuntu 相关包卸载干净再重装。
另一种情况是启动 Ubuntu 时窗口闪一下就消失,没有任何报错。这种大概率是 WSL 运行时版本和发行版不兼容,或者 WSL 内核文件损坏。处理方法是先wsl --shutdown,再wsl --update,如果离线环境没有外网,就手动安装最新版的 WSL MSI 包。
5.3 WSL 内网络能通但 DNS 解析慢
这个现象很烦:在 WSL 里执行ping 223.5.5.5正常,但ping google.com就要卡好几秒。原因是 WSL2 默认会把 Windows 的 DNS 配置同步到虚拟网卡上,但离线内网环境里 Windows 主机的 DNS 可能指向的是某些特殊地址,WSL 里的解析就走歪了。
最简单的解决方法是编辑/etc/wsl.conf,在[network]节点下设置generateResolvConf = false,然后手动写死/etc/resolv.conf里的 nameserver,改成 Windows 主机的实际 DNS 地址或者内网 DNS。改完执行wsl --shutdown重进就生效了。
5.4 WSL 本身版本太旧,离线怎么升级
很多功能(比如镜像网络模式、systemd 支持)都需要新版 WSL 运行时。离线机器执行wsl --update会一直卡住,因为没法访问在线源。解决办法是在联网机器上访问 WSL 的官方 GitHub Release 页面,下载.msi安装包或者便携版.zip包,拷到离线机器后执行msiexec /i wsl.x.x.x.x64.msi静默安装即可。
如果下载的是.zip便携版,可以解压后把整个文件夹拷到C:\Program Files\WSL,然后把这个路径加入系统 PATH 环境变量,执行wsl --version确认版本号已经是新的。
6. 离线装完 WSL2 之后怎么办:开发环境延伸
很多人装完 WSL2 以为万事大吉,结果一进系统发现 apt、pip、npm 全都用不了,因为默认源都在外网。离线环境里跑通开发环境,才是这整套部署真正落地的关键。
6.1 从离线软件仓库拿依赖包
离线环境下 Linux 软件安装有两个思路。一个是提前在联网机器上把需要的.deb包全部下载好,拷进去之后用dpkg -i挨个装,或者用apt install ./*.deb批量装。另一个思路是配置一个内网源,把 Ubuntu 软件仓库同步到内网服务器,然后把/etc/apt/sources.list里的地址全部改成内网镜像地址。
对于小规模部署,我一般用第一种思路,简单直接。在联网机器上可以先apt update,然后apt download 包名下载单个包,依赖多的话用apt-get install --download-only先把所有依赖都缓存下来,一起拷进去。这样在离线机器上只需要一条指令就能装完一堆包。
Python 环境也是类似玩法。在联网机器上用pip download -r requirements.txt -d D:\pypackages把依赖包和所有传递依赖都下成 wheel 文件,拷进 WSL 后执行pip install --no-index --find-links=/path/to/pypackages -r requirements.txt,整个过程零网络依赖。Node 项目用npm pack或者私有 npm registry 的方式处理,思路都一样。
6.2 在 WSL2 里跑 GUI 程序和桌面环境
离线环境有时候还需要图形界面。WSL2 本身支持 WSLg,也就是 Windows 11 或较新 WSL 版本上直接运行图形界面程序,把显示输出到 Windows 桌面。但离线环境下,我遇到的情况是 WSLg 偶尔起不来,尤其是基础系统镜像和 WSL 运行时版本对不上时。
替代方案是用 X Server 转发,或者直接安装 xvfb 做虚拟显示。下载xvfb的 deb 包离线安装后,跑测试脚本时用xvfb-run加--auto-servernum参数,把图形程序塞进虚拟显示,该出截图出截图,该跑测试跑测试,不需要真实桌面环境。这套方案在服务器类 WSL2 环境里很实用。
6.3 用 systemd 托管常驻服务
新版 WSL2 默认支持 systemd,离线安装也不受影响。启用方法是在 WSL 内编辑/etc/wsl.conf:
[boot] systemd=true保存后执行wsl --shutdown重进,运行systemctl list-units就能看到系统服务列表了。接下来不管是systemctl enable ssh还是systemctl start docker,都和真实 Linux 服务器行为一致。
这里要注意一个细节:docker 这种需要内核模块支持的服务,在 WSL2 里不是开箱即用的。离线安装 docker 需要额外的步骤,而且如果公司内网有自定义内核模块或安全策略,还得额外配置。WSL2 的内核由 Windows 侧管理,不像真实 Linux 那样随便加载自定义内核模块,所以跑 docker 是没问题,但碰到底层网络和存储驱动定制就比较折腾。
7. 个人经验总结
离线安装 WSL2 这件事,说难不难,但确实容易在细节上栽跟头。我自己的体会是,整个流程里最容易被低估的是准备工作:虚拟化是否开启、Windows 功能是否启用、依赖包是否齐全,这三件事没确认好,后面全是无效劳动。建议做一张检查表,每台机器按表逐项确认,能省掉至少一半的排查时间。
另外想提醒一点,离线环境下的安装包和配置文件一定要统一管理。我习惯在联网机器上建一个固定的“离线源目录”,按“Windows功能说明文档 / WSL运行时MSI / 发行版appx / 开发工具依赖包”四个子目录归档,版本号写清楚在文件名里。这样不光自己方便,交接给同事的时候也能快速上手。毕竟离线部署这种东西,一旦版本不匹配,排查起来比在线环境痛苦得多。