Skip to content

Instantly share code, notes, and snippets.

@cschiewek
Last active November 6, 2024 12:03
Show Gist options
  • Save cschiewek/246a244ba23da8b9f0e7b11a68bf3285 to your computer and use it in GitHub Desktop.
Save cschiewek/246a244ba23da8b9f0e7b11a68bf3285 to your computer and use it in GitHub Desktop.
X11 in docker on macOS

To forward X11 from inside a docker container to a host running macOS

  1. Install XQuartz: https://www.xquartz.org/
  2. Launch XQuartz. Under the XQuartz menu, select Preferences
  3. Go to the security tab and ensure "Allow connections from network clients" is checked.
  4. Run xhost + ${hostname} to allow connections to the macOS host *
  5. Setup a HOSTNAME env var export HOSTNAME=`hostname`*
  6. Add the following to your docker-compose:
  environment:
  - DISPLAY=${HOSTNAME}:0
  volumes:
  - /tmp/.X11-unix:/tmp/.X11-unix

* It should be noted that steps 4 and 5 can be automated to run everytime XQuartz starts, but that's outside of the scope of this gist

@loadaverage
Copy link

loadaverage commented Mar 27, 2018

Seems that ${hostname} is not correct, should it be ${HOSTNAME} or $(hostname)?
Anyway, I have troubles while trying binding X11 to UNIX socket, network connections works fine.
But it's not so comfortable for me.
UPDATE: nevermind, UNIX sockets are not supported yet
So, xhost or socat (UNIX socket->localhost port) is the only way to go.

@jamestclin
Copy link

Works well!

@DrSnowbird
Copy link

For my MacOS docker run to display X11, I need to set up docker run with "-e DISPLAY=host.docker.internal:0" and then it works!

@vmayoral
Copy link

vmayoral commented Oct 29, 2019

+1 to -e DISPLAY=host.docker.internal:0 from @DrSnowbird, it seems that after the last Docker security updates, that form works and previous ones do not anymore.

@xeonqq
Copy link

xeonqq commented Dec 24, 2019

Instead of step 4, I have to do the following:

IP=$(ifconfig en1 | grep inet | awk '$1=="inet" {print $2}')
/usr/X11/bin/xhost +
/usr/X11/bin/xhost + "$IP"

and +1 also to DrSnowbird

@paul-krohn
Copy link

Thanks for this, it really helped me out!

It seems things have moved a bit underneath all this since 2017, so I created an updated version.

@dragon788
Copy link

@xeonqq the first line you have allows ANY IP to access your X11 display not just the IP you added on the next line.

@theRealSuperMario
Copy link

I created a small example for running firefox inside a docker container here. If this fires up firefox on your mac, you are good to go.

@dozzman
Copy link

dozzman commented Oct 4, 2020

Thanks for this, it really helped me out!

It seems things have moved a bit underneath all this since 2017, so I created an updated version.

For anyone arriving... this link contains the only correctly current version. Steps to follow...

It also helped me understand why the volume mount doesn't do anything and what's really going on.

In short: (with optional explanation)

  1. From the XQuartz preferences, in the security tab, make sure Allow connections from network clients is enabled. Restart XQuartz.

NB: After restarting XQuartz, you can run netstat -an | grep -F 6000 to find that XQuartz has opened port 6000. This is actually how your docker container will be communicating with XQuartz on the host. The volume mount is not (and cannot due to an ongoing issue -- more details in the original link) be used.

  1. In a terminal on the host, run xhost +localhost.

NB: This will allow network X11 connections from localhost only, which is fine. Also if XQuartz is not running, xhost will start it.

  1. Pass -e DISPLAY=host.docker.internal:0 to any docker image you want to forward X to the host.

NB: host.docker.internal is the DNS name which resolves to your host machine from within your docker container. This will get X within the container to connect to port 6000 on your host and communicate with XQuartz -- the volume mount is entirely unused. You can also set the env var directly in the container with bash/Dockerfile/etc.

  1. Run your application.

