Run Linux/X11 apps in Docker and display on a Mac OS X desktop

; Date: December 10, 2019

Tags: Docker

While the MacPorts and Homebrew projects bring many Linux apps to the Mac environment, they don't support every app we'd want to run. Since the X11 environment is not native to macOS it's not a simple recompile, since you have to rewrite the GUI system. Thankfully there is an X11 display server for Mac OS X that can be used to run an application in a Linux environment and display it on the macOS desktop. In this article we'll look at one way to get this all connected up and running.

We need to start with a little bit of background.

Since the 1980's the Unix/Linux/FreeBSD/etc ecosystem has used the X11 windowing system to display GUI applications. The architecture is different from both Windows and Mac OS X GUI environments. The X11 architecture allows an application to run on a distant computer, and be displayed on another computer, in addition to the typical case where the application is displayed on its local computer. In other words, the X11 GUI architecture generalized the connection between application and graphics display, allowing both to run on any computer connected to the Internet, and for the graphics interaction to run across the Internet.

In this case the desire is to run an X11 application on Linux - one which isn't supported by either MacPorts or Homebrew.

We can set up a Docker container with that application. Since the Docker container is a Linux environment the GUI subsystem is X11. Because X11 allows an X11 application to display on any X11 display server, all that's needed is

  • A docker container with the desired Linux GUI application installed
  • An X11 display server on a macOS computer
  • Suitable authentication and permissions suitable for the Linux app that's running inside the Docker container

It is also possible to implement this using Canonical's Multipass environment which makes it easy to run Ubuntu virtual machines on Mac OS X or on Windows. See: Use Canonical's Multipass to display Linux GUI applications on macOS desktop

A Docker image for a Linux GUI application

Since Docker builds container images using regular Linux distributions, it's possible to install any application. The package manager will automatically ensure all needed packages are installed. While we normally think of Docker to run server applications with no GUI, there's no reason that GUI applications cannot be installed.

Consider this Docker image:

FROM ubuntu:14.04

RUN apt-get update
RUN apt-get -y install firefox

CMD ["firefox"]

That's Ubuntu - we really should update that to 18.04 or something but what the heck. The point is that apt-get install firefox will install all dependencies required to run Firefox, including the X11 libraries and everything else. The last step, to launch the firefox binary, causes Firefox to run and attempt to connect with an X11 display server.

XQuartz - an X11 display server for Mac OS X

The phrase "X11 display server" is how the X11 team describes an X11 display. The GUI application is seen to be a client application, displaying its GUI on an X11 display which is the server. Hence "X11 display server" is the correct phrase.

The XQuartz project describes itself as:

The XQuartz project is an open-source effort to develop a version of the (x.org) X.Org X Window System that runs on OS X. Together with supporting libraries and applications, it forms the X11.app that Apple shipped with OS X versions 10.5 through 10.7.

Apple used to ship an X11 display server with Mac OS X, but at some point stopped. This team keeps that software working.

XQuartz is available through Homebrew and MacPorts if you prefer. But you can download a DMG directly from (www.xquartz.org) https://www.xquartz.org/

Simply download the application and install it.

It's recommended to reboot your computer before doing the rest.

Run the XQuartz application, then in it's application menu you'll find a Preferences choice. In the Preferences make this setting:

Namely - Allow connections from network clients. This opens the display so it accepts X11 connections from any non-local computer. The Docker container we're about to create counts - as would a Linux machine in your office.

An X11 display server for Windows

In case you're a Windows user, the VcXsrv Windows X Server is available at this address (sourceforge.net) https://sourceforge.net/projects/vcxsrv/

Running the Docker container, passing along X11 authentication

Since it would be extremely insecure for X11 displays to allow any application access to the display - there is security built in to the X11 protocol. We don't have space to go into all the details of configuring X11 security. Let's just take the happy path and document what works.

The first thing is determining your IP address, which you can do like:

$ ifconfig -a
...
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    options=10b<RXCSUM,TXCSUM,VLAN_HWTAGGING,AV>
    ether a8:20:66:38:a9:16 
    inet6 fe80::10df:8cae:6021:5491%en0 prefixlen 64 secured scopeid 0x8 
    inet6 2600:1700:a3a0:6e40:1853:7294:6085:e00a prefixlen 64 autoconf secured 
    inet6 2600:1700:a3a0:6e40:1ce5:80ee:164:c033 prefixlen 64 autoconf temporary 
    inet 192.168.1.89 netmask 0xffffff00 broadcast 192.168.1.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect (1000baseT <full-duplex,flow-control,energy-efficient-ethernet>)
    status: active
...

Notice the line reading inet has my IPv4 address, and the lines reading inet6 have my IPv6 address. We'll use the IPv4 address.

This magic shell command gets the IP address into an environment variable:

export IP=$(ifconfig en0 | grep inet | awk '$1=="inet" {print $2}')
$ echo $IP
192.168.1.89

With XQuartz running ... execute these commands:

$ xhost +$IP
$ docker run --rm  --name firefox -e DISPLAY=$IP:0 -e XAUTHORITY=/.Xauthority --net host -v /tmp/.X11-unix:/tmp/.X11-unix -v ~/.Xauthority:/.Xauthority  jess/firefox

The xhost command configures XQuartz to allow connections from the given IP address. I had to install xhost using MacPorts.

This command imports various security settings and files into the container. The XQuartz application creates the .X11-unix directory and the .Xauthority file. By importing them into the Docker container we've injected the security bits contained in both. That simplifies setting up the security authentication required.

The DISPLAY variable instructs X11 applications which display server to connect to. This instructs the Firefox application to connect with the XQuartz display on the Mac OS X machine.

The XAuthority file is used in authentication. The .X11-unix thing contains a Unix-domain socket:

$ ls -l /tmp/.X11-unix/X0 
srwxrwxrwx  1 david  wheel  0 Dec 10 11:27 /tmp/.X11-unix/X0

If you get an error: XDG_RUNTIME_DIR not set in the environment .. add this to the Docker command line: -e XDG_RUNTIME_DIR=/tmp/xdgr

So long as you get the message cannot open display: 192.168.1.89:0 then something is configured incorrectly with the authentication. The above authentication bits worked for me. An additional command that may be helpful is:

$ xhost +local:docker

Running the above command we get this - Firefox for Ubuntu displaying on a Mac OS X desktop.

About the Author(s)

David Herron : David Herron is a writer and software engineer focusing on the wise use of technology. He is especially interested in clean energy technologies like solar power, wind power, and electric cars. David worked for nearly 30 years in Silicon Valley on software ranging from electronic mail systems, to video streaming, to the Java programming language, and has published several books on Node.js programming and electric vehicles.