WSL2设置桥接网络及高级设置

本文最后更新于:2023年11月19日 晚上

wsl2默认的网络模式是NAT模式,不方便和外部主机的互相访问,尤其是当Windows上的容器服务需要暴露给外部主机访问时,因此需要修改网络模式。

WSL 网络设置

首先分析一下默认wsl2与宿主机的网络关系,wsl2 可以理解为宿主机虚拟出来的一个完整的 Linux 虚拟机,拥有逻辑上独立的网卡。

image-20231118214831403

上图可以看到wsl2与外界通信需要通过宿主机进行转发,宿主机和wsl2之间存在有一个虚拟局域网,虚拟网卡WSL和虚拟网卡eth0之间由于在同一个网段,所以能够互相通信。wsl2需要访问外部网络时,需要先发往宿主机的虚拟网卡,然后由宿主机的物理网卡将请求转发出去。

image-20231118220021111

如果wsl2上存在某个服务,暴露8989端口对外部提供服务。由于wsl没有外网ip,且wsl2的ip是经由宿主机使用网络地址转换技术(NAT)才得以访问局域网的,这隐藏了wsl2,保证了虚拟局域网的安全性,同时也使得局域网其它主机无法直接访问wsl2上的服务。

当前有3种方式可以实现wsl2和局域网内主机的互通,端口转发桥接网络 或者 镜像网络

端口转发

注意:此方法在 Windows 10 21H2验证没问题。

以wsl2内启动容器httpd为例,该容器对外映射端口80->8989。

1
2
CONTAINER ID  IMAGE                           COMMAND           CREATED      STATUS        PORTS                 NAMES
9e4fa9f3de9d docker.io/library/httpd:latest httpd-foreground 3 hours ago Up 9 seconds 0.0.0.0:8989->80/tcp httpd-test

此时,在wsl2内查看端口使用情况:

1
2
# netstat -ano | grep 8989
tcp 0 0 0.0.0.0:8989 0.0.0.0:* LISTEN off (0.00/0/0)

在cmd命令行中查看端口使用情况:

1
2
>netstat -ano | findstr 8989
TCP 127.0.0.1:8989 0.0.0.0:0 LISTENING 18208

可以看到在宿主机,该端口只是监听在127.0.0.1上,因此并不能对外提供访问,即局域网内其它主机无法访问该服务。

解决方法:

设置主机端口8989映射到wsl2的8989端口

  1. 获取wsl2的ip地址,wsl进入,然后通过命令 ifconfig 查看,eth0网卡ip地址为172.17.45.152

    image-20231119222116623

  2. 以管理员身份运行powershell,执行下面的命令设置端口映射

    1
    2
    # 添加端口转发规则
    netsh interface portproxy add v4tov4 listenport=8989 listenaddress=0.0.0.0 connectport=8989 connectaddress=172.17.45.152

    执行完就设置好监听win上所有ip地址和8989端口,并转发到172.17.45.152的8989端口了。

    拓展命令:

    1
    2
    3
    4
    5
    6
    7
    8
    # 删除端口转发规则
    netsh interface portproxy delete v4tov4 listenport=8989 listenaddress=0.0.0.0

    # 重置所有端口代理(清空规则)
    netsh interface portproxy reset

    # 查看所有端口转发规则
    netsh interface portproxy show all

    image-20231119223231430

打开Windows防火墙

配置好端口映射后,还需要打开windows防火墙,允许端口访问才行。

1、按下win + s打开Windows搜索,输入“防火墙”。打开后选择“高级设置”。

image-20231119224111939

2、入栈规则 -> 新建规则 -> 端口 -> 下一页

image-20231119224255812

3、TCP 特定本地端口, 输入8989,即想要开放的端口

image-20231119224541723

4、允许连接

image-20231119224659303

5、指定可用域

image-20231119224907457

6、添加描述(自己定义)

image-20231119225019058

7、查看属性,验证配置信息

image-20231119225216269

至此,端口转发配置完成。重新启动容器,局域网内其它主机即可访问该端口上的服务。

再次通过cmd命令行中查看端口使用情况:

1
2
>netstat -ano | findstr 8989
TCP 0.0.0.0:8989 0.0.0.0:0 LISTENING 6148

可以看到在宿主机,该端口监听在0.0.0.0上,可以对外提供访问,即局域网内其它主机可以访问该服务。

桥接网络

注意:此方法需要至少 Windows 11 22H2。

image-20231119013309804

桥接模式就是将主机网卡与虚拟机虚拟的网卡利用虚拟网桥进行通信。 在桥接的作用下,类似于把宿主机虚拟为一个交换机,所有桥接设置的虚拟机连接到这个交换机的一个接口上,宿主机也同样插在这个交换机当中,所以所有桥接下的网卡与网卡都是交换模式的,相互可以访问而不干扰。这种方式下,wsl2会获得一个和主机同网段的ip地址。

1. 更新WSL到最新的版本

首先需要从 Microsoft Store 里面下载最新的 Windows Subsystem for Linux。