NB: If all of the above steps were completed successfully, an X window should open on your host which is forwarding from the container. Debugging steps can be checked from the link above.

Much thanks to @paul-krohn for putting together his README which clarified a lot.

@ManuelSchneid3r
Copy link

Step 4: I have no xhost on my system. Or do I have to run this in the docker container?

@paul-krohn
Copy link

xhost is part of XQuartz and on my system is at /opt/X11/bin/xhost. Do you for sure have /opt/X11/bin in your PATH?

@ManuelSchneid3r
Copy link

Yes somehow after restarting it was available. Maybe PATH lookup issues.

@DrSnowbird
Copy link

DrSnowbird commented Jul 15, 2021

The latest version of "DrSnowbird/jdk-mvn-py3-x11" already automatically" set up everything for you.

The latest version will automatically do all the necessary X11 setup for you except "the installation of xquartz" (running the 'run.sh' will automatically launch XQuartz).

So, you don't have do anything to run X11 on your host machine regardless macOS, Ubuntu, or CentOS (due to the automation inside run.sh). It is just as simple as below since "run.sh" script automatically does everything for you.

  1. First, "git clone https://github.com/DrSnowbird/jdk-mvn-py3-x11.git"
  2. then, "cd jdk-mvn-py3-x11"
  3. then, "./run.sh" . Then, you should see the "xeyes" X11 application showing up on your desktop.
    Bonus,
  4. try, "./shell.sh" using a new X-terminal, then run "firefox" from command line, you see will Firefox browser popping up on your Desktop.

That's it!

