从 WSL1 迁移到 WSL2 时,许多事情发生了变化;显然这也适用于 X11 转发。
为了在 Windows 10 上使用 X11 转发和 WSL2,我需要执行哪些步骤,就像我对 WSL1 所做的那样?
23 回答
TL;博士:
将以下内容添加到您的~/.bashrc
:
export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1
在您的 X11 服务器上为 Windows启用公共访问。*
如wsl-windows-toolbar-launcher人员所述,将TCP 端口 6000的单独入站规则添加到 Windows 防火墙,以允许 WSL 访问 X 服务器。
正如reddit 上的 WSL_subreddit_mod所指出的,并且您可以在Microsoft 的 WSL2 文档中阅读,WSL2 架构使用虚拟化网络组件。这意味着 WSL2 具有与主机不同的 IP 地址。这就解释了为什么不能简单地将 WSL1 的 X11 转发设置转移到 WSL2。
在有关 WSL 的 Ubuntu Wiki 页面上,您已经可以在Running Graphical Applications下找到适用于 WSL2 的配置。上面提到的 Reddit 用户也提出了类似的配置,他还贡献了解决方案的另一部分:在 Windows 下的 X11 服务器上启用公共访问。
这意味着将以下内容添加到您的~/.bashrc
:
export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1
并在您的 X11 服务器上为 Windows启用公共访问。*
在 Windows 10 上为 WSL2 启用 X11 转发的最重要部分仍然缺失:默认情况下,Windows 防火墙阻止通过为 WSL 配置的网络接口进行的连接。TCP 端口 6000
的单独入站规则需要允许 WSL 访问 X 服务器。在创建规则后,如wsl-windows-toolbar-launcher人员所述,IP 地址范围可以在新创建的规则的设置中限制为 WSL 子网,在Scope : 172.16.0.0/12下。
*:如果您使用VcXSrv,您可以通过禁用额外设置上的访问控制来为您的 X 服务器启用公共访问:
或者直接使用标志调用:正如ameeno在 github 问题上指出的那样。
vcxsrv.exe
ac
vcxsrv.exe -ac
或者,此 SO 答案显示了如何通过 .Xauthority 文件共享密钥,从而为您提供完整的访问控制。
使用/etc/resolv.conf
名称服务器对我不起作用,因为我禁用resolv.conf
了生成/etc/wsl.conf
(我有一个自定义resolv.conf
)。
最终,您需要 WSL2 主机 IP 地址,这也应该是您的默认路由。这是我~/.bashrc
的 Debian WSL2 发行版的条目:
export DISPLAY=$(ip route | awk '/^default/{print $3; exit}'):0
正如其他人指出的那样,我想出了一个在 Windows 10 上使用 vxcsrv 的解决方案。
XServer Windows - WSL1 和 WSL2:
安装 X 服务器 Windows
https://sourceforge.net/projects/vcxsrv/
在 WSL Distro 中设置向前显示
配置显示:
- 如果您运行WSL1:
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=localhost:0
- 如果您运行WSL2:
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0
- (如果您已禁用
resolv.conf
使用此定义:https ://stackoverflow.com/a/63092879/11473934 )
然后(安装 x11-apps):
sudo apt update
sudo apt install x11-apps
在 Windows 上启动 XLaunch
- 多个窗口
- 不启动客户端
- 禁用本机 opengl
- 启用禁用访问控制
测试一下
在 wsl 中:输入 xcalc - 计算器应在 Windows10 中打开
如果一切正常
并且您希望将设置保留在您的 wsl 发行版中。将它们存储在您的~/.bashrc
.
sudo nano ~/.bashrc
复制两行(从Set Display 在 WSL Distro - Configure Display 中向前),两行结束并保存。
将其添加到自动启动
- 运行对话框请参阅在 Windows 上启动 XLaunch
- 保存配置
- 按 Windows + R
- 输入:外壳:启动
- 将保存的配置:*.launch(在步骤 2 中生成)复制到此文件夹(步骤 4)
现在 XServer 将随 windows 启动一起启动。
我将它用于ROS。为我工作。
我的 XServer 无法通过 Internet 使用,因此可以禁用访问控制。
如何在 WSL2 中设置 X11 转发
此答案假定您已经在 Windows 主机上运行了有效的 XServer 和 PulseAudio 配置,因为您已经在使用 WSL1。(您可能还必须将 -ac 参数添加到命令行以使您选择的 XServer 与 WSL2 一起使用。)
我这样做的方式,并确保无论我在 Windows 主机上使用静态 IP 地址还是 DHCP,甚至我的主机名或网络位置是否更改,我都能获得 X11 转发,我将以下内容添加到我的 ~/ .bashrc 文件:
# Get the IP Address of the Windows 10 Host and use it in Environment.
HOST_IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r')
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=$HOST_IP:0.0
export NO_AT_BRIDGE=1
export PULSE_SERVER=tcp:$HOST_IP
做完以上之后,不管我的Hostname是什么Hostname或者Host的IP地址是什么,在WSL2中每次启动一个BASH session都会放到环境中。通过从命令行运行 firefox 来测试它并观看 YouTube 视频。您应该能够听到声音并看到应用程序本身来观看视频。此外,通过从命令行启动其他 GUI 应用程序进行测试。
它的作用:它使用 host 命令从输出中提取与主机名关联的 IPv4 地址,greps 匹配包含 Windows 主机 IPv4 地址的行的地址,去除除 IP 地址之外的其余信息,以及然后 awks 并将其打印到变量中,并修剪输出。然后,这用于提供必要的 IP 地址作为字符串,以在允许转发 X11 和声音输出的环境变量中使用。
如果其他方法对您不起作用(因为它们对我不起作用),希望它对您有用。
大多数 CLI 应用程序可以从 BASH 提示符或 Windows 终端运行。如果要创建快捷方式,大多数 CLI 应用程序都可以像以下示例中的任何一个一样设置(在这种情况下不需要 X11 转发,除了 Links2 之类的应用程序):
C:\Windows\System32\wsl.exe -e htop
C:\Windows\System32\wsl.exe lynx
如果您想为 Linux GUI 应用程序创建桌面快捷方式,除非您可以在启动程序之前从 ~/.bashrc 文件中获取要使用的环境变量,否则您必须使用以下模板创建快捷方式,并输入程序名称代替 {yourprogram}:
C:\Windows\System32\wsl.exe LIBGL_ALWAYS_INDIRECT=Yes IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r') DISPLAY=$IP:0.0 PULSE_SERVER=tcp:$IP {yourprogram}
您不必为许多程序放置完整的命令行。对于基于 PERL 的程序或基于 Python 的程序,有时您必须添加 PERL 和 PYTHON 的路径以及程序的完整路径,才能使用 WSL2 在 Linux 中运行此类 GUI 程序。对于我的一个 perl 程序,我必须这样做:
C:\Windows\System32\wsl.exe IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r') ; export LIBGL_ALWAYS_INDIRECT=Yes export DISPLAY=$IP:0.0 ; cd /mnt/c/Users/{yourusername}/Desktop ; /usr/bin/perl ~/wget-gui.pl
您可能需要进行一些试验才能使某些应用程序正常运行。例如,您可能需要 dbus-launch 一个应用程序,并且需要将该命令添加到程序名称之前的快捷方式中。
C:\Windows\System32\wsl.exe LIBGL_ALWAYS_INDIRECT=Yes IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r') DISPLAY=$IP:0.0 PULSE_SERVER=tcp:$IP dbus-launch --exit-with-session gedit
在某些情况下,您可能必须使用较短的变量名。有些应用程序根本无法正常运行,但随着时间的推移,这种情况正在改善。此外,不要尝试从 Windows 命令提示符或 PowerShell 运行上述命令。它将引发有关“grep”未被识别为内部或外部命令等的错误。
以下是在我的 Windows 10 系统上运行的几个 Linux GUI 应用程序的屏幕截图,在 WSL2 上运行 X11 转发。
从这个 github issue复制了我的答案。
这个想法是使用通过 stdio 进行通信的能力。
先决条件
- 为了让我们可以在 Windows 主机中使用 socat,您需要一个运行 WSL1 的发行版。我相信你可以在 powershell 中做到这一点,但我没有时间研究这个。也许有人可以在 powershell 中编写一个 stdio->tcp 重定向器,那么我们就不需要 2 个 WSL 发行版。
如何转发 X-server 连接
- 让您最喜欢的 X 服务器在 Windows 上运行。默认情况下,他们会监听 6000 端口。
- 在 WSL2 发行版中,在后台运行以下命令(
ubuntu
是安装了 socat 的 WSL1 发行版的名称):
mkdir -p /tmp/.X11-unix/
socat UNIX-LISTEN:/tmp/.X11-unix/X0,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d Ubuntu socat - TCP\:localhost\:6000"
基本上,这会建立一条从普通 X unix 域套接字到主机端口 6000 的隧道。
如何将任何 TCP 连接转发回主机
假设在 Windows 的 5555 端口上运行了一个 tcp 服务。在 WSL2 发行版中,在后台运行以下命令(ubuntu
是安装了 socat 的 WSL1 发行版的名称):
socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntu socat - TCP\:localhost\:5555"
如何将任何 TCP 连接从主机转发到 WSL2
这只是做同样的事情,但方向相反。您可以在 WSL1 发行版中运行以下命令:
socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntuwsl2 socat - TCP\:localhost\:5555"
表现
在我的 PC 上,它可以处理高达 150MB/s 的数据,因此它不是最快的,但对于大多数应用程序来说已经足够快了。
对于那些可能使用ROS/Gazebo 、 Unity等模拟引擎的人来说,需要另一种配置。
将这些添加到~/.bashrc
:
export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0
export LIBGL_ALWAYS_INDIRECT=0
请务必在 Windows 中为您的 X11 服务器启用公共 访问和私人访问。还要禁用 X11 服务器支持的任何访问控制。
如果您使用VcXSrv取消选中Native opengl。VcXSrv 的最终配置如下:
您可以在不禁用服务器访问控制的情况下连接到 X 服务器。您在服务器上使用 xauth 生成 cookie,然后在 Linux 端使用 xauth 将其加载到 Linux 中。您可以从 /etc/resolv.conf 获取服务器 IP。以下是在我的 .bashrc 中:
k=$('/mnt/c/Program Files/VcXsrv/xauth.exe' -f 'C:\Users\xxx\Documents\scratch.xauth' -i -n -q 2>/dev/null <<EOF
generate localhost:0 . trusted timeout 604800
list
quit
EOF
)
if [ -n "$k" ]
then
export DISPLAY=$(sed '/^nameserver/ {s/^nameserver\s\s*\([0-9][0-9.]*\)[^0-9.]*$/\1/;p;};d' /etc/resolv.conf):0
xauth -q add $DISPLAY . ${k##* }
export LIBGL_ALWAYS_INDIRECT=true
fi
unset k
我不知道这是否特定于我的配置,但这些解决方案不适用于我的计算机。他们返回地址 192.168.0.254,这是我的网关,而不是我的主机。
为了使它工作,我必须在我的 Ubuntu/WSL2 上使用以下内容:
export DISPLAY="`ip -4 address | grep -A1 eth0 | grep inet | cut -d' ' -f6 | cut -d/ -f1`:0"
我不想搞乱对 X 服务器和 Windows 防火墙的公共访问。我的解决方案是使用带有 X 转发的 ssh(也适用于 VirtualBox)。此外,WSL 会自动从主机转发到访客侦听套接字,因此我不关心实际分配给访客的 IP。
所以步骤如下:
- 安装 VcXSrv。使用所有默认值运行它,但将 Display number 设置为 0(如果没有 X 实例正在运行,-1 将选择 0)。不要在其中启动任何客户端(这样做的好处是您可以在同一个 X 服务器实例上启动更多应用程序)。
- 打开 WSL 并配置 ssh 服务器。对我来说,这很简单
sudo service ssh start
。使用命令行创建 Windows 快捷方式:wsl sudo service ssh start
. - 为 Windows 安装 Git。我实际上使用它只是因为它的 ssh 版本能够以
ssh -f
. Windows 版本的 ssh 在此功能上存在缺陷,否则无需进入后台或使用ssh -n
. - 配置从 Git-Bash 到访客的无密码登录。
ssh user@127.0.0.1
此时应该可以工作,因为主机端口被转发给来宾。 - 从 Git-Bash 验证 X 转发工作:
DISPLAY=127.0.0.1:0 ssh -Y user@127.0.0.1 xeyes
. 我认为每个 X 发行版都安装了 xeyes。 - 在 WSL 中安装您选择的文件管理器或终端。例如,pcmanfm。创建 Windows 快捷方式:
"C:\Program Files\Git\git-bash.exe" -c "DISPLAY=127.0.0.1:0 ssh -Y -f user@127.0.0.1 'bash -l -c pcmanfm >/dev/null 2>&1'"
. 这里bash -l
的标志有助于设置环境,这取决于您运行的应用程序可能重要也可能不重要。
当然,我可以在没有 git-bash 的情况下使用 VcXSrv 内置的 ssh 客户端来做同样的事情,但它需要将 ssh 密钥转换为 PuTTY 格式,并且我已经安装了 git-bash。此外,内置客户端显示重用对我不起作用。
https://github.com/microsoft/WSL/issues/4793#issuecomment-588321333的解决方案使用 VcXsrv 作为 X 服务器,这就是我得到这个答案的地方(为了便于阅读,稍微编辑了)。请注意,原件正在由其作者更新,所以不要忘记重新检查。
为了使它工作:
- 在 Windows 上,使用以下内容,更改
E:\VcXsrv
您的安装位置,并将其保存为 xxx.bat 在您的 Windows 启动文件夹中,例如,C:\Users\Me\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
如果您愿意,您可以让它在启动时运行:@ECHO OFF REM Start WSL once to create WSL network interface wsl exit REM Find IP for WSL network interface SET WSL_IF_IP= CALL :GetIp "vEthernet (WSL)" WSL_IF_IP ECHO WSL_IF_IP=%WSL_IF_IP% setx "WSL_IF_IP" "%WSL_IF_IP%" setx "WSLENV" "WSL_IF_IP/u" REM Change E:\VcXsrv to your VcXsrv installation folder START /D "E:\VcXsrv" /B vcxsrv.exe -multiwindow -clipboard -nowgl -ac -displayfd 720 GOTO :EOF :GetIp ( aInterface , aIp ) ( SETLOCAL EnableExtensions EnableDelayedExpansion FOR /f "tokens=3 delims=: " %%i IN ('netsh interface ip show address "%~1" ^| findstr IP') DO ( SET RET=%%i ) ) ( ENDLOCAL SET "%~2=%RET%" EXIT /B )
- 在 WSL 中,编辑 ~/.bashrc 文件以添加以下行:
export DISPLAY=$WSL_IF_IP:0 unset LIBGL_ALWAYS_INDIRECT
这就是让 WSL2 自动工作的全部内容。这个想法是在Windows上获取WSL接口的私有LAN IP,并使用环境变量将其传递给WSL。WSL 然后将此 LAN IP 更新为 DISPLAY 以用于 X-Server 连接。
使用此设置,剪贴板也可以正常工作。我使用 Ubuntu 20.04 LTS 的 WSL2 安装对此进行了测试。
2021答案
自 2021 年 4 月 27 日起, Windows 11和Windows 10的Insider版本包括WSLg。它只是工作™。
注意:目前,所有支持WSLg的 Windows 版本都是Insider版本,通常不建议日常使用。但是,“WSLg 将与即将发布的 Windows 一起普遍可用”。
来自https://github.com/microsoft/wslg(原公告)。
先决条件:
“系统信息”应用程序将告诉您当前的内部版本号。
WSL1 与 WSLg 不兼容。新的 WSL2 实例将正常工作™。
现有的 WSL2 系统需要“更新”:
- 在管理 PowerShell 中:
wsl --update
wsl --shutdown
强制重启 WSL
不要忘记删除DISPLAY
您可能所做的任何其他修改。
虽然官方公告称Windows 10的某些Insider版本支持WSLg,并且在Windows 10上进行了演示,但目前似乎没有任何公开可用的Windows 10的Insider版本支持WSLg。
我使用以下 bash 来设置显示:
export DISPLAY=$(powershell.exe -c ipconfig | grep -A4 WSL | tail -1 | awk '{ print $NF }' | tr -d '\r'):0
我宁愿在来宾中设置一个 ssh 服务器,在主机上安装一个像 Xming 这样的 X11 服务器,并通过带有 X11 转发的 putty 连接到 localhost。无需摆弄防火墙规则,不需要主机 IP。
Windows 10 的 2021 年答案
如果从 resolv.conf 获取 IP 不起作用,请检查此答案。
在 WSL2 中使用以下命令查找您的 Windows IP 地址(是的,linux 中的 .exe 文件):
ipconfig.exe
使用以下命令设置显示(使用您的 IP 填写 YOUR_IP_ADDRESS):
export DISPLAY=YOUR_IP_ADDRESS:0
检查您的 GUI 应用程序是否正常工作。
对于每种情况,自动化可能略有不同,但我将举个例子:
ipconfig.exe | grep 'IPv4 Address' | grep '10\.' | cut -d ":" -f 2 | cut -d " " -f 2
说明:我找到了所有 IPv4 地址(在我的情况下为 3 个 IP)。我知道我的 IP 仅从“10”开始。所以我使用第二个 grep 选择了这条线。接下来,我处理了整行以仅获取 IP。
我不知道为什么,但以上答案都不适合我。我在带有 AMD 和 Nvidia 显卡的 ROG Zephyrus 上运行,我确信这会导致问题。
whme 描述的防火墙设置很重要,但是 linux 环境变量对我不起作用。我在配置文件中有几个标记为名称服务器的条目,其中没有一个允许连接。
我最终将它们设置为:
export DISPLAY=$HOSTNAME:0.0
export LIBGL_ALWAYS_INDIRECT=
我使用 VcXsrv 作为 X 服务器。我还必须将参数设置为-nowgl
我在从 WSL 打开 X11 GUI 时也遇到了困难。
我在检测正确的 IP 时遇到问题,有时 X11 服务器会采用奇怪的偏移量,有时会在 0-17 上随机出现。
我编写了以下脚本来自动化这个问题,但它几乎没有依赖关系:
- 这是在 CentOS7 镜像下测试和运行的
- 在你的 linux 发行版上安装 X11-apps 以获得`xset
- 安装“超时”应用
- 通过 执行脚本
source ./find_display_ip.sh
。注意来源!您将希望在运行的 shell 上有 DISPLAY 环境变量。 - 仅通过“Windows 终端”或在 WSL 外壳中包含 Windows“PATH”的东西运行脚本。例如,在 Windows 提示符 `cmd 中,这并不是我的默认设置。
- 显然要确保您的 X11 服务器具有完全访问权限(“xhost +”或“X11 远程访问”已满)
不用多说,这是脚本源代码:
#!/bin/bash
start_index=$1
start=${start_index:-0}
# check current settings
declare -i stop=0
if [ ! -z "$DISPLAY" ]; then
timeout 1s xset -display $DISPLAY q &> /dev/null;
[[ "$?" -eq 0 ]] && echo "Already Set to $DISPLAY" && stop=1;
fi
# scan displays 0-17
for port in $(seq $start 17);
do
[[ 1 -eq $stop ]] && break;
grp="ipconfig.exe | grep IPv4 | tr -d '\015' | sed 's#.*: \(.*\)\$#\1:${port}.0#;'"
for ipd in $(eval $grp)
do
echo Trying $ipd;
timeout 1s xset -display $ipd q &> /dev/null;
# command was sucessful
[[ "$?" -eq 0 ]] && export DISPLAY=$ipd && echo $ipd was set && stop=1;
##echo "Trying next IP...";
done
done
这是我写的两篇文章,介绍了为不同类型的用例设置 x11:
- 在 WSL2 中安装具有图形用户界面的程序:本文介绍了安装 vcxsrv、将环境变量添加到 bashrc 配置文件以及以编程方式安排 vcxsrv 在启动时使用命令行参数启动。它还包括在 WSL2 中作为独立程序安装和启动 Firefox。
- 在 WSL2 中安装带有图形用户界面的 Ubuntu 桌面本文介绍如何安装 vcxsrv、dotNet、genie 和 Ubuntu 桌面。它包括创建导出环境变量的脚本、启动 vcxsrv、启动 gnome 桌面环境以及创建将它们联系在一起的快捷方式。它还包括运行 Ubuntu 桌面、防止屏幕锁定错误和安装 Snap Store。
我的错误是当我的 xserver 在 Windows 上运行时,我使用了我的 linux wsl2 实例的名称服务器。所以 DISPLAY 变量必须设置为我的 windows ipv4 地址。
只需输入ipconfig
powershell 或 cmd 并使用ipv4 ethernet address
.
通过使用 Windows 主机的 LAN 适配器 IP,我已经成功地使用了开箱即用的 VcXsrv 防火墙配置(即,无需覆盖/禁用任何防火墙规则)。将以下内容添加到我的~/.bash_aliases
export DISPLAY=$(pwsh.exe -c ipconfig | grep -A 3 lan | grep IPv4 | head -1 | awk '{ print $NF }'):0
lan
我的特定于连接的 DNS 后缀在哪里(您的可能不同,在这种情况下,您应该在上面的命令行中替换它)。
我找到了一个对我有用的解决方案,如下:在 WSL2 上设置图形
1. Start ssh service
1.1. Open WSL
1.2. Type: sudo service ssh start
2. Get Windows (WSL net) IP
2.1. Open Powershell
2.2. Type: (ipconfig | Select-String -Pattern 'WSL' -Context 1, 5).Context.PostContext | Select-String -Pattern 'IPv4'
2.3. Get the received IP
3. Set environment variable
3.1. In WSL2 terminal type: export DISPLAY=172.23.64.1:0.0 with the IP of the windows entity (2.3) instead of the place holder
4. Launch Xming
4.1. Open Xlaunch and go with the defaults In Specify parameter settings: Check No Access Control
5. Good luck!
以下链接: https ://docs.google.com/document/d/1ao3vjbC3lCDc9kvybOT5PbuGhC4_k4g8LCjxX23VX7E
我发现有一个来自 Ubuntu 的官方文档,它很全面,供您参考。正如我们所知,这个技巧也适用于 Debian/WSL2。 https://wiki.ubuntu.com/WSL
感谢Kennyhyun和其他人的分享。所有这些都是在我的计算机上以某种方式或某种方式在 Windows10 上托管的 WSL2 上启用 X11 服务器。由于 WSL2 作为 VM 不再是与 WSL1 相同的基础架构。我确实花了一些时间来完成它。
请让我简单地添加一些关于如何在 WSL2 上显示应用程序的内容。
在 WLS2 终端上运行“ip route”。
ip route default via abc1 dev eth0 abc0/20 dev eth0 proto kernel scope link src xxxx
将此“dev eth0”的IP地址添加到“export $DISPLAY=”中
导出 $DISPLAY=abc1:0.0
运行 xming 服务器。然后您可以运行在 WSL2 Linux 上运行的 APP。但对于 X11,您可能需要遵循 Ubuntu 的文档。
以下解决方法对我有用:
Set-NetFirewallProfile -Name $(Get-NetConnectionProfile).NetworkCategory -DisabledInterfaceAliases $(Get-NetAdapter | Where-Object Name -like 'WSL').Name