Running GUI Applications in a Docker Container This article explains how to run GUI applications inside a Docker container, primarily to isolate an application's dependencies from the host system. The main challenge is enabling the container to communicate with the host's display system via X11, which requires mounting the X11 socket and using host networking. The guide uses the Pinta paint program as an example, detailing the steps to install the application in a container and configure the necessary permissions for graphical output. Running GUI Applications in a Docker Container Containers are not usually associated with GUI applications, but there may be times when one might still want to run such a program inside a container, for example to isolate the application's dependencies . Installing a GUI application in a container means that not only the application, but also all its specific dependencies are encapsulated inside the container respectively, the container image , and can therefore reliably be removed from the system in a single step. The primary challenge is to let a container communicate with the host's display system, so that it can create GUI windows on the host. A GUI application will likely also need to share files with the host system, which in turn requires the appropriate user permissions. In this example, I will use the pinta https://github.com/PintaProject/Pinta paint program, which requires the Mono runtime. I do not use any other programs that depend on Mono, and as I like to keep my system installation relatively clean, I would like to isolate the application and its libraries as much as possible. Getting a GUI application to run in a container requires several distinct steps: 1. Installing the application and its dependencies in a container. 2. Letting the application and the host's window system talk to each other. 3. Creating an image of the installed application for later use. 4. Optional: Letting the application and the host share files. This assumes that Docker or an equivalent container management system is already installed and running on the host, and that the user has the necessary permissions to use it. To distinguish which commands are issued on the host, and which are issued in an interactive container session, the respective prompts are shown in the examples below Also, this example assumes a Linux environment throughout. Installing the Application The first step is to obtain a suitable base image. Here, we will use Ubuntu: host docker image pull ubuntu:jammy Next, we log into the container and install the desired application. We could simply run the container using docker container run --rm -it ubuntu -it means to run an interactive session and to attach a terminal, --rm will shut down and remove the container once the interactive session ends , but instead we will use the following command, so that the container can access the graphical display later. This will be explained in the next section. host docker container run --rm --net host -v /tmp/.X11-unix:/tmp/.X11-unix -it ubuntu Now we can install the desired application: container apt update container apt install -y pinta The installation process will ask for the current timezone; enter the appropriate information. Sharing the Screen Attempting to run pinta from within the container at this point will most likely fail. For an application to launch a window requires three things: - The application the "client" must know how to talk to the windowing system the "server" or "display server" . - The application must have appropriate permission to access the server. - The application must tell the server where the window should appear. On Unix, running X11, local client applications usually communicate with the display system via a Unix domain socket . A domain socket is visible in the fileystem; and the one used for X11 communication is found in the directory /tmp/.X11-unix/ . The -v option provided when starting the container created a "bind mount": a directory on the host system has been mapped to a directory of the filesystem inside the container. The path before the colon refers to the host filesystem; the path after the colon refers to the container filesystem. Here the respective paths are equal, later we will see an example where this is not the case. For the client inside the container to be able to communicate with the display server on the host also requires to use the "host" networking mode, as specified by --net host . An application not only needs to be able to communicate with the display server, it also needs to authenticate itself. There are several different ways for X11 applications to authenticate themselves to the server; for now, we will use one of the simplest. On the host, issue the command: host xhost +local: This allows any local application to access the display server. If you are paranoid, you may want to switch this behavior off by issuing the command xhost -local: when you have shut the GUI application and container down. Finally, we need to tell the application which display to use. This is done via the DISPLAY environment variable inside the container: container export DISPLAY=:0 Now, you should be able to execute the command: container pinta and have the window appear on your screen. Creating an Image We can create and save an image of the currently running container. This way, we will be able to run the application without having to to go through the entire installation process again in the future. On the host, run docker container ls to find the ID of the running container, and then still on the host , create an image of the container by feeding its ID to docker's commit command substitute the real ID, of course : host docker commit