Skip to content

Instantly share code, notes, and snippets.

@tdcosta100
Last active September 20, 2024 03:42
Show Gist options
  • Save tdcosta100/e28636c216515ca88d1f2e7a2e188912 to your computer and use it in GitHub Desktop.
Save tdcosta100/e28636c216515ca88d1f2e7a2e188912 to your computer and use it in GitHub Desktop.
A tutorial to use GUI in WSL2/WSLg replacing original Xorg by Xwayland, allowing WSL to work like native Linux, including login screen

Full desktop shell in WSL2 using WSLg (XWayland)

Note

If you want to use Wayland in WSLg in a simpler setup, you can try the WSLg (Wayland) tutorial.

In this tutorial, we will setup GUI in WSL2. No additional software outside WSL (like VcXsrv or GWSL) is required. You will find this tutorial very similar to the one that replaces Xorg with Xvnc. Indeed, it's pretty much the same tutorial, with some few changes.

The key component we need to install is the desktop metapackage you want (GNOME, KDE, Xfce, Budgie, etc), and after that, replace the default Xorg by a script that calls Xwayland instead.

For this setup, I will use Ubuntu 24.04, and install GNOME Desktop. Unfortunately older versions of Ubuntu lack some fundamental things, so we cannot reproduce it in older versions (at least not fully). Since the key components aren't bound to Ubuntu or GNOME, you can use your favorite distro and GUI. Check the Sample screenshots section for examples.

So let's go. First, we need a working WSL2 installation.

Warning

WSLg may not work as expected, since Wayland sockets are disabled for everyone, and not every app can handle this. But if you want to use Wayland apps natively, you can use the command export XDG_RUNTIME_DIR=$HOME/runtime-dir and then start your WSLg app.

Before going to real business, let's make sure we are updated.

sudo apt update
sudo apt upgrade

You also need to make sure /etc/wsl.conf have the following lines:

[boot]
systemd=true

If not, create/edit this file, add these lines and restart WSL (for example, using wsl.exe --shutdown, then reopening the distro terminal).

Now we are ready to go.

Installing components