Important: You don't have to do anything setup including xhost, HOSTNAME, etc. It is all automatically done in "run.sh"

  • "run.sh" script that It has everything automation (auto-detect your host's OS) setup for you except that, in macOS, you need to have 'xquartz' installed as the only manual effort when running on macOS - not for other Linux (e.g., Ubuntu, or CentOS).

PS: if you are still having trouble, my recommendation is to use "noVNC" using your web HTML 5 browsers to run as your desktop. You can access your Docker Container's desktop using any HTML 5 web browser. Please see:

@stevenirby
Copy link

stevenirby commented Feb 12, 2022

I couldn't get it working without running it this way. (on an M1 Mac)

docker run -it --env="DISPLAY=host.docker.internal:0" -v /tmp/.X11-unix:/tmp/.X11-unix:rw <image name>

This did NOT work.

-e DISPLAY=host.docker.internal:0

@DrSnowbird
Copy link

DrSnowbird commented Feb 21, 2022

Most likely you need to install XQuartz first on Mac to allow X11 to work to display to your Desktop. However, with the licensing fee requirements to run Docker with Docker-Desktop on Mac, I myself am not using Docker/Docker-Desktop anymore. I am using 100% Linux (Ubuntu/CentOS and other variations) now for all my open-source projects. Hence, I can't help much further now on Mac. There are many blogs that provide alternative Docker solutions.

@ScottFred
Copy link

This was great! Thanks for providing this GIST!

@saikrn112
Copy link

Hey all,
I am getting these errors when I am running gazebo from docker. Can someone help here?
I am using intel i5 Mac and docker version 20.10.8, build 3967b7d

libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
ALSA lib confmisc.c:855:(parse_card) cannot find card '0'
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_card_inum returned error: No such file or directory
ALSA lib confmisc.c:422:(snd_func_concat) error evaluating strings
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1334:(snd_func_refer) error evaluating name
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5701:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM default
AL lib: (EE) ALCplaybackAlsa_open: Could not open playback device 'default': No such file or directory
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast

@pstoll
Copy link

pstoll commented Nov 25, 2022

Adding a note of encouragement and thanks - I got my display working because of the instructions here.

FYI my setup - M1 MacBook Pro. So I'm using Rancher Desktop with a VM setup/dockerd.

Both of these worked for me getting a (gtk-based) x application runing inside an xterm inside XQuartz. fwiw I'm compiling the latests emacs (29.0) which has GTK support.

## using the `hostname` for the xhost & display
export HOSTNAME=`hostname`                                                                                   
xhost +${HOSTNAME}                                                                                           
docker run  -ti -v /tmp/.X11-unix:/tmp/.X11-unix -e "DISPLAY=${HOSTNAME}:0" pstoll/emacs-cross emacs         

And also

## Using localhost for both xhost & display: 
xhost +localhost                                                                                             
docker run  -ti -v /tmp/.X11-unix:/tmp/.X11-unix -e "DISPLAY=host.docker.internal:0" pstoll/emacs-cross emacs

@Mirey007
Copy link

Mirey007 commented Jul 4, 2023

MacBook Pro ventura 13.3

Need set DISPLAY variable with prefix mac
-e DISPLAY=docker.for.mac.host.internal:0

docker run -p 8282:80 -e DISPLAY=docker.for.mac.host.internal:0 my docker

@marcospgp
Copy link

For those arriving from google like me: 2024 Dockerfile and compose.yaml for MacOS host:

FROM ubuntu:latest

# Install X11 and sample x11 apps
RUN apt-get update && \
    apt-get install -y x11-apps

# Open xclock on startup
CMD ["xclock"]
services:
  gui-app:
    build: .
    environment:
      - DISPLAY=host.docker.internal:0
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix

Before docker compose up, install xquartz and do enable network connections on settings security tab.

@harunkurtdev
Copy link

harunkurtdev commented Jan 23, 2024

Heyoo brotherss,

You can find on the this link,

I find some solution.

apptainer/singularity#5524 (comment)

on the link output

Ekran Resmi 2024-01-24 02 06 19

@jamesjmchugh
Copy link

For those arriving from google like me: 2024 Dockerfile and compose.yaml for MacOS host:

FROM ubuntu:latest

# Install X11 and sample x11 apps
RUN apt-get update && \
    apt-get install -y x11-apps

# Open xclock on startup
CMD ["xclock"]
services:
  gui-app:
    build: .
    environment:
      - DISPLAY=host.docker.internal:0
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix

Before docker compose up, install xquartz and do enable network connections on settings security tab.

I just wanted to post and confirm this worked for me in February 2024 on an m2 macbook. Thank you!

@amura87516
Copy link

For those arriving from google like me: 2024 Dockerfile and compose.yaml for MacOS host:

FROM ubuntu:latest

# Install X11 and sample x11 apps
RUN apt-get update && \
    apt-get install -y x11-apps

# Open xclock on startup
CMD ["xclock"]
services:
  gui-app:
    build: .
    environment:
      - DISPLAY=host.docker.internal:0
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix

Before docker compose up, install xquartz and do enable network connections on settings security tab.

I just wanted to post and confirm this worked for me in February 2024 on an m2 macbook. Thank you!

Somehow it didn't work on my M2 MacOS :(

Error: Can't open display: host.docker.internal:0
Screenshot 2024-02-26 at 10 24 40 PM

Any suggestion?

@ldipenti
Copy link

There shouldn't be a need of using "DISPLAY=host.docker.internal:0" and mounting the "/tmp/.X11-unix" socket file. I was able to make this work with just the DISPLAY envvar and enabling network connections and disabling connections auth in XQuartz settings.
Nevertheless, I think the ideal would be to just use the "/tmp/.X11-unix" file instead of network connections. I'm not being able to make this work even though the file seems to be correctly mounted inside the container.

@Tigatok
Copy link

Tigatok commented Apr 5, 2024

@ldipenti FTR I had to include the host.docker.internal:0, in 2024. I'm on a MacBook Pro 2024 m3 version.

Here is a working Dockerfile and Dockercompose:

FROM openjdk:11

# Install necessary packages for X11 or for your app
RUN apt-get update && apt-get install -y \
    libxext6 \
    libxrender1 \
    libxtst6 \
    x11-apps

# Set the working directory
WORKDIR /app

# Copy the source code into the container
COPY src /app/src
COPY dist/lib /app/lib

# Compile the Java application
RUN javac -cp "/app/lib/*" -d /app/bin /app/src/*.java

# Set the DISPLAY environment variable for X11 forwarding
ENV DISPLAY host.docker.internal:0

# Run the compiled Java application
CMD ["java", "-cp", "/app/bin:/app/lib/*", "MainClass"]
version: '3'
services:
  java-app:
    build: .
    image: java-app
    container_name: java-app-container
    environment:
      - _JAVA_OPTIONS="-Dsun.java2d.xrender=false"

I added the _JAVA_OPTIONS stuff cause I was getting some weird color errors on my swing ui.

@NovoG93
Copy link

NovoG93 commented May 24, 2024

Hey all, I am getting these errors when I am running gazebo from docker. Can someone help here? I am using intel i5 Mac and docker version 20.10.8, build 3967b7d

libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
ALSA lib confmisc.c:855:(parse_card) cannot find card '0'
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_card_inum returned error: No such file or directory
ALSA lib confmisc.c:422:(snd_func_concat) error evaluating strings
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1334:(snd_func_refer) error evaluating name
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5701:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM default
AL lib: (EE) ALCplaybackAlsa_open: Could not open playback device 'default': No such file or directory
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast

@saikrn112 did you manage to use gazebo/rviz2 or any other gtk based application with docker on your mac?
I am facing the same issues

@R1kk3r
Copy link

R1kk3r commented Jul 8, 2024

Lot of comments here, not always correct. Here is the TL;DR.

Volume?

  volumes:
  - /tmp/.X11-unix:/tmp/.X11-unix

This is useless, Docker Desktop does not support Unix socket (exception made for a very specific SSH case). A very good reading to get all the details https://briefcase.readthedocs.io/en/stable/how-to/internal/x11passthrough.html

The only solution is to use the network via the DISPLAY=host.docker.internal:0.

libGL error?

If you get the following error:

libGL error: failed to load driver: swrast

You can try to indirect rendering by setting the export LIBGL_ALWAYS_INDIRECT=1

X request error?

If you get the following error:

X Error of failed request:  BadValue (integer parameter out of range for operation)
  Major opcode of failed request:  149 (GLX)
  Minor opcode of failed request:  24 (X_GLXCreateNewContext)
  Value in failed request:  0x0
  Serial number of failed request:  25
  Current serial number in output stream:  26

The latest Quartz version are buggy. I downgraded to 2.7.8 and everything works fine.

X connection error?

If you get Error: Can't open display: host.docker.internal:0, try to ping host.docker.internal. If it works, then the network is up and running but somehow Quartz is not listening/accepting the connection. Otherwise, this is a docker network issue. In the former case, you need to make sure the settings in Quartz are configured properly "allow connection + disable authorisation". Make sure to add in xhost and also try to reboot (sometimes, running/killing quartz to many times makes it unable to listen correctly on the port).

In addition, starting/stopping XQuartz multiple times, it might have changed the port number. Run the command sudo lsof -i -P | grep LISTEN | grep :$PORT and make sure you see x11.bin using port 6000. If it uses something else, for example 6001, it means you need to adapt the DISPLAY to DISPLAY=host.docker.internal:1, if it is 6005 you should set to DISPLAY=host.docker.internal:5.

@taylorchu
Copy link

taylorchu commented Sep 29, 2024

@idossha
Copy link

idossha commented Oct 21, 2024

I was stuck on this for a while. Eventually I realized there might be a problem with Xquartz. Indeed after downgrading as suggested by @R1kk3r and following these steps below everything worked fine.

defaults write org.macosforge.xquartz.X11 nolisten_tcp -bool false
export DISPLAY=localhost:0
xhost +localhost
xhost +$(hostname)

Hope that helps.

@devnoname120
Copy link

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