Written September 2, 2021

If you want to run graphical Linux applications in WSL2, you'll need an X (X11) Server running. wslg will add native X11/Wayland support into Windows, but for now that's only in Preview.

Download and install VcXsrv

I use VcXsrv because it's still actively maintained.

If you're running an x86-64-bit version of Windows: https://sourceforge.net/projects/vcxsrv/files/vcxsrv/

If you're running Windows on ARM, use the x86-32 bit version: https://sourceforge.net/projects/vcxsrv/files/vcxsrv/

During the install, install the Fonts, or things will not look pretty. installation options

Note, the location of the .exe will depend on whether you chose the 32 or 64 bit version. Convention explained below:

  • C:\Program Files (x86) - contains 32-bit x86 exes

  • C:\Program Files - contains the native OS exes (x86-64 or ARM64 depending on the host system architecture)

  • C:\Program Files (Arm) - contains 32-bit ARM exes

In my case, I chose the 32-bit version, so I am going to use C:\Program Files (x86) throughout the rest of this guide.

Secure the network

To properly secure the daemon, we need to secure the windows firewall. This is so not anyone on your network can start sending graphical programs to your display, but probably more concerning, stealing clipboard data.

Configure the Windows Firewall such that ONLY private class B IP addresses are able to connect on port 6000 (Display 0):

# remove the existing rule if it exists
Get-NetFirewallRule | Where-Object -Property DisplayName -EQ "VcXsrv windows xserver" | Remove-NetFirewallRule
# add a new rule
New-NetFirewallRule -Program "C:\Program Files (x86)\VcXsrv\vcxsrv.exe" -DisplayName "X11" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 6000 -RemoteAddress

Ideally, we would restrict the RemoteAddress to a smaller subnet, but the subnet is sadly unpredictable.

Secure the server application

Don't let anyone connect, only if the client has the right credentials.

Generate one:

New-Item -Type File -Path "${env:USERPROFILE}\.Xauthority"
& "C:\Program Files (x86)\VcXsrv\xauth.exe" add "$((Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "vEthernet (WSL)").IPAddress):0" . $(wsl mcookie)

# to confirm if it worked:
& "C:\Program Files (x86)\VcXsrv\xauth.exe" -n list

Create the following x11.xlaunch file:

New-Item -Type File -Path "$([Environment]::GetFolderPath("MyDocuments"))\x11.xlaunch" -Value @"
<?xml version="1.0" encoding="UTF-8"?>
    ExtraParams="-auth &quot;${env:USERPROFILE}\.Xauthority&quot;"

Launch the X11 server with the configuration file above

Double-click x11.xlaunch (since .xlaunch files are associated with XLaunch.exe) or execute PowerShell command:

& "C:\Program Files (x86)\VcXsrv\XLaunch.exe" -run "$([Environment]::GetFolderPath("MyDocuments"))\x11.xlaunch"

You can create a shortcut in the x11.xlaunch in your Start Menu

explorer.exe "${env:APPDATA}\Microsoft\Windows\Start Menu\Programs"

Right-click drag x11.xlaunch from your Documents to this directory, and select, Create shortcuts here

Configure the X11 client credentials

Back in WSL:

touch ~/.Xauthority
xauth -q merge $(wslpath $(powershell.exe -Command 'echo "${env:USERPROFILE}"' | sed 's/[\r]//g'))/.Xauthority


echo export DISPLAY="\$(ip route show default | sed -n 's/.*via \([^ ]\+\).*$/\1/p'):0" >> ~/.bashrc
source ~/.bashrc

# install some X11 utilities (such as xclock and xcalc for testing purposes)
sudo apt install x11-apps
xclock -update 1

Note X11 windows sometimes don't get focused automatically, so pay attention to your task bar to see what's new; you might have to click on it or Alt+Tab. xclock

Software Rendered Graphics

echo export LIBGL_ALWAYS_INDIRECT=0 >> ~/.bashrc
echo export GALLIUM_DRIVER=llvmpipe >> ~/.bashrc

sudo apt install mesa-utils
glxgears  # cool

Copy to clipboard

While the X server is running, now you can programmatically add to the Windows clipboard within WSL2.

In PowerShell

echo "no way...$(Get-Clipboard)"  # don't hit enter yet!

In bash

sudo apt install xclip
echo -n Yes way. | xclip

Back in PowerShell

# now hit enter

What could possibly go wrong?

Turns out a lot.

  • If you happen to be a member of the Windows Insider program, you might have the wlsg Preview, and not even know it, messing with the DISPLAY and other things. To disable it:
New-Item -Type File -Path "${env:USERPROFILE}\.wslconfig" -Value @"
  • The WSL IP changes on every reboot, which makes the .Xauthority config invalid. So you need to regenerate it.
New-Item -Type File -Path "${env:USERPROFILE}\.Xauthority" -Force

then run the add command all over again and merge in the steps above.