How to set up working X11 forwarding on WSL2
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:
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
It should have stop signs on Windows Defender firewall
Double click it and allow the connection for both private and public,
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
- (If you have disabled
resolv.conf
use this definition: https://stackoverflow.com/a/63092879/11473934)
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
- Run Dialog see Start XLaunch on Windows
- Save configuration
- Press Windows + R
- Enter: shell:startup
- 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.
Related videos on Youtube
whme
Updated on January 09, 2022Comments
-
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 over 2 yearsTools 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 almost 4 yearsI 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 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 almost 4 yearsI 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 over 3 yearsActually 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 NOT172.17.0.1
in any case. -
matbrgz over 3 yearsMy
/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 over 3 yearsFor whom is interested in a general tips for WSL
-
U.V. over 3 yearsip 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 over 3 yearsi love you! lifesaver
-
bselu over 3 yearsThe
awk
command on this page to put the host's IP into theDISPLAY
variable doesn't work for me. What does work isexport 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 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. over 3 yearsYEAH! 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 over 3 yearsPlease don't disable the firewall entirely for the wsl interface.
-
Fuhrmanator over 3 years@whme I removed that part, I think.
-
Antoine Bon over 3 yearsThank you very much, tried several other things but got some problems, this is working fine !
-
david-littlefield over 3 yearsFixed, thanks @HectorJ
-
D. Charles Pyle about 3 yearsSadly, 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 about 3 yearsWhy using awk when sed is good enough:
sed -n 's/nameserver //p' /etc/resolv.conf | head -n 1
-
Arseny about 3 yearsFor authorization, you could also generate an
~/.Xauthority
file by runningxauth generate $DISPLAY .
in WSL while VcXsrv is running with the authorization control disabled (-ac
). Then docp ~/.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 about 3 yearsFor
Cygwin/X
I didn't need to generate the cookie, instead I usedk=$(/mnt/c/cygwin64/rootfs/bin/sh.exe -c '/bin/xauth -n list'|grep "^$DISPLAY")
to get the existing cookie. I moved theexport DISPLAY=...
line above that line. I also needed to add a.xserverrc
file containingexec /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 about 3 yearsThe 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. about 3 yearsHere's another place to toggle the firewall setting for VcXsrv. The security alert did not show up in my case.
-
user2828781 about 3 yearsFinally! That's the only solution that helped, tried everything. Just copy/pasted the first block of commands and voila! Thanks!
-
D. Charles Pyle about 3 yearsYou'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 about 3 yearsWhile 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 almost 3 yearsremember to update that rule, when the app is updated
-
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 over 2 yearsThank 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, thenxinput test <n>
to see all the key events. -
Prut Udomwattawee over 2 yearsI use this in wsl2 for .bashrc and this work for me now.
-
jonespm over 2 yearsI 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 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 over 2 years
-
douyu over 2 yearsIt doesn't work.
-
Kraego over 2 yearsWhat is not working. Do you checked the boxes in the windows alert (like described here: stackoverflow.com/a/63174434/11473934)
-
PranshuKhandal about 2 yearsthe part "Start XLaunch on Windows" with access control helped me
-
Windel about 2 yearsYou can also use
ip route list default | awk '{print $3}'
to extract your windows IP in WSL. -
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 about 2 yearsThank you! this is the only solution that works
-
Carlos about 2 yearsthis works perfect, if you are having a problem try turning off your network firewall
-
Gabriel Berlanda about 2 yearsThank you mate! Now I have my x-server working properly :)