Windows X11 Server setup For WSL2

If you want to be able to run graphical applications from within your WSL2 linux distros, you’ll need to setup an X11 Server running on your Windows 10 host computer and then allow X11 clients to connect to your server.

The typical X11 server being used for Windows 10 is VcXSrv. This guide will walk you through setting this up with your WSL2 distros AND WITHOUT DISABLING ACCESS CONTROL on the X11 server.

I’ve tried updating various places on the internet including the VcXSrv wiki on how to do this. First what is the issue?

All tutorials for setting up VcXSrv that I had seen prior to my postings, had users disable the access control on VcXSrv. This means that anyone on your network can monitor every keystroke and mouse movement that you make on your machine. This is bad on a company network and worse still if your computer is directly connected to the internet.

Let’s do this using X11’s xauth scheme to share private authorization “cookies” or keys between the X11 server and X11 clients that wish to connect to the server.

General Steps

  1. Install WSL2 on your Windows 10.
  2. Get the Ubuntu 20.04 WSL distro and install that using the Windows Store.
  3. Install Docker for Windows
  4. Install VcXSrv

VcXSrv Setup

Install VcXSrv from https://sourceforge.net/projects/vcxsrv/

Setup Your Xauthority File

Create your .Xauthority file. This file will be placed in the home directory for your user. The easiest way to create this file is to use your WSL2 distro to do so. Open up a windows terminal with your WSL2 distro and enter the following commands:

sudo apt install -y xauth coreutils gawk gnome-terminal
xauth list # should be empty
magiccookie=$(echo '{some-pass-phrase}'|tr -d '\n\r'|md5sum|gawk '{print $1}')
# alternate way of creating a cookie:  
magicookie=$(mcookie)
xauth add host.docker.internal:0 . $magiccookie 
# Now check to see if it was added by doing 
xauth list 
# you should see the newly added entry for 
# host.docker.internal The line below assumes
# that you've installed your windows 
# into the default location 
# C:\Windows folder. We use the 
# cmd.exe to grab the location of the 
# Windows' UserProfile folder
userprofile=$(wslpath $(/mnt/c/Windows/System32/cmd.exe /C "echo %USERPROFILE%" | tr -d '\r\n')) 
# $userprofile now holds the Windows User Profile Directory
cp ~/.Xauthority "$userprofile"

Add the following to either your ~/.bashrc in your WSL2 distro home dir

     export DISPLAY=${DISPLAY:-host.docker.internal:0}

Now we’re done setting up our WSL2 distro, we need to setup the X11 server on the Windows 10 host.

Create a Shortcut to Launch VcXSrv

We need to create either an XLaunch.exe configuration file (i.e. config.xlaunch ) or a shortcut to VcXSrv.exe with the desired command line args. XLaunch is a simple launcher provided by VcXSrv that assists in setting up the command line arguments and in turn calls vcxsrv.exe. We’ll ingore using XLaunch and just create our own shortcut with the appropriate arguments.

We want to run VcXSrv.exe with these args:

vcxsrv.exe -multiwindow -clipboard -nowgl -auth {.XAuthority file} -logfile {A Log file} -logverbose {int log level}

From above, we copied the .Xauthority file to:

"%USERPROFILE%\.Xauthority" 
# NOTE: The default location of the User Profile Folder is
# /mnt/c/Users/{WindowsUserName} 

which means our desired command line is:

%ProgramFiles%\VcXsrv\vcxsrv.exe -multiwindow -clipboard -nowgl -auth "%USERPROFILE%\.Xauthority" -logfile "%USERPROFILE%\VcXSrv.log" -logverbose 5

Note the use of the Windows 10 environment variables %ProgramFiles% and %USERPROFILE% to get the location of the Program Files folder and UserProfile folder under Windows 10. The default location of the Program Files folder is “C:\Program Files” while the default location of the UserProfile folder is “C:\Users\{WindowsUserName}”. Feel free to omit the logfile and logverbose options if you’re not debugging any issues. So you can just do:

%ProgramFiles%\VcXsrv\vcxsrv.exe -multiwindow -clipboard -nowgl -auth "%USERPROFILE%\.Xauthority"

To create the shortcut, navigate to where VcXSrv.exe is installed. The default location of this is

%ProgramFiles%\VcXsrv\vcxsrv.exe

In the explorer file window, right click on the VcXSrv.exe and click “Create Shortcut” . This will create a shortcut on your desktop.

Right click over the created shortcut icon, and select properties.

In the Shortcut tab, append the arguments above after the executable . It should look something like:

%ProgramFiles%\VcXsrv\vcxsrv.exe -multiwindow -clipboard -nowgl -auth "%USERPROFILE%\.Xauthority"

In the General tab of the Properties dialog, change the name to be “VcXSrv with XAuthority” .

Click ok.

Now you can start the X11 server by double clicking on the shortcut.

