How to set up working X11 forwarding on WSL2

170,785

Solution 1

TL;DR:

Add the following to your ~/.bashrc:

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

Enable Public Access on your X11 server for Windows.*

Add a separate inbound rule for TCP port 6000 to the windows firewall in order to allow WSL access to the X server, as described by the wsl-windows-toolbar-launcher people.


As pointed out by WSL_subreddit_mod on reddit and as you can read in Microsoft's documentation on WSL2, the WSL2 architecture uses virtualized network components. This means that WSL2 has a different IP address than the host machine. This explains why the X11 forwarding settings of WSL1 cannot simply be transferred to WSL2.

On the Ubuntu Wiki page about WSL you can already find a configuration adapted for WSL2 under Running Graphical Applications. A similar configuration is also suggested by the above mentioned Reddit User, who also contributes another part of the solution: Enable Public Access on the X11 server under Windows.

This means add the following to your ~/.bashrc:

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

And Enable Public Access on your X11 server for Windows.*

The most important part to enable X11 forwarding for WSL2 on Windows 10 is still missing: the Windows firewall blocks connections via the network interface configured for WSL by default.
A separate inbound rule for TCP port 6000 is required to allow WSL access to the X server. After the rule has been created, as described by the wsl-windows-toolbar-launcher people, the IP address range can be restricted to the WSL subnet in the settings of the newly created rule, under Scope: 172.16.0.0/12.

*: If you use VcXSrv you can enable public access for your X server by disabling Access Control on the Extra Settings:
Disable access control VcXSrv
Or by calling vcxsrv.exe directly with the ac flag: vcxsrv.exe -ac as pointed out by ameeno on the github issue.

Alternatively this SO answer shows how to share keys via .Xauthority files, leaving you with intact access control.

Solution 2

For some people who allowed only for private networks like me,

although they Should have been Both Ticked

enter image description here

It should have stop signs on Windows Defender firewall

enter image description here

Double click it and allow the connection for both private and public,

enter image description here

So all the 4 items should be ticked green.

Then the above answer from @NicolasBrauer was working for me.

Like disabling the access control when you XLaunch and

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

Solution 3

Using /etc/resolv.conf nameserver won't work for me since I disabled resolv.conf generation in /etc/wsl.conf (I have a custom resolv.conf).

Ultimately you want the WSL2 host IP address, which should also be your default route. Here's my ~/.bashrc entry for my Debian WSL2 distro:

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

Solution 4

I come up with a solution using vxcsrv on windows 10, as others pointed out.

XServer Windows - WSL1 & WSL2:

Install X-Server Windows

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

Set Display forward in WSL Distro

Configure Display:

  • If you running WSL1:
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=localhost:0
  • If you running WSL2:
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0

and then (install x11-apps):

sudo apt update
sudo apt install x11-apps

Start XLaunch on Windows

  • Multiple Windows
  • Start no client
  • disable Native opengl
  • enable Disable access control

Test it

In wsl: enter xcalc - Calculator should open in Windows10

If everything worked

And you want to persist the settings in your wsl distro. Store them in your ~/.bashrc.

sudo nano ~/.bashrc

Copy the two lines (from Set Display forward in WSL Distro - Configure Display), two the end and save it.

Add it to autostart

  1. Run Dialog see Start XLaunch on Windows
  2. Save configuration
  3. Press Windows + R
  4. Enter: shell:startup
  5. Copy saved configuration: *.launch (Generated in step 2) to this folder (step 4)

Now the XServer will be started with windows startup.

I’m using it for ROS. Works for me.

My XServer isn’t available over internet so its okay to disable access control.

Solution 5

How to Setup X11 forwarding in WSL2

This answer assumes that you already have a working XServer and PulseAudio configuration running on your Windows host because you already were using WSL1. (You also may have to add the -ac parameter to the command line to get your XServer of choice to work with WSL2.)

The way that I do this, and to ensure that I get X11 forwarding no matter whether I am using a static IP address or DHCP on the Windows host, or even whether my hostname or network location changes, I add the following to my ~/.bashrc file:

# 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

After doing the above, no matter what my Hostname or IP address of the Host is, it will be placed in the environment each time a BASH session is started in WSL2. Test it by running firefox from the command line and watch a YouTube video. You should be able to hear the sound as well as see the app itself to watch the video. Test by launching other GUI apps from the command line in addition.

What it does: It uses the host command to pull the IPv4 Addresses associated with the Hostname from the output, greps the address that matches the line that contains your Windows Host IPv4 address, strips the rest of the information except for the IP Address, and then awks that and prints it into the variable, with the output trimmed. This then is used to provide the necessary IP address as a string for use in the environment variables that allow for forwarding of X11 and sound output.

Hopefully it works for you if the other methods don't work for you (as they didn't for me).

Most CLI apps can be run either from the BASH Prompt or from Windows Terminal. If you want to make a shortcut, most CLI apps can be set up like either of the following examples (no need for X11 forwarding in such cases except apps like Links2):

C:\Windows\System32\wsl.exe -e htop
C:\Windows\System32\wsl.exe lynx

