I’ve been really enjoying my time using the Windows Subsystem for Linux, or WSL for short. With it, I’ve been able to develop web software on Windows with the Linux environment familiar to me.

One issue I’d been running into, particularly with WSL 2 is that I sometimes need to run GUI applications from inside Ubuntu.

Why would you need to run GUI applications in WSL?

Well, one example is running system tests on Rails apps I develop. In my client work, I run Capybara using Firefox in headless mode using geckodriver, which works great on WSL!

Problem is, sometimes, I need to do so with headless mode turned off. Maybe some tests are failing, or I just wanna make sure that some layout parts are working well. If I wanted to, running firefox from within WSL would me the following error:

  Unable to init server: Could not connect: Connection refused
  Error: cannot open display: :0

What’s this display about, then?

Xserver

The display mentioned above refers to an Xserver, used by Linux to manage window, keyboard and mouse interaction with applications.

I found a tool that does just this for us! I can run an Xserver on Windows called Xming, which comes with several utilities to run an Xserver on Windows 10.

Setting up Xming on Windows

After downloading and installing the utility, we can run the Xlaunch utility with the following settings:

  • “Multiple windows” selected, display number set to 0
  • “Start no client” selected
  • “Clipboard” and “No Access Control” selected
  • Click on Finish

Xming will now be running in the background!

Setting up WSL for interacting with Xming

We next need to set up the DISPLAY environment variable to point to our running Xming server. With WSL 1, I could set this to be :0:

  export DISPLAY=:0

This, however, won’t work with WSL 2, due to, among other differences, it running a Virtual Machine. We can, however, set the IP address to forward this to.

This is where the discussion on GitHub really came in handy:

How are you seeing your DISPLAY variable in your Linux environment? Currently you will need to specify the IP address of the host, you can easily find this by looking at your /etc/resolv.conf file:

root@BENHILL-DELL:/mnt/c/Users/benhill# cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 192.168.110.177

Then you’ll run:

export DISPLAY=192.168.110.117:0

You may also need to launch vcxsrv with the -ac argument.

This is an area that we are working on improving in an update soon.

Even more helpfully, a poster lower down suggested the following:

export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | \
  awk '{print $2}'):0

Adding this line to the shell profile (~/.zshrc in my case) will set it up on every shell instance I start up! If you wanna do it in the current one, you can do so with the following:

$ source ~/.zshrc

Sadly, we’re not done yet. Running firefox now just causes a big ol’ nothing to happen.

Windows Firewall

The last step before I was able to run firefox is to allow Xming through the firewall. To do that, we’ll:

  1. Open up “Windows Security” (I usually type it into the Start menu)
  2. Click on the “Firewall & network protection”
  3. Click on “Allow an app through the firewall”

This will show the list of apps and their connection permissions through private and public networks, as shown below:

Allowed applications for Windows Defender Firewall

You need to find “Xming X Server” on this list and make sure it’s allowed (checked) for a public network!

Why does Xming need to communicate on public networks?

According to the docs:

WSL 2 has a virtualized ethernet adapter with its own unique IP address.

Our WSL instance isn’t connected to the local network directly, but rather through Windows using this virtualized ethernet adapter. It’s as if there was an ethernet cable connected between Ubuntu and Windows.

This is different from how WSL 1 worked. WSL 2 requires that we setup networking like we would another virtual machine. If you’re curious, this video offers a good in-depth look at how WSL networking works.

Once we do this, back in WSL, we can just run firefox, and voilà, it’s there! Heck, let’s run gedit too:

Firefox and GEdit running in Windows

What’s next?

Well! Shortly before I finished writing all of this down, I found this here tweet.

The WSL team is working on getting this feature built in! Soon, it looks like GUI Linux apps will have not only their own taskbar icons, but proper shadowed windows and full compatibility without having to worry about Xservers, firewalls, or anything like that. Thank you so much, WSL team!

I’m still happy I learned what I learned about Xservers, and until then, you can use GUI apps by doing what I did above!

Big, big thanks to José for pairing with me to figure this out!