Installing GUI

  1. First you select your favorite desktop environment metapackage. Here is a list of the most common metapackages:

    DistroDesktop EnvironmentMetapackage
    UbuntuBudgieubuntu-budgie-desktop (currently very buggy, I don't recommend using it)
    GNOMEubuntu-desktop
    KDEkubuntu-desktop
    Kylinubuntukylin-desktop
    LXDElubuntu-desktop
    MATEubuntu-mate-desktop
    Studioubuntustudio-desktop
    Unityubuntu-unity-desktop
    Xfcexubuntu-desktop
    Ubuntu/DebianCinnamontask-cinnamon-desktop
    GNOMEtask-gnome-desktop
    GNOME Flashbacktask-gnome-flashback-desktop
    KDE Plasmatask-kde-desktop
    LXDEtask-lxde-desktop
    LXQttask-lxqt-desktop
    MATEtask-mate-desktop
    Xfcetask-xfce-desktop
  2. Once you have chosen the metapackage, let's install it. For example, if you choose ubuntu-desktop, the command will be:

    sudo apt install ubuntu-desktop xwayland
    

    This will install the ubuntu-desktop and xwayland (if not already included as dependency for your metapackage). The installation will take a while, so be patient.

  3. If in Ubuntu, you may want to install snap-store. If you don't need it, you can skip this step:

    sudo snap install snap-store
    

Configuring the environment

If you are using Debian, you need to configure the locale (this is not needed in Ubuntu):

echo "LANG=en_US.UTF-8" | sudo tee -a /etc/default/locale

Create and modify services

  1. Now we have everything installed, we need to fix the directory /tmp/.X11-unix/, because it's mounted as read-only by default. We will create a new systemd unit:

    sudo systemctl edit --full --force wslg-fix.service
    
  2. Paste the code below in the editor:

    [Service]
    Type=oneshot
    ExecStart=-/usr/bin/umount /tmp/.X11-unix
    ExecStart=/usr/bin/rm -rf /tmp/.X11-unix
    ExecStart=/usr/bin/mkdir /tmp/.X11-unix
    ExecStart=/usr/bin/chmod 1777 /tmp/.X11-unix
    ExecStart=/usr/bin/ln -s /mnt/wslg/.X11-unix/X0 /tmp/.X11-unix/X0
    ExecStart=/usr/bin/chmod 0777 /mnt/wslg/runtime-dir
    ExecStart=/usr/bin/chmod 0666 /mnt/wslg/runtime-dir/wayland-0.lock
    
    [Install]
    WantedBy=multi-user.target
    
  3. Exit the editor saving the changes to the file.

  4. Let's enable wslg-fix.service:

    sudo systemctl enable wslg-fix.service
    
  5. We also need to remove all references to Wayland, because if not, some apps (gnome-terminal, for example) will open outside the desktop shell. We will edit the user-runtime-dir@.service service:

    sudo systemctl edit user-runtime-dir@.service
    
  6. Paste the code below in the editor:

    [Service]
    ExecStartPost=-/usr/bin/rm -f /run/user/%i/wayland-0 /run/user/%i/wayland-0.lock
    

Warning

Please read the editor instructions about the correct place to position the text cursor before pasting. If you paste the code in the wrong place, it will be discarded.

  1. Exit the editor saving the changes to the file.

  2. Now we will change the default startup target, because if not, a shell window will appear everytime you start your distro (for example, opening a Terminal of your distro in Windows).

    sudo systemctl set-default multi-user.target
    

Replacing default Xorg by XWayland

By default, the display manager call multiple Xorg instances, one for each user session, including the login screen, provided by GDM (if you are using the GDM as your display manager, of course). So we will replace Xorg script by a new version which calls Xwayland instead the classic Xorg. This is the real magic we are trying to do.

  1. First, let's backup the original Xorg script.

    sudo mv /usr/bin/Xorg /usr/bin/Xorg.original
    
  2. Then, we create a new Xorg script.

    sudo nano /usr/bin/Xorg.Xwayland
    
  3. Paste the code below in the editor:

    #!/bin/bash
    for arg do
      shift
      case $arg in
        # Xwayland doesn't support vtxx argument. So we convert to ttyxx instead
        vt*)
          set -- "$@" "${arg//vt/tty}"
          ;;
        # -keeptty is not supported at all by Xwayland
        -keeptty)
          ;;
        # -novtswitch is not supported at all by Xwayland
        -novtswitch)
          ;;
        # other arguments are kept intact
        *)
          set -- "$@" "$arg"
          ;;
      esac
    done
    
    # Check if the runtime dir is present, and create it if not
    if [ ! -d $HOME/runtime-dir ]
    then
     mkdir $HOME/runtime-dir
     ln -s /mnt/wslg/runtime-dir/wayland-0 /mnt/wslg/runtime-dir/wayland-0.lock $HOME/runtime-dir/
    fi
    
    # Point the XDG_RUNTIME_DIR variable to $HOME/runtime-dir
    export XDG_RUNTIME_DIR=$HOME/runtime-dir
    
    # Find an available display number
    for displayNumber in $(seq 1 100)
    do
      [ ! -e /tmp/.X11-unix/X$displayNumber ] && break
    done
    
    # Here you can change or add options to fit your needs
    command=("/usr/bin/Xwayland" ":${displayNumber}" "-geometry" "1920x1080" "-fullscreen" "$@")
    
    systemd-cat -t /usr/bin/Xorg echo "Starting Xwayland:" "${command[@]}"
    
    exec "${command[@]}"
    

    Please note the resolution of the virtual screen. You can change that to fit your needs (1366x768, 3840x2160, etc).

  4. Exit the editor saving the changes.

  5. Finally, we set the correct permissions for the file and create a link to it:

    sudo chmod 0755 /usr/bin/Xorg.Xwayland
    sudo ln -sf Xorg.Xwayland /usr/bin/Xorg
    

