I've been using neovim-from-scratch as my IDE recently, and its incredibly brittle. This post takes some baby steps toward getting any desktop GUI app running in a docker container to run on my screen in Ubuntu 20.04. Eventually, I want to get this working on MacOS and using nvim, but for today we're trying to get any GUI application running on my screen in Ubuntu.

X11 Basics

  • X11 runs as server on the local users workstation
  • Desktop applications run as clients, possibly on a remote machine
  • X11 clients and server communicate over a TCP connection

Given this architecture, running a GUI inside in a docker container should be fine from X11 perspective. It's simply a matter of getting the correct networking setup and configuring the client to communicate with the X11 service.

Networking 101

The simplest path to something that works is to share the host network with the docker container. This is not the most secure and we can definitely do better. But doing so will require us to learn more about how X11 clients and servers communicate. The risk is that we could allow malicious applications to impersonate us on the internet by using our IP address and network location. Additionally, the dockerized application could access anything on our own machine over the network. Longer term, locking down to minimum number of X11-specific ports should stop these risks.

To tell docker run a container with host networking we do:

docker run --net host ...

Pointing our client application at the X11 Server

X11 clients read the DISPLAY environment variable to discover the X Server. DISPLAY generally takes the form: <hostname>:<display number>. The default value is typically :0 -- meaning use display 0 on the localhost. However, on my machine I see DISPLAY is set to a higher number. The easiest way to make sure the docker container has the correct DISPLAY value is to pass that variable from the host to the container:

docker run -e DISPLAY

Xeyes

We'll use the xeyes application as a simple test that things are working. A docker image exists for this at fr3nd/xeyes.

Testing It Out

Let's open a terminal and do this:

docker run --rm -ti --net=host -e DISPLAY fr3nd/xeyes

If all is well, you should see some crazy eyes in a window following your mouse around. Success!

Getting Fancy

Now to put a cherry on top, we'd like to create a desktop icon we can use to launch the crazy eyes application without doing arcane docker magic. After much fumbling, I've discovered this magic:

[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/usr/bin/docker run --rm --net=host -e DISPLAY fr3nd/xeyes
Name=xeyes

Save the above inside xeyes.desktop on your desktop. You'll also need to right-click on this icon and choose "Allow Launching" before this will work. Double click the icon and you should see the same crazy eyes appear!

Caveats

  • Tested on Ubuntu 20.04 LTS -- results may vary on other versions of Ubuntu
  • docker run must not contain -it or else you must use a terminal which is very annoying
  • The full path to docker without any ~ must be set in Exec
  • DISPLAY will only work like this because we're running Linux inside and outside the container on the same machine with shared networking. Don't expect this value of DISPLAY to work on MacOS

Helpful Source Material

  • Nassos Michas post
  • This stackoverflow post concerning permissions
  • This very specific stackoverflow post concerning eliminating terminals from showing up