Running X11 applications like xeyes in Docker
Running xeyes is a useful proof of concept useful for containerizing applications which need UIs.
- Author:
- Christian Hujer, Software Crafter and CEO / CTO of Nelkinda Software Craft Private Limited
- First Published:
- by
Nelkinda Software Craft Private Limited - Last Modified:
- by Christian Hujer
- Approximate reading time:

xeyes in DockerRunning xeyes in Docker seems a bit like an unnecessary stunt. True, running xeyes in Docker has no practical purpose in itself. But the whole point is actually not about xeyes. It is about how to get an X11 application running in Docker in general.
1 Purpose
I came across this problem when I actually wanted to do something else. For a client project, I need to setup a IBM Lotus Domino server and fill it with sample data. It seems that without a GUI, performing this setup ranges from hassle to impossible. Whether something is good server software if it can't be configured from a terminal window is a different story. Hello, IBM, are you listening? I already messed up my system once when trying to get IBM Lotus Notes installed to administer IBM Lotus Domino. I didn't want this to happen again. So I thought of containerizing the two IBM Lotus applications. But when doing so, there is a challenge: How do I get the UI of the IBM Lotus applications from within Docker display on my Docker host? I could've used VNC. But mind you, I'm running Linux inside Linux, so why not use X11 directly?
So, the purpose of running xeyes in Docker is a proof of concept. There are many things why running applications inside Docker could go wrong. X11 is one of the things that can go wrong. With running xeyes in Docker, there is a proof of concept that running X11 applications inside docker works. It helps isolating and fixing one problem at a time.
2 Ingredients
The ingredients are:
- The Linux kernel, providing containerization support.
- The X11 system, with an X11 server running on the Linux host.
- Docker, to run software in containers using
docker run. xeyesto be run inside a container.
2.1 X11 Considerations
You should only run applications this way which you trust. The applications in the container will be able to use X11 to intercept mouse and keyboard. For example, they could perform key-logging. So, only do this with trust-worthy applications.
If your reason for containerization is not security, it's just fine. But if the reason for containerization was security, you should probably prefer VNC over X11.
3 The Dockerfile
The Dockerfile has to do the following things:
- Use a Linux distribution that has
xeyesavailable as a base. - Install
xeyes - Create and use a user named
user, we don't want to run X11 applications asroot. - Specify
xeyesas entry point.
FROM debian:latest RUN apt-get update && apt-get install -y x11-apps RUN rm -rf /tmp/* /usr/share/doc/* /usr/share/info/* /var/tmp/* RUN useradd -ms /bin/bash user ENV DISPLAY :0 USER user ENTRYPOINT ["/bin/sh", "-c", "$0 \"$@\"", "xeyes"]
Dockerfile to run xeyes3.1 Explanation
- The
FROM debian:latestselects the latest version of Debian. I do not use this image in production, otherwise I would pin down the version. - The
RUN apt-getline updates the package index. Then it installsx11-apps, which is the package that containsxeyes. - The
RUN rm -rfline removes a bunch of files that are not needed for this proof of concept. This is not necessary. It's an easy way to reduce the image and container size a bit. - The
RUN useraddline creates a user nameduser. - The
ENVline declares an environment variableDISPLAYand sets it to:0. This is not really necessary at this stage, but provides some convenience when running the container. With this line, it will be possible to run the container without specifying theDISPLAYvariable when its value would be:0. AndDISPLAYis:0most of the time. - The
USER userline ensures that subsequent commands (and thus the container) are run as useruser. - The
ENTRYPOINTline specifies that the container should runxeyes.xeyesis not run directly but wrapped with a shell (/bin/sh), so that Ctrl+C will work and stopxeyes. Furthermore, the way how the shell is wrapped, container command arguments will be forwarded toxeyes. That way it will be possible to specify the geometry of the xeyes window, for example.
For more information what these Dockerfile commands mean and how they work, refer to [Dockerfile].
You can build the container with docker build -t my-xeyes
4 Running it
The first attempt to run the image would look like this:
$ docker run -it --rm --name xeyes my-xeyes No protocol specified Error: Can't open display: :0 $ echo $? 1
The error message means that xeyes in the container was unable to connect to the X11 server. There are two to three reasons for this.
- There is no
.Xauthorityconfigured for the useruserinside the container. - The docker container is running in a separate network, not the host network.
- The
DISPLAYmight be something else than:0.
We need to share the current user's .Xauthority with the xeyes docker container. For that, we can simply mount the .Xauthority file as volume. But there's a caveat: The user user inside the container has id 1000. The id of the current user might be different. So we need to grant access to the user user by granting access to 1000.
To grant access, run setfacl -m user:1000:r ${HOME}/.Xauthority. The volume is configured by adding -v ${HOME}/.Xauthority:/home/user/.Xauthority to docker run.
Note what this means. Such volumes are file system sharing between the host and the container. For such shared file systems, the user ids between the container and the host need to match.
These steps alone will not yet work. The .Xauthority file is shared successfully, but X11 will still deny access. The reason is that the docker container thinks it's a different machine than what was configured automatically in the .Xauthority during login. You can change what the docker container thinks of networks. Add the option --net=host to the docker run command.
To see the full command sequence, look at the next chapter, which shows a shell script for convenience.
5 Shell Script for Convenience
The following shell script contains all the commands to run xeyes in docker.
#!/bin/bash
setfacl -m user:1000:r ${HOME}/.Xauthority
docker build -t my-xeyes .
exec docker run \
-it \
--rm \
--name xeyes \
--net=host \
-e DISPLAY \
-v ${HOME}/.Xauthority:/home/user/.Xauthority \
my-xeyes \
"$@"
xeyes_in_docker.sh, a shell script to run xeyes in Docker5.1 Explanation of the Shell Script
- The
setfaclcommand grants read access to the current host user's.Xauthorityfile to user1000. User1000is the user which was created in the container by theDockerfile. This read access is needed so that the container's user can access the.Xauthorityfile. The.Xauthoritycontains the X11 session credentials cookie which is used to authenticate connections to the X11 display server. - The
docker buildcommand builds the image from theDockerfileand stores it in the local registry under the namemy-xeyes. - The
exec docker runcommand replaces the current shell withdocker. Thedocker run my-xeyescommand runs a docker container from the previously created docker imagemy-xeyes. Options and Arguments explained:-it(interactive terminal) tells Docker to run an interactive terminal. This way, the container will behave like a command in the current shell.--rm(remove) tells Docker that the container will not be needed after it stopped and thus can be deleted automatically.--name xeyesgives the Docker container a name for reference by other Docker commands. This is probably not needed in this case, but still helpful.--net=hostconfigures the network of the Docker container to use the host network. This is the simplest way to get access to X11.-e DISPLAYforwards theDISPLAYenvironment variable to the container. That variable contains the information about which display server to use. Mind you, that Unix systems could in theory run multiple display servers in parallel.-v $(HOME}/.Xauthority:/home/user/.Xauthoritymakes the current host user's.Xauthorityfile visible to the useruserin the Docker container.my-xeyesis the name of the image from which to create the container. It is the name of the image used in the previousdocker buildcommand."$@"forwards the command line arguments to the container.
5.2 Examples
./xeyes_in_docker.sh./xeyes_in_docker.sh -geometry 1000x500
6 Limitations and Alternatives
As already mentioned, there is a security consideration around X11 applications. Besides, this solution only works in situations where the host runs X11 directly. This means success is almost guaranteed if the host that runs docker runs X11 itself. That is the case on Linux and FreeBSD. On other operating systems, such as Mac OS X and Windows, further steps would be required.
There are at least two options in that case.
- Using X11 with more effort. If you use X11 on Mac OS X or Windows, you can still get this to run. But you will need to modify the
DISPLAYenvironment variable, and potentially do other things as well, maybe usingxauthorxhost. - Use VNC.