Warning

Sometimes, system updates replace Xorg link with the original version. Just repeat this step if this happens, and Xwayland will work again as Xorg replacement.

Configuring the monitor resolution under GDM and GNOME

Currently, one of the annoying things is the resolution of Xwayland. Even with the -geometry switch, GDM and GNOME don't not respect it. Fortunately, this can be overriden by creating a monitors.xml file. Let's do it then.

  1. First, we create it in the current user directory:

    mkdir ~/.config
    nano ~/.config/monitors.xml
    
  2. Paste the code below in the editor (here it is configured for a 1920x1080 resolution, so change it to reflect your resolution if necessary):

    <monitors version="2">
      <configuration>
        <logicalmonitor>
          <x>0</x>
          <y>0</y>
          <scale>1</scale>
          <primary>yes</primary>
          <monitor>
            <monitorspec>
              <connector>XWAYLAND0</connector>
              <vendor>unknown</vendor>
              <product>unknown</product>
              <serial>unknown</serial>
            </monitorspec>
            <mode>
              <width>1920</width>
              <height>1080</height>
              <rate>59.963</rate>
            </mode>
          </monitor>
        </logicalmonitor>
      </configuration>
    </monitors>
  3. Exit the editor saving the changes to the file.

  4. Now let's copy this file to GDM's home directory:

    sudo mkdir /var/lib/gdm3/.config
    sudo cp ~/.config/monitors.xml /var/lib/gdm3/.config/
    
  5. Finally, we set the correct permissions to the monitors.xml of GDM user:

    sudo chown -R gdm:gdm /var/lib/gdm3/.config/
    
  6. Restart WSL using wsl.exe --shutdown, then reopen your distro terminal.

Running your distro with GUI enabled

Now you have everything ready to start. Just do the following command:

sudo systemctl start graphical.target

After a while (usually a few seconds, but it can take more if you don't have a SSD), the login screen must appear.

After logging in, the logged user's desktop must appear. When you log out, the screen will show the login interface again. This applies to GDM (which is the case if you installed Ubuntu Desktop). In GDM, you can change this behavior changing the configuration file like this:

  1. sudo nano /etc/gdm3/custom.conf

  2. Uncomment and edit the following lines:

     AutomaticLoginEnable=true
     AutomaticLogin=[your username without the brackets]
    

Shutting down

One important thing is: once you start your WSL instance, you cannot just stop it. You must perform a standard Linux shutdown. You can do one of the alternatives below:

  • Power off option on GUI menu
  • sudo poweroff

After doing that, you can safely shut down your WSL instance, either by wsl.exe --terminate or wsl.exe --shutdown. Not doing the shutdown process may cause damage to your WSL instance. So be careful.

Troubleshooting

  1. If it doesn't work at first, try to check your journalctl logs:

    journalctl -b -t /usr/lib/gdm3/gdm-x-session -t /usr/bin/Xorg --no-pager
    

    If you are using Debian, then the command is:

    journalctl -b -t /usr/libexec/gdm-x-session -t /usr/bin/Xorg --no-pager
    

    In the output, you must see what command line was generated for Xwayland, and which error messages appear. Of course, even if it works correctly, you can check the logs just to see what is happening, or for debugging.

  2. You must check if the custom Xorg script was not replaced by the default version of it. If it was the case, just repeat the steps of Replacing default Xorg by Xwayland section.

  3. Check if Xorg is your default display server, not Xephyr or Wayland. If it's not, you must change it to have Xorg as your default display server.

  4. If you are using LightDM, you also need to check logs at /var/log/lightdm (you will need to use sudo to cat files in that directory). The Xwayland output will be in the file /var/log/lightdm/x-0.log.

  5. If it still doesn't work, you can try to restart WSL with wsl.exe --shutdown (don't forget to save everything that is unsaved before, because WSL will shut down completely), then open your distro terminal again and repeat the steps of section Running your distro with GUI enabled.

Sample screenshots

