如何在WSL2上设置工作的X11转发

185

当从WSL1迁移到WSL2时,许多事情都会发生变化;显然,这也适用于X11转发。


我需要采取哪些步骤才能像在WSL1上一样在Windows 10上使用WSL2进行X11转发?


4
程序员常用的工具,需要一定的常识。众所周知,并非所有与 WSL2 相关的问题都适合在此讨论,本应永远不应该重新开放这个问题。我们有其他的网站可以讨论此类问题,例如 Super User 更加适合。甚至可能适合于 Ask Ubuntu(假设涉及发行版)或 Unix & Linux Stack。但是,这不是一个关于“特定编码、算法或语言问题”的问题。 - NotTheDr01ds
这个答案帮了我 - https://dev59.com/5lEG5IYBdhLWcg3wY8My - nycynik
1
我强烈建议非程序员甚至意识到WSL是罕见的。X11转发不是主题,但对于要转发的工具的资格(比如证书工具)是有资格的。说一个真正的程序员会依赖命令行是无稽之谈,但也承认这是一个VirtualBox场景是有效的。有解决方法。 - mckenzm
23个回答

241

简述:

将以下内容添加到您的~/.bashrc文件中:

export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1

为 Windows 上的 X11 服务器启用公共访问

为了允许 WSL 访问 X 服务器,您需要在 Windows 防火墙中添加一个单独的入站规则,用于TCP端口6000,如 wsl-windows-toolbar-launcher 人员所描述。


正如WSL_subreddit_mod 在 Reddit 上指出的,以及您可以在Microsoft关于WSL2的文档中阅读到的,WSL2架构使用虚拟化网络组件。这意味着WSL2具有与主机不同的IP地址。这解释了为什么不能简单地将WSL1的X11转发设置传递到WSL2。

在Ubuntu关于WSL的Wiki页面下,您已经可以找到适用于WSL2的配置,位于运行图形应用程序下。以上提到的Reddit用户也建议类似的配置,并提供解决方案的另一部分:为 Windows 上的 X11 服务器启用公共访问。

这意味着将以下内容添加到您的~/.bashrc中:

export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1

在 Windows 上启用 X11 服务器的公共访问* 是启用 WSL2 的 X11 转发的最重要的部分:Windows 防火墙默认阻止通过 WSL 配置的网络接口进行连接。
需要为 TCP 端口 6000 创建单独的 入站规则,以允许 WSL 访问 X 服务器。创建规则后,根据 wsl-windows-toolbar-launcher 的说明,在新创建的规则的设置下范围中将 IP 地址范围限制为 WSL 子网:172.16.0.0/12

*:如果您使用 VcXSrv,可以通过在 Extra Settings 中禁用访问控制来启用 X 服务器的公共访问:
Disable access control VcXSrv
或者通过调用带有 ac 标志的 vcxsrv.exe 直接启动:vcxsrv.exe -ac,如 ameeno 在 Github 问题上指出的。

另外,这个 SO 回答 显示了如何通过 .Xauthority 文件共享密钥,从而保留完整的访问控制。


