Skip to content

Instantly share code, notes, and snippets.

@paul-krohn
Last active March 23, 2024 09:30
Show Gist options
  • Star 42 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save paul-krohn/e45f96181b1cf5e536325d1bdee6c949 to your computer and use it in GitHub Desktop.
Save paul-krohn/e45f96181b1cf5e536325d1bdee6c949 to your computer and use it in GitHub Desktop.
Docker X11 macOS

Preamble

There is a longstanding issue/missing feature/bug with sockets on Docker on macOS; it may never work; you'll need to use a network connection between Docker containers and X11 on macOS for the foreseeable future.

I started from this gist and made some adjustments:

  • the volume mappings aren't relevant/used, due to the socket issue above.
  • this method only allows X11 connections from your Mac, not the entire local network, which would include everyone on the café/airport WiFi.
  • updated to include using the host.docker.internal name for the the container host, instead.
  • you have to restart XQuartz after the config change.

Assumptions

  • you have a docker image with x11-apps (or the equivalent for not-ubuntu) installed
  • you have XQuartz installed (ie from Homebrew, brew cask install xquartz) and your PATH updated to include /opt/X11/bin and/or /usr/X11/bin.

Set up XQuartz

  1. Launch XQuartz. Under the XQuartz menu, select Preferences
  2. Go to the security tab and ensure "Allow connections from network clients" is checked.
  3. Restart XQuartz.

Every time you want to run an X11 program

  1. Make sure X11 is accepting connections from your host with xhost +$(hostname).local (if your Mac's name is So-and-So's Computer, you will need to do some fancy quoting and escaping).
  2. Set your DISPLAY environment variable to :0, eg export DISPLAY=:0.
  3. Test it from your Mac with xeyes.
  4. It works? Cool, one step fancier, from a container: docker run --rm -e DISPLAY=host.docker.internal:0 -it some-container-name xeyes
@falcorocks
Copy link

Thank you, this may help others:

  • xquartz is not available on brew, but can be installed with cask brew cask install xquartz
  • xhost and xeyes will not work withouth fixing PATH, but they can be called with full path /usr/X11/bin/xhost, /usr/X11/bin/xeyes

@paul-krohn
Copy link
Author

Thanks @falcorocks; I had done some of these steps many moons ago.

@jack89roberts
Copy link

jack89roberts commented Jun 12, 2020

Thanks for this!

I had to add the line <LOCAL_IP> <HOSTNAME>.local to my /etc/hosts file for this to work, where <LOCAL_IP> is your local IP address (e.g. from ipconfig getifaddr en0) and <HOSTNAME> is whatever you get back from echo $(hostname). Without doing this I was getting a bad hostname error from xhost +$(hostname).local.

@glennchid
Copy link

@jack89roberts; xhost +localhost also seems to work, and is less reliant on a static host ip address.
Thanks @paul-krohn for the write-up. I also found (after lots of trial and error) that I did not need to set the DISPLAY variable on the host, and the default value on my system/private/tmp/com.apple.launchd.zEK89jAgFe/org.macports:0 worked okay.

@jack89roberts
Copy link

Thanks and hi @glennchid ! 👋 🙂

@MohammadJavadD
Copy link

Thanks, it works for me!
I have a question. The reason we decided to use Docker was to make our code works in different OS. But it seems we need to install and config display for each OS (Linux, Mac and Window). So Does it make sense to use Docker? How to manage this?

@akauppi
Copy link

akauppi commented Jul 26, 2021

@MohammadJavadD I think it depends on what you are trying to simplify. For many technical projects (you seem to be in university, for example), it likely makes sense to focus on one development platform and this is a way to that. By the end of 2021, Windows 10 has WSLg so Linux GUIs can be run ”just so”. That leaves macOS, the instructions for which are here.

@richtong
Copy link

richtong commented Sep 18, 2021

OK on Big Sur 11.6 with Xquartz 2.8.1 and Docker for Mac 3.3.3, I followed the instructions and tried

docker run --rm -e DISPLAY=host.docker.internal:0 -it jess/firefox

And I got this error

Unable to init server: Broadway display type not supported: host.docker.internal:0
Error: cannot open display: host.docker.internal:0

However reading another guide at https://lmiller1990.github.io/electic/posts/20201119_cypress_and_x11_in_docker.html I tried to just use the MacOS IP address to the external network. This didn't make sense to me because it has a port on the outside and then one to the internal network to the docker vm, but it did work?!@

ghost +$HOSTNAME
docker run --rm -e DISPLAY=$(ifconfig en0 | grep "inet " | cut -d ' ' -f 2)l:0 -it jess/firefox

Just worked

@richardrl
Copy link

This guide is awesome, confirms works. I followed the section after "Every time you want to run an X11 program...". Additionally, I manually added the hostname using xhost +(hostname) where (hostname) is copy pasted from typing "hostname" into the terminal.

@zeldin
Copy link

zeldin commented Aug 19, 2022

Instead of xhost +localhost, you can use xauth for even better security.
First, you need to copy the magic cookie for :0 so that it is used also with the magic host.docker.internal address (192.168.65.2):

xauth add $(xauth list $DISPLAY | awk '{$1="192.168.65.2:0"; print}')

Then, add -v ~/.Xauthority:/tmp/.Xauthority -e XAUTHORITY=/tmp/.Xauthority to the Docker command line. Now it should work without xhost.

@arvganesh
Copy link

arvganesh commented Mar 14, 2023

Tested on MBP with an M1 Pro, OS X 12.5. Everything still works.

Details:

  • Used xhost + localhost in the XQuartz terminal.
  • Used -e DISPLAY=host.docker.internal:0 when running the container

I was trying to run a gymnasium environment which needed to use indirect GLX from within the container, so I had to run this command in my terminal on OS X: defaults write org.xquartz.X11 enable_iglx -bool true.

@rizvanovic
Copy link

M1 Pro macOS Monterey 12.3, works here too. Simply adding "-e DISPLAY=host.docker.internal:0" to runArgs fixed it.

Mounting the volume like you would on a linux machine - "--volume=/tmp/.X11-unix:/tmp/.X11-unix", with a containerEnv for the display - worked on my macOS machine for a couple months. Stopped working for some reason but this way works.

Appreciate the thread and gist.

@fabianem
Copy link

fabianem commented Nov 17, 2023

Instead of xhost +localhost, you can use xauth for even better security. First, you need to copy the magic cookie for :0 so that it is used also with the magic host.docker.internal address (192.168.65.2):

xauth add $(xauth list $DISPLAY | awk '{$1="192.168.65.2:0"; print}')

Then, add -v ~/.Xauthority:/tmp/.Xauthority -e XAUTHORITY=/tmp/.Xauthority to the Docker command line. Now it should work without xhost.

Unfortunately, this is not working for me.
How can I get it to work without using xhost + localhost every time?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment