双系统的终极方案 - WSL2

注意
本文最后更新于 2024-04-08,文中内容可能已过时。

双系统的终极方案 - WSL2

作为一个开发者主力系统使用 Linux 系统的好处是显而易见的,大部分的技术的安装、演示,都是以 Linux 系统为基础的,而且很多技术或者工具压根儿就不兼容 Windows 系统,比如 Docker。主力系统使用 Linux,开发体验将有很大提升。

主要是我这段时间主要从事运维相关的工作,对 Linux 的使用也很有心得,我感觉有这个能力了可以用好 Linux

其实从很早的时候想将主力操作系统切换为 Linux,希望能在一个跟服务器环境相同的环境中开发,这样的话,我们就可以使用 Nginx、Docker 这种非常方便的工具了,对我们的开发和日常工作都将带来极大的便利,但是经过一定的调研之后(主要调研 Ubuntu+GNOME),发现 Ubuntu 到目前为止依然有一些无法解决的问题,有这些问题的存在,让我认为现在将主力操作系统切换到 Linux 并不明智:

  • GNOME 桌面存在不稳定的问题,插件装多了之后可能会崩溃

  • GNOME 桌面的额头叠加问题很难适配解决,IDEA 等开发工具在 GNOME 桌面下的额头问题很严重,而此类问题在 Windows 下已经成功优化了

  • 微信和企业微信不支持 Linux,在可见的未来也不会支持,此外,其他的常用办公软件都不是很重视 Linux 的适配

诸如此类的原因让我觉得完全放弃 Windows,转向 Linxu 并不明智,这个时候我想到了,作为一个成年人,我的想法应该是我全都要

于是我想到了双系统方案、Linux 虚拟机、还有 WSL。这三种方式我基本上都尝试过,然后我了解到 WSL2 经过一段时间的优化已经足够好用,简单体验之后,发现使用起来确实非常丝滑,非常方便,最终决定采用 WSL2 来实现双系统,我相信这也是目前为止(2024 年 2 月 28 日)双系统的终极方案。

先说结论:

WSL2 的文件系统跟 Windows 是互通的,而且通过配置可以让 WSL2 中的 Linux 发行版跟 Windows 共用网卡端口,给人的感觉就是像是一个电脑里真的安装了两个独立又互通的操作系统,这两个操作系统同时共享电脑的磁盘、网卡等硬件。WSL2 可以浏览 Windows 的文件,Windows 也可以浏览 WSL2 的文件,在 WSL2 中启动一个服务占用了 8080 端口,在另一台电脑访问当前电脑的ip:8080,可以正常访问 WSL2 中的服务,非常惊艳。

安装

在线安装

官方文档:安装 WSL | Microsoft Learn。官方文档写的很好,没有必要看别人的博客

首先打开 powersehll,运行以下命令行查看当前支持哪些 Linux 发行版

1
wsl --list --online

然后选择一个版本进行安装

1
wsl --install -d <DistroName> 

比如当前(2024 年 2 月 28 日)支持Ubuntu-22.04

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
wsl --list --online
以下是可安装的有效分发的列表
使用 'wsl.exe --install <Distro>' 安装

NAME                                   FRIENDLY NAME
Ubuntu                                 Ubuntu
Debian                                 Debian GNU/Linux
kali-linux                             Kali Linux Rolling
Ubuntu-18.04                           Ubuntu 18.04 LTS
Ubuntu-20.04                           Ubuntu 20.04 LTS
Ubuntu-22.04                           Ubuntu 22.04 LTS
OracleLinux_7_9                        Oracle Linux 7.9
OracleLinux_8_7                        Oracle Linux 8.7
OracleLinux_9_1                        Oracle Linux 9.1
openSUSE-Leap-15.5                     openSUSE Leap 15.5
SUSE-Linux-Enterprise-Server-15-SP4    SUSE Linux Enterprise Server 15 SP4
SUSE-Linux-Enterprise-15-SP5           SUSE Linux Enterprise 15 SP5
openSUSE-Tumbleweed                    openSUSE Tumbleweed