5
我刚刚测试了你的解决方案。即使勾选了“禁用访问控制”标志,我还是需要允许通过Windows Defender公开访问(“允许应用程序通过Windows Defender防火墙进行通信”)。但是,我不需要添加额外的入站规则。 - stedes
5
为避免造成安全问题,应添加额外的入站规则以防止允许所有公共网络访问。 - whme
15
我进行了一些小修改,现在它可以工作了。首先,我使用[MobaXterm](https://mobaxterm.mobatek.net/)代替VcXSrv,因为从防火墙的角度来看似乎更可靠。其次,我使用以下导出的环境变量。一个关键区别是我不依赖于/ etc / resolv.conf。export DISPLAY = $(ip路由| awk '/ default via / {print $ 3; exit}'2> / dev / null):0 export LIBGL_ALWAYS_INDIRECT = 1 - Adam
5
我的/etc/resolv.conf文件包含多个nameserver条目,但没有一个是我的当前IP地址,这使得出现了问题。看起来有一些关于它是如何工作的假设。 - Thorbjørn Ravn Andersen
3
为了授权,您也可以在运行具有禁用授权控制(-ac)的 VcXsrv 时通过运行 xauth generate $DISPLAY . 在 WSL 中生成一个 ~/.Xauthority 文件。 然后执行 cp ~/.Xauthority /mnt/c/Users/<your login>/,下次启动 VcXsrv 时,使用 -auth C:\Users\<your login>\.Xauthority 参数代替 -ac - Arseny
显示剩余23条评论

62

对于像我一样只允许私有网络的某些人,尽管应该勾选两个复选框,

enter image description here

Windows Defender 防火墙上应该有停止标志。

enter image description here

双击它并允许私人和公共连接,

enter image description here

所以所有4个项目都应该被打上绿色勾选符号。

然后@NicolasBrauer的回答适用于我。

例如,在 XLaunch 时禁用访问控制

export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0
export LIBGL_ALWAYS_INDIRECT=1

1
对于那些对WSL的一般技巧感兴趣的人。 - Kennyhyun
1
被接受的答案中关于防火墙更改的链接显示了有关限制访问端口6000和IP范围172.16.0.0/12的更多详细信息(这很好),但它不针对特定程序(像这个答案一样)。对于MobaXterm,我的exe名称是xwin_mobax.exe。他们也没有真正解释如何导航到Windows Defender防火墙的正确位置。这些额外的图片帮助完成了这个难题。 - kevincasey
这是另一个可以切换VcXsrv防火墙设置的地方。在我的情况下,安全警报没有出现。 - M.W.
请记得在应用程序更新时更新该规则。 - pscheit
谢谢,防火墙拦截了连接。 - Cocuba

48

我想到了一个解决方案,使用Windows 10上的vxcsrv,正如其他人所指出的。它也适用于Windows 11。

XServer Windows - WSL1和WSL2:

安装X-Server Windows

https://sourceforge.net/projects/vcxsrv/

在 WSL 发行版中设置显示屏向前

配置显示屏:

  • 如果你正在运行 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

然后(安装x11-apps)

sudo apt update
sudo apt install x11-apps

在Windows上启动XLaunch

  • 多个窗口
  • 不启动客户端
  • 禁用本地OpenGL
  • 启用禁用访问控制

测试它

在wsl中:输入xcalc - 计算器应该在Windows10中打开

如果一切正常

并且您想将设置保留在您的wsl发行版中,请将它们存储在您的~/.bashrc中。

sudo nano ~/.bashrc

复制两行代码(从在WSL Distro中设置显示器 - 配置显示器)到末尾并保存。

将其添加到自动启动

  1. 运行对话框,查看Windows上的Start XLaunch
  2. 保存配置
  3. 按下Windows + R
  4. 输入:shell:startup
  5. 将保存的配置:*.launch(在步骤2中生成)复制到此文件夹(步骤4)

现在XServer将随Windows启动而启动。

我正在使用它来进行ROS开发。对我很有效。

我的XServer不可通过互联网访问,因此可以禁用访问控制。


1
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。仅有链接的答案如果链接页面更改可能会变得无效。 - Yoni
它不起作用。 - douyu
什么没有运作。你在Windows警告框中勾选了吗(就像这里描述的那样:https://dev59.com/dVIH5IYBdhLWcg3wH5X1#63174434)? - Kraego
1
“在Windows上启动XLaunch并进行访问控制”这部分帮助了我。 - PranshuKhandal
1
如果您遇到问题,请尝试关闭网络防火墙。此方法完美运作。 - Carlos
1
可以确认这在干净的 Windows 11 安装上运行,而无需安装 VcXsrv。在我的情况下,我缺少了 x11-apps 和环境变量。 - dev404

26

如何在WSL2中设置X11转发

本答案假设您已经有一个在Windows主机上运行的工作中的XServer和PulseAudio配置,因为您之前正在使用WSL1。(您也可能需要向命令行添加-ac参数,以便使您选择的XServer能够与WSL2一起工作。)

我采用的方法是,在我的~/.bashrc文件中添加以下内容,以确保我无论是使用静态IP地址还是DHCP在Windows主机上,甚至无论我的主机名或网络位置是否更改,都可以进行X11转发:

# 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

按照上述步骤操作后,不管我的主机名或主机IP地址是什么,在WSL2中每次启动BASH会话时,它都将被放置在环境变量中。通过从命令行运行firefox并观看YouTube视频来测试它。你应该能够听到声音并看到应用程序本身来观看视频。此外,通过从命令行启动其他GUI应用程序进行测试。

它的作用:使用host命令从输出中获取与主机名关联的IPv4地址,从中匹配包含Windows主机IPv4地址的行的地址,除IP地址之外去掉其余信息,然后将其awk并打印到变量中,输出被修整。然后,将其用作字符串以提供必要的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的路径,以及程序的完整路径,在Linux使用WSL2运行此类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转发正常工作。

输入图像描述


终于!这是唯一有效的解决方案,尝试了所有方法。只需复制/粘贴第一个命令块,就完成了!谢谢! - user2828781
不客气!很高兴它对你有用。虽然它会增加一两秒的处理时间,但为了一个工作配置,这是一个微不足道的代价,而且它不受IP地址的影响。 - D. Charles Pyle
我在wsl2中使用这个命令来编辑.bashrc文件,现在它可以正常工作。 - Prut Udomwattawee
谢谢!这是唯一有效的解决方案。 - Lee Hounshell
谢谢你,伙计!现在我的X服务器正常工作 :) - Gabriel Berlanda

26

使用/etc/resolv.conf命名服务器对我没有用,因为我在/etc/wsl.conf中禁用了resolv.conf生成(我有一个自定义的resolv.conf)。

最终您希望得到WSL2主机IP地址,这也应该是您的默认路由。这是我在我的Debian WSL2发行版中的~/.bashrc条目:

export DISPLAY=$(ip route | awk '/^default/{print $3; exit}'):0

1
ip route | wc -l 151 这个命令是干嘛用的? 换句话说,我们要找的路由是什么。 现在单一路由已经比较少见了... - U.V.
2
我爱你!救星 - Guillaume Perrault-Archambault

12

这个github issue中复制了我的答案。

关键是利用能够通过stdio通信的能力。

先决条件

  • 只要我们可以在Windows主机上使用socat,你就需要运行WSL1。我相信你可以在powershell中完成这个操作,但我没有时间去研究。也许有人可以在powershell中编写一个stdio->tcp重定向器,那么我们就不需要有2个WSL发行版了。

如何转发X服务器连接

  1. 在Windows上运行你喜欢的X服务器。默认情况下,它们会监听6000端口。
  2. 在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 Linux子系统中,后台运行以下命令(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"

性能

在我的电脑上,它可以处理高达150MB/s的数据,虽然不是最快的,但对于大多数应用程序来说速度足够快。


1
耶!这就是正确的方法。 我将它添加到我的startx脚本中: #!/bin/bash

如果未运行,则启动Xming X11

if /mnt/c/Windows/System32/tasklist.exe | grep -q Xming.exe; then echo 找到X服务器 else echo 没有找到X服务器 - 启动它 /mnt/c/Program\ Files\ (x86)/Xming/XLaunch.exe -run '\Users\user\Desktop\config.xlaunch' & # 同时启动X11管道 mkdir -p /tmp/.X11-unix/ socat UNIX-LISTEN:/tmp/.X11-unix/X0,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d Ubuntu-18.04 socat - TCP:localhost:6000" & echo 等一下 sleep 1 fi
- U.V.

7
对于那些可能使用仿真引擎,例如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,请取消勾选本地OpenGL。VcXSrv的最终配置将如下所示:

enter image description here

如果想要使用更简单的X11服务器,可以考虑 X410MobaXterm。关于这些配置的详细信息,请参考 此处此处


6

Windows 11Windows 10 22H2 (build 2311)及更高版本,包括WSLg。它可以轻松使用™。

推荐使用显卡驱动程序(Intel AMD Nvidia)

"系统信息"应用程序将告诉您当前的构建版本号。


注意:WSL1 与 WSLg 不兼容。新的 WSL2 实例将会“即插即用”™。
现有的 WSL2 系统需要进行“更新”:
  1. 在管理员 PowerShell 中执行:wsl --update
  2. wsl --shutdown 强制重启 WSL

不要忘记删除您可能已经进行的任何其他 DISPLAY 修改。

Proof that it works


https://dev59.com/pVIG5IYBdhLWcg3w_nXt#68416242 - PCM
1
它本来是可以正常工作的,但后来出现了故障... 现在我似乎无法让 XLaunch 与 WSLg 协同工作,当我需要进行实际工作时... :( 有什么办法可以让 XLaunch 与 WLSg 同时工作,或者如何禁用 WLSg,以便 XLaunch 可以像以前一样工作? - ColinM
可能是这个吗? - Cameron Tacklind
3
WSLg适用于Windows 10 22H2版本2311及更高版本。请安装所有Windows更新,它将作为WSL2的一部分提供。如果您的更新无法完全升级到2311版本,则可能需要安装KB5020030以获得允许安装WSL2版本的WSL2版本。 - Neill Robbins

3

您可以在不禁用服务器访问控制的情况下连接到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

对于Cygwin/X,我不需要生成cookie,而是使用k=$(/mnt/c/cygwin64/rootfs/bin/sh.exe -c '/bin/xauth -n list'|grep "^$DISPLAY")来获取现有的cookie。我将export DISPLAY=...行移到了那一行的上面。我还需要在Cygwin主目录中添加一个名为.xserverrc的文件,其中包含exec /usr/bin/XWin -listen tcp "$@",以便为Cygwin X服务器启用TCP访问(在Cygwin中使用echo 'exec /usr/bin/XWin -listen tcp "$@"' >> ~/.xserverrc)。 - T S
@TS,您能详细说明一下如何在WSL2中使用Cygwin/X吗?我已经成功使用VcXsrv了,但是我听说Cygwin/X可能可以解决我遇到的一些图形故障。不幸的是,我无法从WSL2终端启动任何GUI应用程序。 - user3534080
感谢您发布如何正确执行此操作的方法。 所有其他答案都相当危险,因为允许未经身份验证的连接的X服务器将允许不仅是恶作剧,而且还会使附加键记录器变得轻而易举 - 只需运行xinput list获取键盘ID,然后运行xinput test <n>查看所有键事件。 - andrewdotn

3

我不知道这是否只适用于我的配置,但是这些解决方案在我的电脑上不起作用。它们返回地址192.168.0.254,这是我的网关而不是我的主机。

为了使其工作,我在我的Ubuntu/WSL2上使用了以下方法:

export DISPLAY="`ip -4 address | grep -A1 eth0 | grep inet | cut -d' ' -f6 | cut -d/ -f1`:0"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接