How to run graphical Linux desktop applications from Windows 10’s Bash Shell?
First, I installed Windows Subsystem for Linux (WSL) following steps as shown in here as follows:
(1) Installed Windows 10 Pro Insider Preview Build 19619.
(2) Installed Ubuntu Linux distribution.
(3) Changed the distribution version from WSL 1 to WSL 2.
Second, to enable graphical Linux desktop applications from Windows 10’s Bash Shell, I followed the following steps as shown here as follows:
(4) I installed an X Server that is Xming
(5) Installed graphical GTK-based vim editor as test using:
sudo apt-get install vim-gtk
(6) Set my display environment variable
export DISPLAY=:0
(7) Launch an Application
gvim
However, this did not lunch the application and I got the following error:
E233: cannot open display
Press ENTER or type command to continue
E852: The child process failed to start the GUI
Press ENTER or type command to continue
Any idea why this error is occurring?
The networking subsystem in WSL2 is different than the used in WSL1. You must consider the differences to access networking apps running on Windows and on Linux:
localhost or 127.0.0.1There are many ways to determine the IP addresses in the Windows host. You may run the following commands in your WSL Linux:
cat /etc/resolv.conf shows the IP address of the eth0 interface in Windowsipconfig.exe shows the all the IP configuration in the Windows hostroute.exe print shows the network routing configuration in the Windows hostBased on the Microsoft documentation, you may set the DISPLAY variable checking the nameserver in the /etc/resolv.conf file. (@fqquiner and @VPraharsha already mentioned this)
export DISPLAY=$(grep nameserver /etc/resolv.conf | awk '{print $2}'):0.0
However, I had problems using this solution, probably because I use my notebook with a WiFi connection and multiple virtual networks. Instead of the previous solution, I determine the Windows IP address using route.exe and checking the interface used in the default gateway.
export DISPLAY=$(route.exe print | grep 0.0.0.0 | head -1 | awk '{print $4}'):0.0
.profileYou may set the DISPLAY variable in your ~/.profile file. I used the following code:
# set DISPLAY to use X terminal in WSL
# in WSL2 the localhost and network interfaces are not the same than windows
if grep -q WSL2 /proc/version; then
# execute route.exe in the windows to determine its IP address
DISPLAY=$(route.exe print | grep 0.0.0.0 | head -1 | awk '{print $4}'):0.0
else
# In WSL1 the DISPLAY can be the localhost address
if grep -q icrosoft /proc/version; then
DISPLAY=127.0.0.1:0.0
fi
fi
The following instructions were copied and pasted from an article I wrote but it lost the original formatting, links, and screenshots:Source: How to Install Ubuntu Desktop with a Graphical User Interface in WSL2
Download VcXsrv: Visit the official website Click "Download"
Install VcXsrv: Open "vcxsrv-64.1.20.8.1.installer.exe" Click "Next" Click "Install" Click "Close"
Allow Access to VcXsrv: Check "Private Networks" Click "Allow Access"
Open PowerShell: Press "⊞ Windows" Enter "PowerShell" into the search bar Right-click "Windows PowerShell" Click "Run as Administrator"
Open WSL2: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
wsl
Install Ubuntu Desktop: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo apt --yes install ubuntu-desktop
Set the Username Variable: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
username=$(wslvar USERNAME)
Create the Ubuntu Directory: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
mkdir --parents /mnt/c/users/$username/.ubuntu/
Open the Ubuntu Directory: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
cd /mnt/c/users/$username/.ubuntu
Download Linux Software Repository for Microsoft Products: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
Ubuntu 20.04:
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb --output-document packages-microsoft-prod.deb
Ubuntu 18.04:
wget https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb --output-document packages-microsoft-prod.deb
Install Linux Software Repository for Microsoft Products: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo dpkg --install packages-microsoft-prod.deb
Update the Repositories: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo apt update
Install APT Transport for HTTPS: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo apt install --yes apt-transport-https
Update the Repositories: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo apt update
Install .Net: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo apt install --yes dotnet-sdk-5.0
Add Arkane Systems to the Source List Directory: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo sh -c 'echo "deb [trusted=yes] https://wsl-translinux.arkane-systems.net/apt/ /" > /etc/apt/sources.list.d/wsl-translinux.list'
Update the Repositories: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo apt update
Install Genie: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
sudo apt install --yes systemd-genie
Create the Sudoers File: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
echo "$USER ALL=(ALL) NOPASSWD:/usr/bin/genie" | sudo EDITOR="tee" visudo --file /etc/sudoers.d/$USER
Create the Desktop Script: Copy the code from below these instructions Paste the code into PowerShell Press "Enter"
# CREATE BASH SCRIPT
# Store block of text with here document
create_bash_script=$(cat << end_of_string
# Define necessary environment variables
export DISPLAY="\$(cat /etc/resolv.conf | grep nameserver | awk '{ print \$2 }'):1.0"
export DESKTOP_SESSION="ubuntu"
export GDMSESSION="ubuntu"
export XDG_SESSION_DESKTOP="ubuntu"
export XDG_CURRENT_DESKTOP="ubuntu:GNOME"
export XDG_SESSION_TYPE="x11"
export XDG_BACKEND="x11"
export XDG_SESSION_CLASS="user"
export XDG_DATA_DIRS="/usr/local/share/:/usr/share/:/var/lib/snapd/desktop"
export XDG_CONFIG_DIRS="/etc/xdg"
export XDG_RUNTIME_DIR="\$HOME/xdg"
export XDG_CONFIG_HOME="\$HOME/.config"
export XDG_DATA_HOME="\$HOME/.local/share"
export XDG_CACHE_HOME="\$HOME/.cache"
export XDG_DESKTOP_DIR="\$HOME/Desktop"
export XDG_DOCUMENTS_DIR="\$HOME/Documents"
export XDG_DOWNLOAD_DIR="\$HOME/Downloads"
export XDG_MUSIC_DIR="\$HOME/Music"
export XDG_PICTURES_DIR="\$HOME/Pictures"
export XDG_PUBLICSHARE_DIR="\$HOME/Public"
export XDG_TEMPLATES_DIR="\$HOME/Templates"
export XDG_VIDEOS_DIR="\$HOME/Videos"
# Start desktop environment
gnome-session
end_of_string
)
# Store username environment variable in lowercase
username=$(wslvar USERNAME | awk '{ print tolower($0) }') &&
# Save block of text in bash file
echo "${create_bash_script}" > "/mnt/c/users/$username/.ubuntu/02_start_desktop.sh"
Download the Shortcut Images: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
wget https://assets.ubuntu.com/v1/9fbc8a44-circle-of-friends-web.zip
Unzip the Shortcut Images: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
unzip -o 9fbc8a44-circle-of-friends-web.zip
Create the Shortcut Icon: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
convert -resize 64x64 ./circle-of-friends-web/png/cof_orange_hex.png ubuntu.ico
Exit WSL2: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
exit
Create the VcXsrv Script: Copy the code from below these instructions Paste the code into PowerShell Press "Enter"
# RELOAD VCXSRV SCRIPT
# Store username environment variable in lowercase
$username = $env:username.tolower()
# Store block of text with here-string
$reload_vcxsrv_script = @"
# Stop vcxsrv proccess that contains "1.0" in the program window title
get-process vcxsrv | where { `$_.mainwindowtitle -like "*1.0*" } | stop-process
# Start vcxsrv process in a large program window on display number one
start-process "c:\program files\vcxsrv\vcxsrv.exe" -argument ":1 -ac -nowgl -multimonitors -dpms"
"@
# Save block of text in powershell file
echo "${reload_vcxsrv_script}" > $env:userprofile/.ubuntu/reload_vcxsrv.ps1
Create the Ubuntu Script: Copy the code from below these instructions Paste the code into PowerShell Press "Enter"
# CREATE VISUAL BASIC SCRIPT
# Store username environment variable in lowercase
$username = $env:username.tolower()
# Store block of text with here-string
$create_vbs_script = @"
' Run PowerShell script in background
set application = createobject("shell.application")
application.shellexecute "powershell", "-file c:\users\admin\.ubuntu\01_reload_vcxsrv.ps1", "", "", 0
' Allow PowerShell script to complete
wscript.sleep 3000
' Run Bash script in background
set shell= createobject("wscript.shell")
shell.run "wsl sudo genie -c bash /mnt/c/users/admin/.ubuntu/02_start_desktop.sh", 0
"@
# Save block of text in bash file
echo "${create_vbs_script}" > $env:userprofile/.ubuntu/03_start_ubuntu.vbs
Create the Shortcut Script: Copy the code from below these instructions Paste the code into PowerShell Press "Enter"
# Store block of text with here-string
$create_shortcut_script = @"
# Define location variables
`$shortcut_location = "`$env:userprofile\.ubuntu\Ubuntu.lnk"
`$program_location = "`$env:userprofile\.ubuntu\03_start_ubuntu.vbs"
# Create shortcut
`$object = new-object -comobject wscript.shell
`$shortcut = `$object.createshortcut(`$shortcut_location)
`$shortcut.targetpath = `$program_location
`$shortcut.iconlocation = "`$env:userprofile\.ubuntu\ubuntu.ico"
`$shortcut.save()
"@
# Save block of text in powershell file
echo $create_shortcut_script > $env:userprofile/.ubuntu/04_create_shortcut.ps1
Open the Ubuntu Directory: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
cd c:\users\admin\.ubuntu
Create the Shortcut: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
powershell.exe -file .\04_create_shortcut.ps1
Open the Directory in Explorer: Copy the command from below these instructions Paste the command into PowerShell Press "Enter"
explorer .
Launch the Ubuntu Desktop: Double-click the "Ubuntu" shortcut
Open Terminal: Click "Activities" in the top-left corner Enter "Terminal" into the search bar Click "Terminal"
Disable the Screen Lock: Copy the command from below these instructions Paste the command into Terminal Press "Enter"
gsettings set org.gnome.desktop.screensaver lock-enabled false
Install the Snap Store: Copy the command from below these instructions Paste the command into Terminal Press "Enter"
sudo snap install snap-store
This worked for WSL1, for WSL2 set appropriate IP adress
I personally use a different approach from the other answers here, one that's more in-line with the architecture (as I understand it) of the upcoming (in Preview/Beta) WSLg feature.
I'm so used to connecting to my various systems using Remote Desktop (a.k.a. RDP) that it just made sense to use xrdp in my WSL instance(s) for graphical apps. This also gives me a full desktop environment, with the ability to try out different desktop managers (although I haven't explored this much yet).
Installation steps on Ubuntu 20.04 are very straightfoward:
sudo apt install xrdp xfce4 # Or whatever desktop manager you want
sudo cp /etc/xrdp/xrdp.ini /etc/xrdp/xrdp.ini.bak
sudo sed -i 's/3389/3390/g' /etc/xrdp/xrdp.ini # So it doesn't interfere with Windows RDP on 3389
In /etc/xrdp/startwm.sh, comment out the last two lines (that mention Xsession) and add:
#test -x /etc/X11/Xsession && exec /etc/X11/Xsession
#exec /bin/sh /etc/X11/Xsession
exec startxfce4
Start xrdp with:
sudo service xrdp start
And that's it -- You should be able to connect to your WSL Desktop using the built-in Remote Desktop Connection app. The computer to connect to will be localhost:3390. Make sure Xorg is selected as the Session type.
In case anyone didn't know, there is an easier way. In 2021, Microsoft gave us WSLg. 🎉
You basically just need Windows 11 but drivers for vGPU (Intel AMD Nvidia) are recommended.
WSLg is not compatible with WSL1. New WSL2 instances will basically just work™.
Older WSL2 systems will need to be updated once:
wsl --updatewsl --shutdown to force a restart of the WSLDon't forget to remove any other modifications to $DISPLAY that you may have made!
There's a troubleshooting section here for debugging X11 on wsl2:
https://github.com/cascadium/wsl-windows-toolbar-launcher/blob/master/README.md#troubleshooting
Port forwarding is not the same as WSL1 - your Linux services may be accessible via localhost for windows, but the reverse is no longer true.
So you need to use the internal IP of your windows host and tweak the firewall to allow the WSL network through.
Adding to fquinner's answer,
Your DISPLAY env variable should be set as export DISPLAY=X.X.X.X:0 to use the Windows host's IP address as WSL2 and the Windows host are not in the same network device, where X.X.X.X is the IP address
and your IP address is listed in resolv.conf against the nameserver ($ cat /etc/resolv.conf)
or simply export DISPLAY="`grep nameserver /etc/resolv.conf | sed 's/nameserver //'`:0" to load the correct IP address automatically. Additionally, you can add this to .bashrc or .zshrc (If you use Zsh)
Found out that now in order to get GUI working (at least when online) you need to use your public IP...
e.g. running the following should work:
export DISPLAY=$(dig +short myip.opendns.com @resolver1.opendns.com):0
Had the same problem so I tried these other suggestions but what ended up working was allowing vcxsrv through the public firewall. I know you're not using vcxsrv but perhaps it's the same problem for you too.
Install VcXsrv then enable public firewall like these pictures. Open Windows Defender Firewall with Advanced Security using wf.msc at command prompt. Then allow connections like in these pictures.
[
Then run VcXsrv from this guide for Windows 10 WSL2
Run VcXsrv by adding -ac addition parameter or type this at command prompt "C:\Program Files\VcXsrv\vcxsrv.exe" :0 -multiwindow -clipboard -wgl -ac
Then type this into your WSL2 terminal
export DISPLAY_NUMBER="0.0"
export DISPLAY=$(grep -m 1 nameserver /etc/resolv.conf | awk '{print $2}'):$DISPLAY_NUMBER
export LIBGL_ALWAYS_INDIRECT=1
# OPTIONAL Set the keyboard layout to US
setxkbmap -layout us
setsid emacs
exit