我们可以直接通过以下命令安装,注意,Windows11 中默认使用的是 WSL2,而不是 WSL1

1
wsl --install -d Ubuntu-22.04

实际上,Ubuntu-22.04是通过微软的应用商店下载的

安装完成之后提示重启操作系统,重启之后会自动打开 PowerShell,并让用户设置Ubuntu-22.04系统的用户名密码即可登录Ubuntu-22.04

后续,如果我们想进入Ubuntu-22.04,可以在 Windows Terminal 中进入,安装Ubuntu-22.04的时候,已经自动在 Windows Terminal 中添加了相关链接。选择Ubuntu 22.04.03 LTS登录我们刚刚安装的Ubuntu-22.04

然后,我们可以通过以下命令,查看所有安装的发行版,

1
wsl --list --verbose

简化版为wsl -l -v

在结果中,可以看到 WSL 安装的所有的发行版的版本,其中 VERSION 列表示的是 WSL 当前的版本,Windows11 中默认使用的是 WSL2。

1
2
3
wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-22.04    Running         2

自己准备发行版 ISO 安装

官方教程:导入要与 WSL 一起使用的任何 Linux 发行版 | Microsoft Learn

过程很简单,到 Docker Hub 上下载 CentOS 的镜像,打成 tar 包,然后导入到 WSL 中即可。以后有时间再弄吧,TODO

日常使用

命令

WSL 管理 Linux 发行版(Distro)/ 子系统 的方式,有点类似 Docker 管理镜像的方式:WSL 就是一个类似于 docker 的管理程序,wsl 可以安装多个发行版,然后可以单独控制每一个发行版的启动和关闭。

wsl命令的格式如下

1
wsl.exe [参数] [选项...][命令行]

其中我们一般省略.exe

直接执行wsl,会进入默认的子系统,如果当前没有子系统启动,则会先启动默认的子系统,然后进入默认的子系统。

后面我们会学习到wsl --set-default <Distro>用于设置默认的子系统,其中--set-default 可简写为 -s

参数:运行 Linux 二进制文件(一般我们称之为命令 command)的参数,如果未指定 shell(例如/bin/bash),wsl.exe 将启动默认的 shell。

每一个命令都有其对应的二进制文件,比如cpmv这类的,在/bin都有其对应的文件。

  • --exec <CommandLine>-e <CommandLine>:在不使用默认 Linux shell 的情况下执行指定的命令。

    1
    2
    
    wsl -e pwd
    /mnt/c/Users/wwwli
  • --shell-type <standard|login|none>:使用指定的 shell 类型执行指定的命令。

  • --:按原样传递剩余的命令行。

    1
    2
    
    wsl pwd   
    /mnt/c/Users/wwwli

选项:

  • --cd <Directory>:将指定目录设置为当前工作目录。即登录发行版,并切换到指定目录。如果使用 ~,则将使用 Linux 用户的主路径。如果路径以/字符开始,它将解释为绝对 Linux 路径。否则,该值必须是绝对 Windows 路径。

  • --distribution <Distro>, -d <Distro>:运行指定的分发版。常用

  • --user <UserName>, -u <UserName>:以指定用户身份运行。

  • --system:为系统分发版启动 shell。不知道啥意思