用不了商店的可以前往这里自己下载部署安装:https://github.com/microsoft/WSL/releases ,装好之后可以运行 wsl --version 查看版本信息。

1
2
3
4
5
6
7
WSL 版本: 2.0.9.0
内核版本: 5.15.133.1-1
WSLg 版本: 1.0.59
MSRDC 版本: 1.2.4677
Direct3D 版本: 1.611.1-81528511
DXCore 版本: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows 版本: 10.0.22621.819

2. 使用 Hyper-V 创建和配置虚拟交换机

2.1 启用Hyper-V

启用 Hyper-V 以在 Windows 10 上创建虚拟机。参考:在 Windows 10 上安装 Hyper-V

  • 使用 PowerShell 启用 Hyper-V

    以管理员身份打开 PowerShell 控制台,执行命令:Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

  • 通过“设置”启用 Hyper-V 角色

    按下win + s打开Windows搜索,输入“Windows 功能”。

    image-20231118230320773

    选择“Hyper-V”,然后单击“确定”。

    image-20231118230511128

安装完成后,系统会提示你重新启动计算机。

2.2 添加虚拟交换机

介绍如何使用 Hyper-V Manager 或 PowerShell 创建和配置虚拟交换机(选择其中一种方式即可)。

2.2.1 使用 Hyper-V Manager 创建和配置虚拟交换机

在Windows搜索栏内输入”hyper-v”,出现Hyper-V管理器,点击即可打开Hyper-V管理器程序。

Hyper-V管理器的网络模式默认为NAT,如果想使用桥接模式,需要添加一个外部网络的虚拟交换机。点击“虚拟交换机管理器”。

image-20231118231028505

弹出虚拟交换机管理器窗口,点击“新建虚拟网络交换机”,然后在右侧选中“外部”,再点击“创建虚拟交换(S)”。

image-20231118231343235

在弹出的窗口中,填入虚拟交换机的名称,如WSLSwitch,连接类型栏确保选中的是“外部网络(E)”,如果主机配置了多块物理网卡,点击下拉箭头,可选择虚拟机交换机绑定(桥接)的物理网卡。

image-20231119011624880

点击“确定(O)”,提示应该网络更改可能导致网络连接中断,点击“是(Y)”即可。

看到虚拟机交换机一栏中,已经出现刚才添加的WSLSwitch交换机了,点击确定完成设置。

2.2.2 使用 PowerShell 创建和配置虚拟交换机

使用 New-VMSwitch 命令创建虚拟交换机。

  1. 在提升的会话中在计算机上运行 PowerShell。

  2. 执行以下命令查找现有网络适配器。 标识要用于虚拟交换机的网络适配器名称。

    1
    Get-NetAdapter
  3. 执行以下命令创建外部虚拟交换机,将 <value> 占位符替换为你自己的值。并设置允许虚拟交换机与管理操作系统共享。

    1
    2
    3
    4
    New-VMSwitch -Name <switch-name>  -NetAdapterName <netadapter-name> -AllowManagementOS $true

    # 示例
    New-VMSwitch -Name WSLSwitch -NetAdapterName WLAN -AllowManagementOS $true

3. 创建.wslconfig配置文件

win+R快捷键输入%USERPROFILE%打开默认用户目录,在此目录下创建.wslconfig配置文件。文件内容如下:

1
2
3
4
[wsl2]
networkingMode=bridged # 桥接模式
vmSwitch=WSLSwitch # 你所创建的虚拟交换机名
ipv6=true # 启用 IPv6

wsl --shutdownwsl 重启 WSL2。

镜像网络