GDM

GDM

LightDM (Kubuntu)

LightDM

GNOME

GNOME

KDE (Kubuntu)

KDE

LXDE (Lubuntu)

LXDE

Xfce (Xubuntu)

Xfce

Contributors

Thanks to this guys, whose feedback made this tutorial reach the current level of quality and completeness (and it will be more and more complete as more feedback is given).

@asoretmadolell
Copy link

Hello my friend, love your tutorials, but I'm having an issue that was happening on the Xvnc tutorial that I find is still happening on this new Xwayland tutorial.
Every time I try to edit the user-runtime-dir@.service, I get the error:
Editing "/etc/systemd/system/user-runtime-dir@.service.d/override.conf" canceled: temporary file is empty.
And it fails to save any changes.
All the steps up to creating the Xorg link seem to work fine, but after I start the system and connect to 5901, I can see the login screen, but when I log in, I get a white screen with the "oh no!" dead computer message.
I followed all the steps carefully and the only one I can see different from you is that one.
I'm using 22.04
Thank you!

@tdcosta100
Copy link
Author

tdcosta100 commented Jul 29, 2024

Hi, @asoretmadolell. When you open the editor, it tells you to put your code below and above some specific lines. If you put the code before these lines, they are discarded, hence the "temporary file is empty" message. I will update the tutorial to warn people about this. Please repeat this step and once succeeded, tell me if it works.

@asoretmadolell
Copy link

Hi, @asoretmadolell. When you open the editor, it tells you to put your code below and above some specific lines. If you put the code before these lines, they are discarded, hence the "temporary file is empty" message. I will update the tutorial to warn people about this. Please repeat this step and once succeeded, tell me if it works.

My friend, you are absolutely right and it clearly says where to put it. I was pasting it at the very end of the file.
I'm having a different issue now; the journalctl command returns normal, I think:
Jul 30 10:46:22 ASO-5CG2224M5T /usr/bin/Xorg[2641]: Starting Xwayland: /usr/bin/Xwayland :1 -geometry 1920x1080 -fullscreen tty1 -displayfd 3 -auth /run/user/128/gdm/Xauthority -nolisten tcp -background none -noreset -verbose 3
But when I inspect the syslog or try to run it outside of the systemctl, I get this:
Unrecognized option: -geometry
I then checked the version and this is what I got
The X.Org Foundation Xwayland Version 22.1.1 (12201001) X Protocol Version 11, Revision 0

@asoretmadolell
Copy link

asoretmadolell commented Jul 30, 2024

I tried on Ubuntu 24 and I can confirm everything works now :)
Some scaling and resolution issues make it look funky but can be changed later in settings. It starts with a res of 5120x2880 and a scale of 200%. I guess I'll have to tweak the Xwayland parameters, right? Definitely on the right track.
Now the next step is to support multiple monitors :D
Thank you so much for such amazing tutorials.

@Saentist
Copy link

saen@PC2:~$ sudo systemctl edit --full --force wslg-fix.service
[sudo] password for saen:
Failed to connect to bus: No such file or directory

What can be a problem?

@tdcosta100
Copy link
Author

I tried on Ubuntu 24 and I can confirm everything works now :) Some scaling and resolution issues make it look funky but can be changed later in settings. It starts with a res of 5120x2880 and a scale of 200%. I guess I'll have to tweak the Xwayland parameters, right? Definitely on the right track. Now the next step is to support multiple monitors :D Thank you so much for such amazing tutorials.

That's nice to know you managed to get it working. I was thinking it was only with me, but apparently it works with everyone. I have some workarounds to fix this under GNOME and GDM. For LightDM you have to do a xrandr command to set the correct resolution. I will improve the tutorial.

@tdcosta100
Copy link
Author

saen@PC2:~$ sudo systemctl edit --full --force wslg-fix.service
[sudo] password for saen:
Failed to connect to bus: No such file or directory

What can be a problem?

What distro and version are using?

@Saentist
Copy link