用于管理子系统的参数

  • --help:显示帮助文档。

  • -debug-shell:出于诊断目的打开 WSL2 调试 shell。

  • --install [发行版] [选项...]:安装适用于 Linux 的 Windows 子系统分发版。其中,发行版参数可以通过wsl.exe --list --online查看当前可用的发行版的列表,选项部分解释如下:

    • --no-launch, -n:安装后不要启动分发版。

    • --web-download:从 Internet 而不是 Microsoft Store 下载分发版。

    • --no-distribution:仅安装所需的可选组件,不安装分发版。

    • --enable-wsl1:启用 WSL1 支持。

  • --manage <Distro> <Options...>:更改发行版特定选项。支持的选项如下:

    • --set-sparse <true|false>, -s <true|false>:将发行版的 vhdx 设置为稀疏,从而允许自动回收磁盘空间。
  • --mount <Disk>:在所有 WSL 2 分发版中附加和装载物理磁盘或虚拟磁盘。选项:

    • --vhd:指定 <Disk> 引用虚拟硬盘。

    • --bare:将磁盘附加到 WSL2,但不要装载它。

    • --name <Name>:使用装入点的自定义名称装载磁盘。

    • --type <Type>:装载磁盘时要使用的文件系统 (如果未指定) 默认为 ext4。

    • --options <Options>:其他装载选项。

    • --partition <Index>:要装载的分区的索引 (如果未指定) 默认为整个磁盘。

  • --unmount [磁盘]:从所有 WSL2 分发版中卸载和分离磁盘。如果在没有参数的情况下调用,则卸载和分离所有磁盘。

  • --set-default-version <Version>:更改新分发版的默认安装版本。若要设置 WSL 1 或 WSL 2 为默认使用的版本,请将 <Version> 替换为数字 1 或 2。例如 wsl --set-default-version 2。该数字表示新 Linux 发行版安装默认使用的 WSL 版本。

  • --shutdown:立即终止所有正在运行的分发版和 WSL 2, 常用

  • --status:显示所有子系统状态。

  • --update:更新适用于 Linux 的 Windows 子系统包。

    • --pre-release:下载预发行版本 (如果可用)。
  • --version, -v:显示版本信息。

用于在子系统中管理分发版的参数:

  • --export <Distro> <FileName> [选项]:将分发版导出到 tar 文件。

    • --vhd:指定应将分发版导出为 .vhdx 文件。
  • --import <Distro> <InstallLocation> <FileName> [选项]:将指定的 tar 文件作为新分发版导入。

    • --version <Version>:指定要用于新分发的版本。

    • --vhd:指定所提供的文件是 .vhdx 文件,而不是 tar 文件。此操作在指定的安装位置创建 .vhdx 文件的副本。

  • --import-in-place <Distro> <FileName>:将指定的 .vhdx 文件作为新分发版导入。必须使用 ext4 文件系统类型设置此虚拟硬盘的格式。

  • --list [选项]-l [选项]:列出分发版。选项:

    • --all:列出所有分发版,包括当前正在安装或卸载的分发版。

    • --running:仅列出当前正在运行的分发版。

    • --quiet, -q:仅显示分发版名称。

    • --verbose, -v:显示有关所有分发版的详细信息。

    • --online, -o:显示适合通过 wsl.exe --install 安装的可用分发版列表。

  • --set-default <Distro>, -s <Distro>:将分布版设置为默认值。

  • --set-version <Distro> <Version>:更改指定分发版的版本。

  • --terminate <Distro>, -t <Distro>:终止指定的分发版。

  • --unregister <Distro>:取消注册分发版并删除根文件系统。


其实常用的也就是:

  • 启动并进入默认子系统wsl,启动指定的子系统wsl -d <Distro>

  • 关闭子系统和 WSL:wsl --shutdownwsl -t <Distro>关闭指定的子系统。


注意,关闭 Terminal 是不会关闭 Linux 系统的。需要通过wsl --shutdown关闭子系统和 WSL2 或者通过wsl --terminate <Distro>或者wsl -t <Distro>关闭指定的子系统。

隐藏桌面图标

参考博客:Reddit - Dive into anythingBrainByteZ » [Windows 11] Hide/Remove WSL Linux icon from Desktop

具体的原理是:Registry Tweak - Add or Remove System Icons from the Desktop

安装完Ubuntu 22.04之后,桌面出现了图标:

这个图标无法删除,想要隐藏的话,没有找到官方提供的方法,只找到一个国外大神想到的办法。

具体做法是,到[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel]这个目录下,创建一个名称为{B2B4A4D1-2754-4140-A2EB-9A76D9D7CDC6}类型为DWORD (32-Bit)的十进制的值,值为 1,然后重启,即可隐藏图标

配置用户

WSL 修改默认用户_wsl 设置默认用户-CSDN 博客