注意:使用这种方式至少 Windows 11 23H2。需要加入 Windows Insider 预览版计划,而且可能还需要Canary`渠道,可能存在系统不稳定的情况。

这种配置方式我也没试验过,网络拓扑类似下面这样?

image-20231119014622828

参考WSL2 今天史诗级更新 - V2EX,如下设置.wslconfig文件:

1
2
3
4
5
[experimental]
networkingMode=mirrored
dnsTunneling=true
firewall=true
autoProxy=true

这样wsl2 和 Windows 主机的网络互通而且 IP 地址相同了,还支持 IPv6 了,并且从外部(比如局域网)可以同时访问 WSL2 和 Windows 的网络。这波升级彻底带回以前 WSL1 那时候的无缝网络体验了,并且 Windows 防火墙也能过滤 WSL 里的包了,再也不需要什么桥接网卡、端口转发之类的操作了。

WSL 中的高级设置配置

详细配置参考:WSL 中的高级设置配置

为已安装的 Linux 发行版配置设置,使它们在每次启动 WSL 时自动应用,有两种方法:

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

这两种文件类型都用于配置 WSL 设置,但存储文件的位置、配置的范围以及运行发行版的 WSL 版本都会影响应选择的文件类型。

这里再介绍几个实用的配置项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[wsl2]
networkingMode=bridged # 桥接模式
vmSwitch=WSLSwitch # 虚拟交换机名
ipv6=true # 启用 IPv6

# 限制 WSL2 虚拟机使用的内存不超过 8GB。可以使用 GB 或 MB 来设置整数值。
memory=8GB

# 设置 WSL2 虚拟机使用的虚拟处理器数量为4
processors=4

# 设置交换空间的大小为 8GB,默认为可用内存的 25%。
swap=8GB

# 指定交换文件的路径。默认路径为 %USERPROFILE%\AppData\Local\Temp\swap.vhdx。
swapfile=C:\\temp\\wsl-swap.vhdx

WSL(ext4.vhdx)磁盘空间回收

问题描述:
Docker Desktop for Windows v2 使用 WSL2,将所有映像和容器文件存储在单独的虚拟卷 (vhdx) 中。当需要更多空间(达到一定限度)时,这个虚拟硬盘文件会自动增长。
不幸的是,如果您回收一些空间,即通过删除未使用的图像,vhdx 不会自动缩小。

处理方法:
暂时没有好的处理方法,得手动执行命令。

ext4.vhdx的完整路径获取方法:
见:https://learn.microsoft.com/zh-cn/windows/wsl/disk-space?source=recommendations#how-to-locate-the-vhdx-file-and-disk-path-for-your-linux-distribution

1
(Get-ChildItem -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | Where-Object { $_.GetValue("DistributionName") -eq 'Ubuntu-20.04' }).GetValue("BasePath") + "\ext4.vhdx"

执行命令前注意先停止Docker Desktop和WSL2
windows专业版执行命令:

1
2
wsl --shutdown
optimize-vhd -Path C:\…\…\ext4.vhdx -Mode full

windows家庭版执行命令:

1
2
3
4
5
6
7
8
wsl --shutdown
diskpart
# open window Diskpart
select vdisk file="C:\…\…\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit

WSL 存储位置迁移

wsl镜像导出导入命令参考:https://learn.microsoft.com/zh-cn/windows/wsl/enterprise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 关闭wsl
wsl --shutdown
# 确保为stop状态
wsl -l -v
# 文件夹需提前创建
wsl --export Ubuntu-20.04 E:\UbuntuWSL\ubuntu.tar
# 注销
wsl --unregister Ubuntu-20.04
# 确定已注销
wsl -l -v
# 执行导入(如果失败可再次尝试执行)
# 执行完会在E:\UbuntuWSL\创建ext4.vhdx,然后ubuntu.tar就可以删掉了
wsl --import Ubuntu-20.04 E:\UbuntuWSL\ E:\UbuntuWSL\ubuntu.tar
wsl -l -v

Windows-docker存储位置迁移

windows-docker是基于wsl2的,参考:https://docs.docker.com/desktop/wsl/

docker使用的磁盘目录无法通过data-root来指定,而是在名为docker-desktop-data的wsl上。
其ext4.vhdx具体位置可通过以下命令获取:

1
(Get-ChildItem -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | Where-Object { $_.GetValue("DistributionName") -eq 'docker-desktop-data' }).GetValue("BasePath") + "\ext4.vhdx"

所以其目录迁移和普通的wsl迁移一致,执行下面命令之前,先关闭windows-docker。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 关闭wsl
wsl --shutdown
# 确保为stop状态
wsl -l -v
# 文件夹需提前创建
wsl --export docker-desktop-data E:\dockerData\docker-desktop-data.tar
# 注销
wsl --unregister docker-desktop-data
# 确定已注销
wsl -l -v
# 执行导入(如果失败可再次尝试执行)
wsl --import docker-desktop-data E:\dockerData\ E:\dockerData\docker-desktop-data.tar
wsl -l -v

# 再次查看位置,确认修改成功
(Get-ChildItem -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | Where-Object { $_.GetValue("DistributionName") -eq 'docker-desktop-data' }).GetValue("BasePath") + "\ext4.vhdx"

再次启动windows-docker。

参考:

  1. WSL2 网络异常排查 @笔记助手
  2. Windows开启端口转发功能 @LLLibra146
  3. 从局域网访问wsl2内的网络程序 @程序扫地僧
  4. 如何在局域网的其他主机上中访问本机的WSL2 @Kingdo
  5. wsl2设置桥接网络或镜像网络,解决服务互通访问的问题 @萌萌哒赫萝
  6. WSL2 网络的最终解决方案 @hez2010
  7. WSL2 静态IP(固定IP)不需要自动化脚本的设置方案 @知乎用户YvidLB
  8. 在 Windows 10 上安装 Hyper-V @Microsoft
  9. 使用 Hyper-V 创建和配置虚拟交换机 @Microsoft
  10. Hyper-V创建虚拟网路交换机桥接到路由器 @613a001f5e87
  11. WSL2 今天史诗级更新 @hez2010
  12. Windows Subsystem for Linux September 2023 update @Craig Loewen
  13. WSL 中的高级设置配置 @Microsoft
  14. Netsh interface portproxy 命令 @Microsoft
  15. WSL开发系列-基础篇 @且炼时光