GitHub Codespaces: Developing GUI Applications 3/3

6 minute read

Third post of a series of three about running GUI applications on GitHub Codespaces.

The second post, GitHub Codespaces: Developing GUI Applications 2/3, showed you how to run a GUI application on a Codespace using VNC, this one will show you how to run a GUI application on a Codespace using X11 Server.

X11 (with forwarding)

The second way is to use X11 Server, and for which we will rely X11 forwarding, with forwarding we will be able to graphical interfaces of X11 programs running on a remote machine to be displayed on a local client machine without the need to have direct connectivity between the remote machine and the local machine. (X11 was designed from the start to be used over local network connection).

While this method is simpler to setup, and doesn’t place any load on the Codespace, it requires a X11 server on a machine you have access to (typically your machine, which we will consider for this example).

X11 server configuration

If you are using Linux (on a desktop) it is very likely that you already have a X11 server installed and running.

If you are using Windows you may need need to install one. If you are running Windows Linux Subsystem 2 then it has the capability to run X applications out of the box but you may need to configure it. See Run Linux GUI apps on the Windows Subsystem for Linux for more details.

If you are not running WSL2 you will need to install a X11 server. VcXsrv is a popular free choice and I’ve heard some praises on (paid) x410. (not endorsing any of them, just mentioning them as examples).

If you are using MacOS you will need to install a X11 server. XQuartz is a popular free choice.

I will personally use WSL2 for this example.

SSH configuration (client)

After you have a X11 server running on your machine, you need to configure SSH to forward X11 connections (using OpenSSH here, other clients configuration may be different) from Codespace to your machine.

Edit your SSH config file ($HOME\.SSH\config on windows and ~/.SSH/config in other systems) and add the following lines:

Host *
    ForwardX11 yes
    ForwardX11Trusted yes

This will tunnel X11 connections over SSH.

Note: This will enable X11 forwarding for SSH to all HOSTS (because of the *), which may not be advisable, specially on shared machines (which is not the case here). See the notice on ForwardX11 parameter description. ForwardX11Trusted is required to allow X11 forwarding for remote hosts which are not trusted (which is the case here), it is recommended you set this value to No and take the effort to configure XAuth (but will use true here for simplicity).

See ssh_config for more information (referencing OpenSSH docs which is the most used SSH client).

Connecting to the Codespace with SSH

With SSH client configured, now all we need to do is connect to the codespace via SSH. For that we will use the GitHub CLI, if you don’t have it installed, now it’s the time to do it.

Note: This requires SSH server running on the Codespace, since we are using the default image, it is already running. But you may need to install a server. You can run which sshd on the codespace to check if it is installed (not necessarly running though).

On your machine, execute the command gh codespace ssh -c CODESPACENAME and you will be connected to the Codespace via SSH (if you omit the -c CODESPACENAME then CLI will allow you to interactively select the Codespace you want to connect to).

See SSH into a codespace and gh codespace SSH for more details.

Note: if when you login you get the message X11 forwarding request failed on channel 0 then you need to install xauth on the Codespace. The simplest way wou can do that by adding the following line to your devcontainer.json file (when using a Debian/Ubuntu based image):

"postCreateCommand": "apt-get update && apt-get install -y xauth",

But there are other ways, like adding a Dockerfile to your repository and installing it there, or installing it manually after you login to the Codespace.

I will leave it as an exercise for you to figure out the preferred way of doing it.

This is the devcontainer.json file I used for this example (again using the default image):

{
    "image": "mcr.microsoft.com/devcontainers/universal:2",
    "postCreateCommand": "sudo apt-get update && sudo apt-get install -y xauth x11-apps x11-common"
}

Note: You can integrate Codespaces with OpenSSH so you can remote into your codespaces without the need to call the CLI. see for more info.

DISPLAY environment variable

In order for X Apps to connect to the X11 server, they need to know where it is, for that they use the DISPLAY environment variable (must X apps also allows to specify the display via command line parameters).

Most of the times you don’t need to set it since SSH does it for you, run echo $DISPLAY

Most of the times SSH will get it right, for example this is what I get when I run it on my Codespace:

$ echo $DISPLAY
localhost:10.0

So let’s try to run a X11 application, for example xlogo, a simple X11 application that displays the X logo. (part of the x11-apps package we installed earlier).

If all goes well you should see the X logo displayed on your machine and you can skip the next section (or read if you want to have a better understanding of DISPLAY variable)

xlogo running on top of `SSH` session in terminal

If the DISPLAY variable is not set or it’s incorrect you will see the following error:

$ xlogo
Error: Can't open display: :0

It’s time to understand how to fix this, read the next section.

Setting DISPLAY environment variable

Once we login we will need to set the DISPLAY environment variable to point to the X11 server. The value of the variable depends on the X11 server listening port. The value of environment variable follows the format [hostname]:displaynumber[.screennumber] (you can omit hostname for localhost and the screen number if it’s zero)

The X server is listening on port 6000 + display number, SSH does the port forwarding for us, so (tipically) we just need to set the DISPLAY variable to :10, by default SSH will forward the X11 connection to port 6010 (6000 + 10) to avoid conflicts with other X11 servers running on the machine itself. This value is defined in the X11DisplayOffset setting in the SSH server configuration file (/etc/SSH/sshd_config), since in our case it is not defined then it uses the default value of 10.

The display number is going to be must likely 10, but in case it isn’t, we can see which ports SSH is forwarning by executing the command netstat -tunlp |grep ':60'' and look for the port 6000 + display number.

In the example below we can easily see that the display number is indeed 10.

$ netstat -tunlp |grep ':60'
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:6080            0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN      -
tcp6       0      0 ::1:6010                :::*                    LISTEN      -

Based on the display number you have determined, set the DISPLAY variable to the correct value, in the case above we should use :10 (or localhost:10)

Now try again to run an X application.

You are done

You can test if everything is working by running X11 applications, perhaps you can install some Gnome or KDE to run something more modern than the old X11 apps or test your own GUI application.

Last Remarks

Using X11 is remarkly simple, there is almost a zero effort to configure and there is no desktop to manage all windows will just blend with your desktop as if they were a native application, the only requirement is that you keep the SSH session open.