首先在 Linux 子系统中设置 root 用户密码,我这里设置的是root/root

1
sudo  passwd root

然后配置以后都用 root 用户登录,修改 Linux 子系统的默认登录用户,命令为:

1
<DistributionName> config --default-user <Username>

当前安装的发行版是Ubuntu-22.04,其在微软应用商店下下载,下载的软件执行器的名字为ubuntu2204.exe,因此当前执行的就是

1
ubuntu2204 config --default-user root

再次启动wsl,默认登录的就是 root 用户了。

手动的安装发行版不能这样设置,因为这些发行版没有可执行启动器。 可以改为使用 /etc/wsl.conf 文件来更改导入的发行版的默认用户。请参阅高级设置配置文档中的“自动装载”选项。

但是现在都.wslconfig了啊,不用wsl.conf了啊

可以用wsl --user <Username>或者wsl --distribution <Distribution Name> --user <User Name>来启动。

配置子系统

配置文件:WSL 中的高级设置配置 | Microsoft Learn

我们在 VMware 虚拟机中创建虚拟机的时候,可以配置虚拟机使用的 CPU 核心数,占用的内存,WSL 中也可以配置这些信息。

  • .wslconfig 用于在 WSL 2 上运行的所有已安装发行版中配置全局设置
  • wsl.conf 用于为在 WSL 1 或 WSL 2 上运行的每个 Linux 发行版按各个发行版配置本地设置

我们当前使用的是 WSL2,因此只需要关注.wslconfig

使用 .wslconfig 为 WSL 上运行的所有已安装的发行版配置全局设置

  • 默认情况下,.wslconfig 文件不存在。它必须创建并存储在%UserProfile%目录中才能应用这些配置设置。

    %UserProfile%路径一般为C:\Users\<UserName>

  • 用于在作为 WSL 2 版本运行的所有已安装的 Linux 发行版中全局配置设置。

  • 只能用于 WSL 2 运行的发行版。作为 WSL 1 运行的发行版不受此配置的影响,因为它们不作为虚拟机运行。

  • 要访问 %UserProfile% 目录,请在 PowerShell 中使用 cd ~ 访问主目录(通常是用户配置文件 C:\Users\<UserName>),或者可以打开 Windows 文件资源管理器并在地址栏中输入 %UserProfile%。该目录路径应类似于:C:\Users\<UserName>\.wslconfig

配置项:

key value default 说明
内核 (kernel) path Microsoft 内置内核提供的收件箱 自定义 Linux 内核的绝对 Windows 路径。
内存 大小 Windows 上总内存的 50% 或 8GB,以较小者为准;在 20175 之前的版本上:Windows 上总内存的 80% 要分配给 WSL 2 VM 的内存量。
处理器 number Windows 上相同数量的逻辑处理器 要分配给 WSL 2 VM 的逻辑处理器数量。
localhostForwarding boolean true 一个布尔值,用于指定绑定到 WSL 2 VM 中的通配符或 localhost 的端口是否应可通过 localhost:port 从主机连接。
kernelCommandLine string 空白 其他内核命令行参数。
safeMode boolean false 在“安全模式”中运行 WSL,这会禁用许多功能,应用于恢复处于错误状态的发行版。仅适用于 Windows 11 和 WSL 版本 0.66.2+。
swap 大小 Windows 上 25% 的内存大小四舍五入到最接近的 GB 要向 WSL 2 VM 添加的交换空间量,0 表示无交换文件。交换存储是当内存需求超过硬件设备上的限制时使用的基于磁盘的 RAM。
swapFile path %USERPROFILE%\AppData\Local\Temp\swap.vhdx 交换虚拟硬盘的绝对 Windows 路径。
pageReporting boolean true 默认的 true 设置使 Windows 能够回收分配给 WSL 2 虚拟机的未使用内存。
guiApplications 布尔* true 一个布尔值,用于在 WSL 中打开或关闭对 GUI 应用程序 (WSLg) 的支持。仅适用于 Windows 11。
debugConsole 布尔* false 一个布尔值,用于在 WSL 2 发行版实例启动时打开显示 dmesg 内容的输出控制台窗口。仅适用于 Windows 11。
nestedVirtualization 布尔* true 用于打开或关闭嵌套虚拟化的布尔值,使其他嵌套 VM 能够在 WSL 2 中运行。仅适用于 Windows 11。
vmIdleTimeout 数量* 60000 VM 在关闭之前处于空闲状态的毫秒数。仅适用于 Windows 11。
dnsProxy bool true 仅适用于 networkingMode = NAT。布尔值,通知 WSL 将 Linux 中的 DNS 服务器配置为主机上的 NAT。设置为 false 会将 DNS 服务器从 Windows 镜像到 Linux。
networkingMode** string NAT 如果值为 mirrored,则会启用镜像网络模式。默认或无法识别的字符串会生成 NAT 网络。
firewall** bool 如果设置为 true,则 Windows 防火墙规则以及特定于 Hyper-V 流量的规则可以筛选 WSL 网络流量。
dnsTunneling** bool false 更改将 DNS 请求从 WSL 代理到 Windows 的方式
autoProxy* bool false 强制 WSL 使用 Windows 的 HTTP 代理信息