saen@PC2:~$ sudo systemctl edit --full --force wslg-fix.service
[sudo] password for saen:
Failed to connect to bus: No such file or directory

What can be a problem?

What distro and version are using?

 wsl -v
WSL version: 2.2.4.0
Kernel version: 5.15.153.1-2
WSLg version: 1.0.61
MSRDC version: 1.2.5326
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26091.1-240325-1447.ge-release
Windows version: 10.0.19045.4651
lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.7 LTS
Release:        16.04
Codename:       xenial

@tdcosta100
Copy link
Author

tdcosta100 commented Jul 31, 2024

@Saentist, this version of Ubuntu is not compatible with this tutorial. The minimum version compatible with it is 24.04. Maybe you should try the Xvnc tutorial instead. I don't know if it will work in 16.04, but maybe.

@Saentist
Copy link

Saentist commented Aug 1, 2024

@tdcosta100 there is a problem with SystemD
but this tutorial work
https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-vnc-on-ubuntu-16-04
Badly in WSL do-release-update do not work

@asoretmadolell
Copy link

I tried on Ubuntu 24 and I can confirm everything works now :) Some scaling and resolution issues make it look funky but can be changed later in settings. It starts with a res of 5120x2880 and a scale of 200%. I guess I'll have to tweak the Xwayland parameters, right? Definitely on the right track. Now the next step is to support multiple monitors :D Thank you so much for such amazing tutorials.

That's nice to know you managed to get it working. I was thinking it was only with me, but apparently it works with everyone. I have some workarounds to fix this under GNOME and GDM. For LightDM you have to do a xrandr command to set the correct resolution. I will improve the tutorial.

Thank you so much for the work you put on this tutorial. I think that as demand for WSL increases, this will become more popular!
I've been trying to get dual monitors working but there's something I must be missing. I think that it's a problem with WSL as the system only detects one monitor. Any ideas on this front?

@tdcosta100
Copy link
Author

tdcosta100 commented Aug 1, 2024

Since under the hood everything you see coming from WSLg is a RDP window, maybe configuring it to use all monitors will do the job, just like a regular RDP connection. If you manage to achieve this, you will be able to set a monitors.xml with 2 or more logical monitors, to match your physical screens. The RDP config file is located at C:\Program Files\WSL\wslg.rdp. You can also override the %USERPROFILE%\.wslgconfig file to point to other .rdp file, so the original will be untouched. The configuration contents may be like:

[system-distro-env]
WSL2_RDP_CONFIG_OVERRIDE=wslg_custom_file.rdp

The wslg_custom_file.rdp file must be in the directory C:\Program Files\WSL.

According to this, you can add the use multimon:i:1 setting in your custom RDP file. I don't have multiple monitors here to test if it works, so it's up to you to check if it works.

@aneeqkhurram007
Copy link

@tdcosta100 Thank you for the wsl setup, everything is working fine I'm getting the display, as I open libre office or ubuntu-dekstop I get "Oh no" error screen. I'm using Ubuntu 24 lts with wsl 2.

I've tried repeating the above setup twice, nothing helped

I tried journalctl logs but everything is fine there.

@tdcosta100
Copy link
Author

tdcosta100 commented Aug 12, 2024

Hi, @aneeqkhurram007. Unfortunately it happens with me too, I don't know the reason, maybe it's something related to MESA drivers, or something else, I don't know. Under Wayland it doesn't happens.

@aneeqkhurram007
Copy link

@tdcosta100 Thanks I'll try that out and is there any way to revert back to original state in wsl

@tdcosta100
Copy link
Author

@aneeqkhurram007, you have two options:

  1. Reset/reinstall your distro
  2. Undo the changes in this tutorial. However, you cannot undo the package installation of ubuntu-desktop.

@LILCOOTS
Copy link

Nothing seems to be happening after
sudo systemctl start graphical.target
what should i do?

image
image

@LILCOOTS
Copy link

There also seems to be an error for wslg applications.
image
I'm Fairly new to Linux. Please help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment