Running X11 QGIS with Docker on a MacBook

Previous blogs on this site have highlighted the strengths and advantages of Docker. Docker is a great utility tool that allows ‘containerisation’ of a very wide range of applications, where the containers are used to build images that can be shared, running applications in a way that seals them off from the rest of your computer. This can prevent applications cross-corrupting each other, and also permit developed applications to be easily shared.

Most of the time, such applications are server based (e.g. databases and web servers), or command line (e.g. Python programming). However, some applications have a graphical user interface (GUI) for users to interact with. An example of such an application is the Free and Open Source Geographical Information System (GIS) tool QGIS. QGIS is able to create, edit, visualise, analyse and publish geospatial information. There is an installer on the QGIS website to allow installation of the software into the core operating system. With an Apple MacBook however, this installation has been found to sometimes corrupt other software installed, and also to become corrupted by other software. With a Docker image available on the Docker hub, this is clearly a good way to address this. But QGIS is a graphical tool, and so a key challenge is to direct the display output from the programme running in the docker container to the screen of the parent computer/laptop. Various advice exists for achieving this. The following steps then explain how to make QGIS work in this way – the principles can be used by other GUI-based software also.

The first step is to install the package manager homebrew on the MacBook. Homebrew is described as the ‘missing package manager‘ for Macs – and allows installation of a wide range of open source tools. The installation code is below – but also read up about homebrew at the link above. Here’s a great blog that covers the process of installing homebrew. All the commands below are run in the terminal window.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Once homebrew is installed, it can be used to install Docker itself. This command is run in terminal.

brew cask install docker

Next, we need to install the Xquartz utility with homebrew, Apples version of the X server.

brew cask install xquartz

Next, a utility called socat is installed, again with homebrew. Socat is used to govern the exchange of data between the X11 QGIS application in the container, and the display screen of the MacBook. One may encounter issues installing socat in this way – strangely many people report that their home broadband ‘child safe’ filters may prevent successful installation. If this occurs, temporarily disabling such services may help.

brew install socat

We are now ready to run the socat command that passes display communications from the docker container to the laptop screen. In a new terminal run the following command.

socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"

Next, we create a project folder where we can exchange data and project files in and out of the Docker container.

cd ~
mkdir qgisfolder
cd qgisfolder
touch run_qgis
chmod 775 ./run_qgis

Within this folder, create an executable script that will be used to run docker, to load the qgis image and direct the display output to the laptop screen. Edit ‘run_qgis’, and add the following lines:

# Run QGIS
# Allow connections from any host
xhost +
# Run the Docker command to run qgis
docker run --rm -it --name qgis \
    -v /tmp/.X11-unix:/tmp/.X11-unix  \
    -v $(PWD)/qgisfolder:/data \
    -e DISPLAY=`ipconfig getifaddr en0`:0  \
    qgis/qgis:latest qgis

The xhost command adds or deletes host names on the list of machines from which the X Server accepts connections. ‘xhost +’ grants access to everyone, even if they aren’t on the list (i.e., access control is turned off).

The docker run command will commence a docker session. Note that where a docker image is referenced (e.g. here, qgis/qgis:latest), then if the image is not currently available on the computer, it is downloaded. So the very first time this is run, the download process starts. At 7.8Gb this can take a while – but it is all automatic and is only run the once. The backslashes are used to wrap a long command line over several lines for readability. The parameters in the command are then as follows:

--rm      removes any anonymous volumes associated with the container when the container is removed
-it       For interactive processes (like a shell), you must use -i -t together in order to allocate
          a tty for the container process. -i -t is often written -it
--name    An assigned container name
-v        Permit bind mounts (see this blog to explain) from:to
-e        Set an environment variable in the container

ipconfig getifaddr en0     (surrounded by the quote symbol `), this is a command that returns the IP of the laptop (which can also be specified manually and explicitly if preferred. The ':0' is the display number, so an explicit IP might be for example '123.456.890.123', thus    -e DISPLAY=123.456.890.123:0

With socat running in a first window, start a second terminal window to run the script in. Hopefully, when this command is run (./run_qgis), QGIS will appear on the screen!

QGIS Screen

Due to the use of the bind mount above (the ‘-v’ settings), all files created within qgis and saved to /data will appear on the laptop in the work folder ~/qgisfolder (and vice versa) – ‘~’ being your home folder.

Uninstalling qgis if needed is as simple as removing the Docker image – simple! Using the image ‘qgis/qgis:latest’ ensures that the version of QGIS run at any time is the latest one.