其中

具有 path 值的条目必须是带有转义反斜杠的 Windows 路径,例如:C:\\Temp\\myCustomKernel

具有 size 值的条目后面必须跟上大小的单位,例如 8GB 或 512MB

值类型后带有 * 的条目仅在 Windows 11 中可用。

值类型后带有 ** 的条目需要 Windows 11 版本 22H2 或更高版本。

这些设置是试验性功能的选择加入预览,我们的目标是将来将其设为默认设置。

.wslconfig 节标签:[experimental]

设置名称 默认值 说明
autoMemoryReclaim string disabled 检测空闲 CPU 使用率后,自动释放缓存的内存。设置为 gradual 以慢速释放,设置为 dropcache 以立即释放缓存的内存。
sparseVhd bool false 如果设置为 true,则任何新创建的 VHD 将自动设置为稀疏。
useWindowsDnsCache** bool false 仅当 wsl2.dnsTunneling 设置为 true 时才适用。如果此选项设置为 false,则从 Linux 隧道传输的 DNS 请求将绕过 Windows 中的缓存名称,以始终将请求放在网络上。
bestEffortDnsParsing** bool false 仅当 wsl2.dnsTunneling 设置为 true 时才适用。如果设置为 true,Windows 将从 DNS 请求中提取问题并尝试解决该问题,从而忽略未知记录。
initialAutoProxyTimeout* string 1000 仅当 wsl2.autoProxy 设置为 true 时才适用。配置启动 WSL 容器时,WSL 等待检索 HTTP 代理信息的时长(以毫秒为单位)。如果代理设置在此时间之后解析,则必须重启 WSL 实例才能使用检索到的代理设置。
ignoredPorts** string Null 仅当 wsl2.networkingMode 设置为 mirrored 时才适用。指定 Linux 应用程序可以绑定到哪些端口(即使该端口已在 Windows 中使用)。通过此设置,应用程序能够仅侦听 Linux 中的流量端口,因此即使该端口在 Windows 上用于其他用途,这些应用程序也不会被阻止。例如,WSL 将允许绑定到 Linux for Docker Desktop 中的端口 53,因为它只侦听来自 Linux 容器中的请求。应在逗号分隔列表中设置格式,例如:3000,9000,9090
hostAddressLoopback** bool false 仅当 wsl2.networkingMode 设置为 mirrored 时才适用。如果设置为 True,将会允许容器通过分配给主机的 IP 地址连接到主机,或允许主机通过此方式连接到容器。始终可以使用 127.0.0.1 环回地址,此选项也允许使用所有额外分配的本地 IP 地址。仅支持分配给主机的 IPv4 地址。

值类型后带有 * 的条目仅在 Windows 11 中可用。

值类型后显示 ** 的条目需要 Windows 版本 22H2 或更高版本。

我们可以自定义

1
2
3
4
5
6
7
8
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
firewall=true

