X11 windows with Docker Desktop.

Using Docker to test X11 Applications on Windows and MacOS

Some Github repositories now produce docker images and automatically store them in Github’s own container registry, ghcr.io. I had a github repo CI action generate an image of Debian Bullseye with the latest dev branch of RawTherapee and tested new instructions for launching X11-capable linux apps like RawTherapee:

Launching ghcr.io/kd6kxr/rawtherapee_docker-image


Windows 11 Pre-requisite: Install the Linux Subsystem for Windows via the Microsoft Store.

  1. Install Docker Desktop

  2. Login to Github Container Registry with your own Github username and a properly scoped token:

docker login -u username -p token ghcr.io

  1. Download rawtherapee_docker-image:
$ docker pull ghcr.io/kd6kxr/rawtherapee_docker-image:latest

Windows 11+:

Pre-requisite: Install an X11 Window System: Xming

  1. Launch Xming by double-clicking the :heavy_multiplication_x: Xming app icon.
In Docker Desktop:
  1. Select the image in the Images tab and click Run.
  2. Enter the volumes to map and the DISPLAY environment value host.docker.internal:0
    config options

Result: a resizable RawTherapee window.

On MacOS 11+:

Pre-requisite: Install an X11 Window System: XQuartz

  • In XQuartz app, set the Preferences>Security>Network Connections button to On.
  1. In Terminal, launch an xterm window: /opt/X11/bin/xterm
  2. In the xterm window, start the localhost listener:
xhost +localhost
/opt/X11/bin/Xquartz -depth 24-1 :0 -listen tcp &
In Docker Desktop:
  1. Enter the volumes to map and the DISPLAY environment value host.docker.internal:0
    config options

Results in an optimized RawTherapee window.


if the screen is unresponsive at first

The Dockerfile

The Dockerfile is simple Go and resides at the root level of the repository. It indicates to start off with Debian’s bullseye image, configure and build rawtherapee, and set it up to be launched on command.

FROM debian:bullseye

#   add the dependencies

RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends build-essential locales cmake git curl libcanberra-gtk3-dev libexiv2-dev libexpat-dev libfftw3-dev libglibmm-2.4-dev libgtk-3-dev libgtkmm-3.0-dev libiptcdata0-dev libjpeg-dev liblcms2-dev liblensfun-dev liblensfun-bin liblensfun-data-v1 libpng-dev libsigc++-2.0-dev libtiff5-dev zlib1g-dev librsvg2-dev ca-certificates ssl-cert -y

#   prepare the environment

RUN locale-gen C.UTF-8

#   clone source code, checkout the dev branch

RUN mkdir -p ~/programs && git clone http://github.com/Beep6581/RawTherapee.git ~/programs/code-rawtherapee && cd ~/programs/code-rawtherapee && git checkout dev

#   update lensfun
RUN cd ~/programs && lensfun-update-data

#   configure build system and compile

RUN cd ~/programs/code-rawtherapee && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE="release" -DCACHE_NAME_SUFFIX="" -DPROC_TARGET_NUMBER="1" -DBUILD_BUNDLE="ON" -DBUNDLE_BASE_INSTALL_DIR="$HOME/programs/rawtherapee" -DOPTION_OMP="ON" -DWITH_LTO="ON" -DWITH_PROF="OFF" -DWITH_SAN="OFF" -DWITH_SYSTEM_KLT="OFF" ..
RUN cd ~/programs/code-rawtherapee/build && make -j$(nproc --all) && make install

#   set the entrypoint command

LABEL maintainer="kd6kxr@gmail.com"
CMD echo "This is a test..." && ~/programs/rawtherapee/rawtherapee && echo "...end of test."


The workflow file is in Yet Another Markup Language, and sets up the repository to build RT-dev. The Ubuntu runner builds the app system and pushes the final image to the registry. The script conveniently accesses two built-in secrets belonging to the user account: username and an access token, automatically. The workflow gets tucked away inside the /.github folder structure.

name: Docker Image CI

    branches: [ "main" ]
    branches: [ "main" ]



    runs-on: ubuntu-latest

    - uses: actions/checkout@v3
    - name: Login to GitHub Container Registry
      uses: docker/login-action@v2
        registry: ghcr.io
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    - name: Build image and push  
      run: |
            docker build . --file Dockerfile --tag ghcr.io/kd6kxr/rawtherapee_docker-image:latest
            docker push ghcr.io/kd6kxr/rawtherapee_docker-image:latest

Extra credit:

A test of the metadata-exiv2 feature branch on Debian bullseye with Docker:

docker pull ghcr.io/benitoite/rawtherapee_docker-image:latest

It has both x86_64 and arm64 builds.


Hmm, interesting that xming was needed on a recent WSL setup now that they’ve significantly increased graphical support in WSL. Unless that is something that was driven by Docker being part of it.

For people stuck with older versions of windows (such as enterprise users…), gWSL works even on ancient WSL2 setups. (yeah, at this point, earlier variations of WSL2 can be considered almost as ancient as WSL1…)


What I think is going on in my case is I have WSL2 installed first as a backend requirement for Docker Desktop. In the default status the host display is not found by the X11 server unless I have Xming running. I have not investigated any other WSL2 X11 procedures, rumors about which I have read recently.

We’ve used X via RDP with WSL, without Docker.


provides many hits.

I personally enjoyed what X410 by Chuong Networks brought to the table, especially alongside Token2Shell.