If you want to create desktop shortcuts for Linux GUI apps, unless you can get the environment variables from your ~/.bashrc file to be used before launching the programs, you will have to create shortcuts using the following template, and put the program name in place of {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}

You do not have to place the full command line for many programs. For PERL-based programs or Python-based programs, you sometimes will have to add the path for PERL and PYTHON, as well as your program's full path, to run such GUI programs in Linux using WSL2. For one of my perl programs, I have to do it this way:

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

You may have to experiment a bit to get some apps working properly. For example, you might need to dbus-launch an app, and will need to add that command to the shortcut just before the program name.

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

And you might have to use a shorter variable name in some circumstances. Some apps just won't work well, if at all, but this situation is improving over time. Also, don't try to run the above from a Windows Command Prompt or from PowerShell. It will throw errors about 'grep' not being recognized as an internal or external command, etc.

Following is a screenshot of a few Linux GUI apps running on my Windows 10 system, with working X11 forwarding on WSL2.

enter image description here

Share:
170,785

Related videos on Youtube

whme
Author by

whme

Updated on January 09, 2022

Comments

  • whme
    whme about 2 years

    When moving from WSL1 to WSL2 many things change; apparently this applies to X11 forwarding as well.
    What steps do I need to make in order to use X11 forwarding with WSL2 on Windows 10 as I did with WSL1?

    • NotTheDr01ds
      NotTheDr01ds over 2 years
      Tools commonly used by programmers must be taken with some level of common sense. It's well established that not all WSL2 questions are on-topic here, and this one should never have been reopened. We have sister sites for this reason, and Super User is much better for this. It might even be on-topic on Ask Ubuntu (assuming that distro is involved) or the Unix & Linux Stack. But no, this is not a question about "specific coding, algorithm, or language problems.'
  • stedes
    stedes almost 4 years
    I just tested your solution. Even with the "Disable access control" flag checked, I had to allow public access via Windows Defender ("Allow apps to communicate through Windows Defender Firewall"). However, I didn't have to add an extra inbound rule.
  • whme
    whme almost 4 years
    @stedes The extra inbound rule should be added to avoid allowing access for all public networks as this can cause security issues.
  • Adam
    Adam almost 4 years
    I made some slight modifications and got it to work. First, I used MobaXterm instead of VcXSrv since it seems more reliable from a firewall perspective. Second I used the following exported ENV variables. Key difference is I don't rely on /etc/resolv.conf. export DISPLAY=$(ip route | awk '/default via / {print $3; exit}' 2>/dev/null):0 export LIBGL_ALWAYS_INDIRECT=1
  • whme
    whme over 3 years
    Actually I did some research and couldn't find anything about the IP of the wsl2 being 172.17.0.1 in any case. I did also check regularly the IP of my wsl2 which indeed sometimes is the above mentioned one but also quite often happens to be another one. So NO, the IP is NOT 172.17.0.1 in any case.
  • matbrgz
    matbrgz over 3 years
    My /etc/resolv.conf contains several nameserver entries, none of which is my current IP-address, so this breaks. It appears there is assumptions about how this works.
  • Kennyhyun
    Kennyhyun over 3 years
    For whom is interested in a general tips for WSL
  • U.V.
    U.V. over 3 years
    ip route | wc -l 151 how is this supposed to work? or in other words: whats the route we are looking for. a single route is somewhat rare these days....
  • Guillaume Perrault-Archambault
    Guillaume Perrault-Archambault over 3 years
    i love you! lifesaver
  • bselu
    bselu over 3 years
    The awkcommand on this page to put the host's IP into the DISPLAY variable doesn't work for me. What does work is export DISPLAY=127.0.0.1:0. Of course, this needs a running loopback device. I wonder, why so many answers try to figure out the host's IP when there is such a simple solution?
  • ThoSil
    ThoSil over 3 years
    .bash_aliases should be used for...alias, not export variables And you're launching a command on windows from wsl2 to get the output of ipconfig, pass it to 2 grep, one head and one awk... and every time you open a shell. The pwsh.exe alone on my laptop takes 1.125s to run!
  • U.V.
    U.V. over 3 years
    YEAH! thats the way to go. I added it to my startx script: #!/bin/bash # start Xming X11 if not running if /mnt/c/Windows/System32/tasklist.exe | grep -q Xming.exe; then echo found X server else echo did not found Xserver - starting it /mnt/c/Program\ Files\ (x86)/Xming/XLaunch.exe -run '\Users\user\Desktop\config.xlaunch' & # also start the X11 pipe 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 wait a sec sleep 1 fi
  • whme
    whme over 3 years
    Please don't disable the firewall entirely for the wsl interface.
  • Fuhrmanator
    Fuhrmanator over 3 years
    @whme I removed that part, I think.
  • Antoine Bon
    Antoine Bon over 3 years
    Thank you very much, tried several other things but got some problems, this is working fine !
  • david-littlefield
    david-littlefield over 3 years
    Fixed, thanks @HectorJ
  • D. Charles Pyle
    D. Charles Pyle about 3 years
    Sadly, this doesn't work for me for two reasons. There is no pwsh.exe on my system. I assume that you meant powershell.exe or have some alias on your Windows system. The output when using powershell.exe ends up being the following on my system: :02.168.0.5. That of course won't work as that is only part of the address and the string order is flipped for some reason.
  • Sandburg
    Sandburg about 3 years
    Why using awk when sed is good enough: sed -n 's/nameserver //p' /etc/resolv.conf | head -n 1
  • Arseny
    Arseny about 3 years
    For authorization, you could also generate an ~/.Xauthority file by running xauth generate $DISPLAY . in WSL while VcXsrv is running with the authorization control disabled (-ac). Then do cp ~/.Xauthority /mnt/c/Users/<your login>/, and next time you start VcXsrv, use the -auth C:\Users\<your login>\.Xauthority parameter instead of -ac
  • T S
    T S about 3 years
    For Cygwin/X I didn't need to generate the cookie, instead I used k=$(/mnt/c/cygwin64/rootfs/bin/sh.exe -c '/bin/xauth -n list'|grep "^$DISPLAY") to get the existing cookie. I moved the export DISPLAY=... line above that line. I also needed to add a .xserverrc file containing exec /usr/bin/XWin -listen tcp "$@" to the cygwin home directory (echo 'exec /usr/bin/XWin -listen tcp "$@"' >> ~/.xserverrc in cygwin) to enable tcp access for the cygwin x server.
  • kevincasey
    kevincasey about 3 years
    The accepted answer's link to firewall changes shows some more details about limiting access to port 6000 and IP range 172.16.0.0/12 (which is good) but it is not specific to a program (like this answer). For MobaXterm my exe name was xwin_mobax.exe. They also didn't really explain how to navigate to the correct place in Windows Defender Firewall. These extra pictures helped complete the puzzle.
  • M.W.
    M.W. about 3 years
    Here's another place to toggle the firewall setting for VcXsrv. The security alert did not show up in my case.
  • user2828781
    user2828781 about 3 years
    Finally! That's the only solution that helped, tried everything. Just copy/pasted the first block of commands and voila! Thanks!
  • D. Charles Pyle
    D. Charles Pyle about 3 years
    You're welcome! Glad that it is working for you. It adds a second or two processing time but that is a small price to pay for a working configuration that is IP address agnostic.
  • Yoni
    Yoni about 3 years
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.
  • pscheit
    pscheit almost 3 years
    remember to update that rule, when the app is updated
  • user3534080
    user3534080 almost 3 years
    @TS can you elaborate on how you got Cygwin/X working with WSL2 as a new answer? I have VcXsrv working, but I've heard Cygwin/X may solve some of the graphical glitches I'm having. Unfortunately, I was unable to get any GUI apps to launch from the WSL2 terminal
  • andrewdotn
    andrewdotn over 2 years
    Thank you for posting how to do this correctly. All the other answers are fairly dangerous, as an X server that allows unauthenticated connections will allow not only mischief but also makes it trivial to attach a keylogger—just do xinput list to get the keyboard ID, then xinput test <n> to see all the key events.
  • Prut Udomwattawee
    Prut Udomwattawee over 2 years
    I use this in wsl2 for .bashrc and this work for me now.
  • jonespm
    jonespm over 2 years
    I originally set it up using these steps. However my system updated to Windows 11 and it wasn't working anymore. 11 has native support and doesn't need an XServer or any special config. I just ran though the steps here docs.microsoft.com/en-us/windows/wsl/tutorials/gui-apps updating WSL (wsl --update in Powershell) and updating my video driver (I used GeForce Experience to update). Then removed the DISPLAY override and everything worked great!
  • Marcus Vinicius Pompeu
    Marcus Vinicius Pompeu over 2 years
    @jonespm, YES!, I'm anxious for Window 11, primarily because of the WSL updates. Have you installed the preview or was it already available to you? For me the site states that 'Windows 11 isn’t here yet' :-(
  • PCM
    PCM over 2 years
  • douyu
    douyu over 2 years
    It doesn't work.
  • Kraego
    Kraego over 2 years
    What is not working. Do you checked the boxes in the windows alert (like described here: stackoverflow.com/a/63174434/11473934)
  • PranshuKhandal
    PranshuKhandal about 2 years
    the part "Start XLaunch on Windows" with access control helped me
  • Windel
    Windel about 2 years
    You can also use ip route list default | awk '{print $3}' to extract your windows IP in WSL.
  • Marcus Vinicius Pompeu
    Marcus Vinicius Pompeu about 2 years
    @Windel, perfect! Having to resort to resolv.conf did not sound good to me. I'll edit the proposed answer with this approach.
  • Lee Hounshell
    Lee Hounshell about 2 years
    Thank you! this is the only solution that works
  • Carlos
    Carlos about 2 years
    this works perfect, if you are having a problem try turning off your network firewall
  • Gabriel Berlanda
    Gabriel Berlanda about 2 years
    Thank you mate! Now I have my x-server working properly :)

Related