[experimental]
autoMemoryReclaim=gradual  # gradual  | dropcache | disabled

移动子系统

我发现,子系统实际上安装到了C:\Users\<username>\AppData\Local\Packages\Canonical...\LocalState\ext4.vhdx,也就是说,保存在 C 盘,

参考博客:windows subsystem for linux - Where is WSL located on my computer? - Ask Ubuntu

到目前为止,WSL 没有提供自定义安装路径的配置。比较好的办法是装好子系统之后再移动子系统,也就是先通过在线安装安装好子系统,之后再导出成一个文件放到你想要的位置,然后再导入到 WSL 中。

另一个办法是手动去下发行版文件(tar 文件),放到目标目录,然后解压再安装,不过这样就缺失了很多功能。

操作步骤是:

首先,关闭所有子系统

1
wsl --shutdown

查看所有分发版本

1
wsl -l --all -v

导出分发版为 tar 文件到 G 盘

1
wsl --export Ubuntu-20.04 G:\WSL\ubuntu22.04.tar

注销当前分发版

1
wsl --unregister Ubuntu-20.04

重新导入并安装分发版在G:\WSL\ubuntu22.04

1
wsl --import Ubuntu-22.04 G:\WSL\ubuntu22.04 G:\WSL\ubuntu22.04.tar --version 2

此外,我还发现了一个工具LxRunOffline,但是对 WSL2 的支持好像很差,有 bug,例如:Issue with WSL2 Ubuntu 22 trying to use LxRunOffline - Microsoft Q&A,反正官方的指令又不长,就用官方指令算了。

自定义 wsl 安装位置以及多 wsl 共存 | 骏马金龙

子系统桌面

子系统可配置其使用桌面,比如可以装 GNOME 或者 KDE,我找过了,有教程,但是没有必要,就用 Windows 桌面来访问子系统算了,反正文件系统是互通的。

设置 wsl 开机自启

方法如下:

  1. WIN+R 运行 shell:startup 打开启动目录,其实就是C:\Users\<user_name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

  2. 在此目录中创建文件 wsl-start.vbs

  3. wsl-start.vbs 中填充如下内容,Ubuntu-22.0需替换为你使用的发行版名称。

    1
    2
    
    Set ws = CreateObject("Wscript.Shell")
    ws.run "wsl -d Ubuntu-22.04", vbhide
  4. 想要停止 WSL 开机自启,直接删除掉wsl-start.vbs即可。

wsl 开机自启之后,我们可以在 wsl 中设置一些开机自启的服务,这样就可以做到 Windows 启动的时候 wsl 中的一些服务也自启。

为了不让 wsl 的开机自启影响到 Windows 的性能,推荐设置一下 wsl 的内存占用,CPU 占用的限制就不必了,一般用不到

开发相关

Python

Ubuntu22.04 自带 python3.10。

装 Docker

在 Ubuntu 中安装 Docker,参考博客:Ubuntu - Docker — 从入门到实践

网络设置 - 重点

如果你进入子系统的时候看到这个错误,说明子系统的网络没有配置好。

1
检测到 localhost 代理配置,但未镜像到 WSL。NAT 模式下的 WSL 不支持 localhost 代理。

别人也遇到了同样的问题:Github Issue

这个问题和下面这个问题其实是一个问题:如何实现 WSL 使用宿主机的代理,比如 Clash?

参考博客:在 WSL2 中使用 Clash for Windows 代理连接 - East Monster 个人博客

在 WSL 2.0.5 版本后,一些特性得以稳定,比如镜像模式网络。启用镜像模式网络会将 WSL 更改为全新的网络体系结构,其目标是将 Windows 上的网络接口“镜像”到 Linux 中,以添加新的网络功能并提高兼容性。

以下是启用此模式的当前优势:

  • IPv6 支持
  • 使用 localhost 地址 127.0.0.1 从 Linux 内部连接到 Windows 服务器。不支持 IPv6 localhost 地址 ::1
  • 改进了 VPN 的网络兼容性
  • 多播支持
  • 直接从局域网 (LAN) 连接到 WSL