If you wish to have the X11 server started at startup, follow the instructions here:
https://support.microsoft.com/en-us/windows/add-an-app-to-run-automatically-at-startup-in-windows-10-150da165-dcd9-7230-517b-cf3c295d89dd

  1. Now back in the WSL distro terminal, you should be able to run
    the gnome-terminal or other X11 client and have it display securely
    on the VcXSrv X11 server running on the Windows host.

Using XLaunch instead of a Shortcut to VcXSrv

You can also run the VcXSrv using its XLaunch program. Run XLaunch from
the Windows Start Menu. This will show a dialog and you should use these
settings:

     ....
     Display Settings:
       Select display settings:
         CHOOSE: Multiple windows
         Display number: -1
     Select Next
     ....
     Client startup
       Select Start no client
     Select Next
     ....
     Extra settings
       Select Clipboard & Primary Selection
       Uncheck Native opengl (This depends on your particular setup)
       Additional parameters:
          -auth "c:\Users\{WindowUserName}\.Xauthority"
     Select Next
     ....
     Finish configuration
       You can save this configuration for next time should you wish
       or just always specify the -auth {filename} where to read
       your xauth file.
     Select Finish
     ....

WSL Interop

There are some issues to consider if you start an X11 terminal client such as gnome-terminal instead of Windows Terminal. When Windows Terminal starts, it creates a WSL2 instance for your distro which uses a unix filesystem socket /run/WSL/NNNN_interop to communicate in order to execute Windows 10 commands under the Windows Host instead of inside the WSL2 distro. This happens under the covers. The particular unix filesystem socket to use to talk to the host is specified in the $WSL_INTEROP variable. If the original WSL instance is cleaned up, the socket is removed and any Windows 10 commands will fail to execute with the error:

ERROR: UtilConnectToInteropServer:300: connect failed 2

If your only running commands in your WSL distro, you won’t have an issue. Further you can restore the functionality by starting up a new WSL distro in a Windows Terminal and reusing the new WSL distro’s WSL_INTEROP socket with your existing gnome-terminal.

Try this example:

  1. Run Windows Terminal and use your favorite WSL2 distro.
  2. Within the WSL2 distro, start gnome-terminal . (You’ll need to have an X Server on your Windows Host).
  3. In the new gnome-terminal, execute the command:
/mnt/c/Windows/System32/cmd.exe /C "echo %USERPROFILE%"

NOTE: that it works and prints out the contents of the Windows Environment Variable USERPROFILE.

Also note the contents of the WSL_INTEROP bash environment variable points to /var/run/NNNN_interop or something like that

  1. Close the original Windows Terminal. This frees up the WSL instance
  2. Go back to the gnome-terminal and re-execute the above command. It will fail with the error:
ERROR: UtilConnectToInteropServer:300: connect failed 2
  1. Now start up a new Windows Terminal with a new WSL2 instance. In that terminal, see what the contents of WSL_INTEROP is
echo $WSL_INTEROP
  1. Go back to the gnome-terminal and change that WSL_INTEROP variable to use the new value from the new Windows Terminal
  2. Reexecute the command and it works again since its now using the new filesystem socket.

I added a gist on github that will walk you through setting up your xauthority file with WSL2. It will ask that you create a WSLENV variable to export a couple of Windows Environment Variables to your WSL2 distro. You’ll need to determine the IP address which I obtained the one associated with my PC’s ethernet connection using Window’s “Network and Internet settings”.

To get the full gist, in your WSL2 distro app do

git clone git@gist.github.com:c9c3b95b90d9620d4805c30e0b4791cc.git

Using a GIST to setup your WSL

export DISPLAY=NN.NN.NN.NN:0
cd {gist-folder}
bash ./wsl2SetupForVcXSrv.sh

Sleeping Clients never Rise : AKA The Disappearing X clients under WSL2

As of Windows 10 build 21343, there is an issue with X11 clients not redisplaying after a Windows resume from a Windows sleep. The underlying issue appears to be that outbound TCP connections from WSL2 to Windows (e.g. such as an X11 client under WSL2 connecting to VcXSrv running under Windows), those connections aren’t being “restored” after a resume.

The opposite does work though. That is, if you have a TCP connection from Windows into WSL2, after resume Windows performs some housekeeping to allow those connections to perform as expected. This means that you can run a Windows SSH client application and have it connect to your WSL2 instance. If you do this, the connection will be restored upon a Windows resume.

To do this, first start an ssh daemon on your WSL2 distro. If you’re using the Ubuntu 20.04 distro, you can do:

sudo service ssh start

to run the ssh daemon. Now setup PuTTY to open a connection to WSL2 and forward the X11 connections. Under the Connection>SSH>X11 section, set the X display location in PuTTY to ‘:0.0’, set the X authority file for local display to be the location %USERPROFILE%\.Xauthority file you’ve setup previously. You can optionally setup a ssh key file. Have PuTTY connect to localhost port 22 to access the ssh daemon that you started under WSL2.

Untested

I have tested this, but there’s an app that will run a daemon under windows and one under WSL2 that will do this for you. Check out

https://github.com/nbdd0121/wsld