如何启用镜像模式网络?我们在配置子系统小节了解过如何配置 WSL,具体做法是在 C:\Users\<UserName>\.wslconfig 文件中 (如果不存在就手动创建一个) 加入以下内容:

1
2
[wsl2]
networkingMode=mirrored

经过这样设置之后,WSL 管理的子系统的 IP 跟主机一样了,也就是说,两个机器共用一套 IP 和端口,在子系统中部署的服务,在 Windows 中直接可以通过 localhost 来访问,比如我在 wsl 中部署了一个 nginx 服务,代理了 80 端口,那么在 Windows 下的浏览器中,直接输入localhost:80就能访问,再加上 WSL 管理的子系统和 Windows 的文件本来就是互通的,修改和调试 Linux 下的应用就更加简单了。

我宣布,Windows11 是最好的 Linux 管理软件

注意,这个时候,子系统中的服务,Windows 中想要访问只能通过 localhost 来访问,因此此时只是开启了 Hyper-V 的回环地址访问(WSL 基于 Hyper-V,localhost 基于回环地址),在其他机器上通过 Windows/子系统的具体 ip 访问子系统中的服务是访问不了的,必须在 wsl 的虚拟机的防火墙上开端口。也就是配置 WSL 虚拟机的入站规则。

配置 WSL 虚拟机的入站规则

官方文档:

使用 WSL 访问网络应用程序 | Microsoft Learn

Hyper-V 防火墙 - Windows Security | Microsoft Learn

首先,我们要知道 WSL 基于 Hyper-V,而 Hyper-V 的防火墙规则按 VMCreatorId 启用。若要获取 WSL 虚拟机的 VMCreatorId,则可以这样查询:

1
2
3
4
Get-NetFirewallHyperVVMCreator

VMCreatorId  : {40E0AC32-46A5-438A-A0B2-2B479E8F2E90}
FriendlyName : WSL

此时我们查看 WSL 虚拟机的配置,我们会发现入站是被阻断(Block)的,也就是说,通过 IP 从 WSL 虚拟机的外部,是无法 ping 通 WSL 虚拟机中的任何端口的

1
2
3
4
5
6
7
8
Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}'

Name                  : {40E0AC32-46A5-438A-A0B2-2B479E8F2E90}
Enabled               : True
DefaultInboundAction  : Block
DefaultOutboundAction : Allow
LoopbackEnabled       : True
AllowHostPolicyMerge  : True

我们可以开启这个入站规则,开启之后,虚拟机外部访问虚拟机内部的所有端口,都会放行。此命令需要以管理员权限运行终端

1
Set-NetFirewallHyperVVMSetting -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -DefaultInboundAction Allow

再次查看

1
2
3
4
5
6
7
8
Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}'

Name                  : {40E0AC32-46A5-438A-A0B2-2B479E8F2E90}
Enabled               : True
DefaultInboundAction  : Allow
DefaultOutboundAction : Allow
LoopbackEnabled       : True
AllowHostPolicyMerge  : True

那我们如何关闭 WSL 虚拟机入站的命令呢?

1
Set-NetFirewallHyperVVMSetting -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -DefaultInboundAction Block

此外,你也可以不开启所有端口,也可以只开启特定端口,方法是创建一个入站规则

1
New-NetFirewallHyperVRule -Name MyWebServer -DisplayName My Web Server -Direction Inbound -VMCreatorId {40E0AC32-46A5-438A-A0B2-2B479E8F2E90} -Protocol TCP -LocalPorts 80

然后通过以下命令查看手动添加的入站规则,

应该会有两个默认的PolicyStoreSourceType : Local的规则。

1
Get-NetFirewallHyperVRule -VMCreatorId '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}'

删除此特定的入站规则

1
Remove-NetFirewallHyperVRule -Name 'MyWebServer'

相关 API 页面:New-NetFirewallHyperVRule (NetSecurity) | Microsoft LearnRemove-NetFirewallHyperVRule (NetSecurity) | Microsoft Learn


0%