Can you run GUI applications in a Linux Docker container?

363,408

Solution 1

You can simply install a vncserver along with Firefox :)

I pushed an image, vnc/firefox, here: docker pull creack/firefox-vnc

The image has been made with this Dockerfile:

# Firefox over VNC
#
# VERSION               0.1
# DOCKER-VERSION        0.2

FROM    ubuntu:12.04
# Make sure the package repository is up to date
RUN     echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN     apt-get update

# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN     apt-get install -y x11vnc xvfb firefox
RUN     mkdir ~/.vnc
# Setup a password
RUN     x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way to do it, but it does the trick)
RUN     bash -c 'echo "firefox" >> /.bashrc'

This will create a Docker container running VNC with the password 1234:

For Docker version 18 or newer:

docker run -p 5900:5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create

For Docker version 1.3 or newer:

docker run -p 5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create

For Docker before version 1.3:

docker run -p 5900 creack/firefox-vnc x11vnc -forever -usepw -create

Solution 2

Xauthority becomes an issue with newer systems. I can either discard any protection with xhost + before running my docker containers, or I can pass in a well prepared Xauthority file. Typical Xauthority files are hostname specific. With docker, each container can have a different host name (set with docker run -h), but even setting the hostname of the container identical to the host system did not help in my case. xeyes (I like this example) simply would ignore the magic cookie and pass no credentials to the server. Hence we get an error message 'No protocol specified Cannot open display'

The Xauthority file can be written in a way so that the hostname does not matter. We need to set the Authentication Family to 'FamilyWild'. I am not sure, if xauth has a proper command line for this, so here is an example that combines xauth and sed to do that. We need to change the first 16 bits of the nlist output. The value of FamilyWild is 65535 or 0xffff.

docker build -t xeyes - << __EOF__
FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes
__EOF__
XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
xauth nlist :0 | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
docker run -ti -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH -e XAUTHORITY=$XAUTH xeyes

Solution 3

I just found this blog entry and want to share it here with you because I think it is the best way to do it and it is so easy.

http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/

PROS:
+ no x server stuff in the docker container
+ no vnc client/server needed
+ no ssh with x forwarding
+ much smaller docker containers

CONS:
- using x on the host (not meant for secure-sandboxing)

in case the link will fail someday I have put the most important part here:
dockerfile:

FROM ubuntu:14.04

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

# Replace 1000 with your user / group id
RUN export uid=1000 gid=1000 && \
    mkdir -p /home/developer && \
    echo "developer:x:${uid}:${gid}:Developer,,,:/home/developer:/bin/bash" >> /etc/passwd && \
    echo "developer:x:${uid}:" >> /etc/group && \
    echo "developer ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/developer && \
    chmod 0440 /etc/sudoers.d/developer && \
    chown ${uid}:${gid} -R /home/developer

USER developer
ENV HOME /home/developer
CMD /usr/bin/firefox

build the image:

docker build -t firefox .

and the run command:

docker run -ti --rm \
   -e DISPLAY=$DISPLAY \
   -v /tmp/.X11-unix:/tmp/.X11-unix \
   firefox

of course you can also do this in the run command with sh -c "echo script-here"

HINT: for audio take a look at: https://stackoverflow.com/a/28985715/2835523

Solution 4

With docker data volumes it's very easy to expose xorg's unix domain socket inside the container.

For example, with a Dockerfile like this:

FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes

You could do the following:

$ docker build -t xeyes - < Dockerfile
$ XSOCK=/tmp/.X11-unix/X0
$ docker run -v $XSOCK:$XSOCK xeyes

This of course is essentially the same as X-forwarding. It grants the container full access to the xserver on the host, so it's only recommended if you trust what's inside.

Note: If you are concerned about security, a better solution would be to confine the app with mandatory- or role-based-access control. Docker achieves pretty good isolation, but it was designed with a different purpose in mind. Use AppArmor, SELinux, or GrSecurity, which were designed to address your concern.

Solution 5

OSX

Jürgen Weigert has the best answer that worked for me on Ubuntu, however on OSX, docker runs inside of VirtualBox and so the solution doesn't work without some more work.

I've got it working with these additional ingredients:

  1. Xquartz (OSX no longer ships with X11 server)
  2. socket forwarding with socat (brew install socat)
  3. bash script to launch the container

I'd appreciate user comments to improve this answer for OSX, I'm not sure if socket forwarding for X is secure, but my intended use is for running the docker container locally only.

Also, the script is a bit fragile in that it's not easy to get the IP address of the machine since it's on our local wireless so it's always some random IP.

The BASH script I use to launch the container:

#!/usr/bin/env bash

CONTAINER=py3:2016-03-23-rc3
COMMAND=/bin/bash
NIC=en0

# Grab the ip address of this box
IPADDR=$(ifconfig $NIC | grep "inet " | awk '{print $2}')

DISP_NUM=$(jot -r 1 100 200)  # random display number between 100 and 200

PORT_NUM=$((6000 + DISP_NUM)) # so multiple instances of the container won't interfer with eachother

socat TCP-LISTEN:${PORT_NUM},reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" 2>&1 > /dev/null &

XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth.$USER.$$
touch $XAUTH
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -

docker run \
    -it \
    --rm \
    --user=$USER \
    --workdir="/Users/$USER" \
    -v "/Users/$USER:/home/$USER:rw" \
    -v $XSOCK:$XSOCK:rw \
    -v $XAUTH:$XAUTH:rw \
    -e DISPLAY=$IPADDR:$DISP_NUM \
    -e XAUTHORITY=$XAUTH \
    $CONTAINER \
    $COMMAND

rm -f $XAUTH
kill %1       # kill the socat job launched above

I'm able to get xeyes and matplotlib working with this approach.

Windows 7+

It's a bit easier on Windows 7+ with MobaXterm:

  1. Install MobaXterm for windows
  2. Start MobaXterm
  3. Configure X server: Settings -> X11 (tab) -> set X11 Remote Access to full
  4. Use this BASH script to launch the container

run_docker.bash:

#!/usr/bin/env bash

CONTAINER=py3:2016-03-23-rc3
COMMAND=/bin/bash
DISPLAY="$(hostname):0"
USER=$(whoami)

docker run \
    -it \
    --rm \
    --user=$USER \
    --workdir="/home/$USER" \
    -v "/c/Users/$USER:/home/$USER:rw" \
    -e DISPLAY \
    $CONTAINER \
    $COMMAND

xeyes running on PC

Share:
363,408
Will
Author by

Will

Updated on September 09, 2021

Comments

  • Will
    Will over 2 years

    How can you run GUI applications in a Linux Docker container?

    Are there any images that set up vncserver or something so that you can - for example - add an extra speedbump sandbox around say Firefox?

  • user94154
    user94154 over 10 years
    How would I use a VNC client to view this remotely? Typing in the IP + port doesn't seem to be working.
  • creack
    creack over 10 years
    First, you need to check the port allocated (by doing docker inspect <container id> or simply docker ps, then you connect to your host's ip with the port you just found.
  • timthelion
    timthelion about 10 years
    Please note that subuser is still very new and relatively untested. If you run into any problems please submit bug reports!
  • Will
    Will about 10 years
    I'd avoid X11 if there's any way you can. Your killer app would be running the tor proxy in docker, and running a full browser with plugins in a child docker such that firewalling etc forces all network out via the tor docker. This would run laps around the current tor browser bundle for web usability because you'd let rich content through.
  • timthelion
    timthelion about 10 years
    Is the trouble for you with X11 security? Or is it that you want this working with windows? Or that you want this to work remotely? All of the above? I think that making this work with vnc is quite possible(though I wouldn't make it the default method because it adds a dependency on vnc). Making subuser work remotely isn't really possible/meaningfull. There is also this: github.com/rogaha/docker-desktop but from the bug reports it seems xpra might be unusable in real life.
  • Will
    Will almost 10 years
    (This is great for trusted apps. For any kind of sandboxing, though, you want to avoid X-forwarding.)
  • Bruno Adelé
    Bruno Adelé almost 10 years
    You can see the equivalent 5900 port with this command docker ps | grep -Po ':\K[0-9]*'
  • Will
    Will over 9 years
    This is great if security isn't a concern. If the purposes of dockering something are to isolate it, its best to avoid X11 in-out of the container.
  • Tully
    Tully over 9 years
    You also need to allow access to the X Server from other hosts using a tool like xhost. To completely open it up use xhost + on the host.
  • Aryeh Leib Taurog
    Aryeh Leib Taurog over 9 years
    @Tully only xhost +local is necessary. It would be better to make the ~/.Xauthority file available in the container however, so it can authenticate itself.
  • Karl Forner
    Karl Forner over 9 years
    have you managed to get it working on a Mac (using boot2docker) ?
  • Aryeh Leib Taurog
    Aryeh Leib Taurog over 9 years
    @KarlForner sorry, I've only got linux here.
  • alfonsodev
    alfonsodev over 9 years
    the creackfirefox-vnc image fails with error: Enter VNC password: stty: standard input: Inappropriate ioctl for device fgets: No such file or directory stty: standard input: Inappropriate ioctl for device x11vnc -usepw: could not find a password to use.
  • Cristopher Van Paul
    Cristopher Van Paul over 9 years
    Use docker well > Running GUI apps with Docker fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker
  • pablo
    pablo over 9 years
    How can I find the firefox window id and share only the firefox window? x11vnc has the -id <window> option but I don't know how to find the id. A terminal window is also opened and I'm not sure why.
  • Sudipta Basak
    Sudipta Basak over 9 years
    Not clear what is the username and password. Which vnc client to use and how to connect?
  • creack
    creack over 9 years
    There is no username, the password is clearly indicated in the answer and any vnc client will do. In my case, I like the native osx one. (from finder, press command+K and connect to vnc://<docker ip>:<container exposed port>)
  • Manglu
    Manglu almost 9 years
    Is there a way to change the screen resolution. When I used this image it uses only 50% of the real estate.
  • cboettig
    cboettig almost 9 years
    This was working rather nicely for me on an Ubuntu 14.04 laptop with docker 1.5 earlier; but is now failing for me on Ubuntu 15.04, docker 1.6.2, with the error Can't open display: :0. Any ideas?
  • cboettig
    cboettig almost 9 years
    I see my problem on 15.04 is solved by the XAuthority mapping listed in Jürgen Weigert's solution below.
  • Fish Monitor
    Fish Monitor almost 9 years
    @KarlForner, for OS X see kartoza.com/…. This is much easier.
  • creack
    creack over 8 years
    I think 12.04 is not supported anymore. If you bump to 14.04 it should work. Might need to update the universe repo as well.
  • Robert Haines
    Robert Haines over 8 years
    If you'd rather not mount the whole home directory into the container you can just mount the .Xauthority file itself: -v $HOME/.Xauthority:/root/.Xauthority -e XAUTHORITY=/root/.Xauthority.
  • Nick Breen
    Nick Breen over 8 years
    I used xhost +si:localuser:$USER to authorise just the user starting the container.
  • Yair Zaslavsky
    Yair Zaslavsky about 8 years
    I found the port the vnc server mapped to, and the docker version I am using is (on ubuntu 14.04) 1.10.2. When I run vncviewer localhost:32776 -passwd ~/.vnc/passwdfile I do not see firefox, but i see Thu Feb 25 07:07:31 2016 CConn: connected to host localhost port 32776 main: End of stream Can anyone help please?
  • Piotr Aleksander Chmielowski
    Piotr Aleksander Chmielowski about 8 years
    Just a note, -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH can be shortened to -v $XSOCK -v $XAUTH
  • valentt
    valentt almost 8 years
    @creack awesome works, but please, please, please include run example in Dockerfile and on your github, or at least link to this stackoverflow question.
  • creack
    creack almost 8 years
    Done. Didn't test if still working though. hub.docker.com/r/creack/firefox-vnc
  • Peter Butkovic
    Peter Butkovic almost 8 years
  • tbc0
    tbc0 over 7 years
    @PiotrAleksanderChmielowski that did not work for me, Docker version 1.12.0, build 8eab29e
  • Aleksandr Dubinsky
    Aleksandr Dubinsky over 7 years
    I seemed to need -t in docker run to get a password prompt. I'm not sure why a password is even needed in this. Anyway, please update the instructions by editing the original instructions rather than adding "EDIT" sections.
  • Piotr Aleksander Chmielowski
    Piotr Aleksander Chmielowski over 7 years
    @tbc0 - interesting. Maybe it is a bug to report?
  • TmTron
    TmTron over 7 years
    @AryehLeibTaurog I think the trailing colon is missing in your command xhost +local:. Without the colon, the command failed on Ubuntu 16.04
  • Dirk
    Dirk over 7 years
    Does not work for me either: Error: Can't open display: :0 Docker v1.8.2-7 on Fedora 22.
  • johndodo
    johndodo over 7 years
    @Dirk: You might want to replace :0 with $DISPLAY. That means xauth nlist $DISPLAY | ... and docker run -ti -e DISPLAY=$DISPLAY .... Usually the X DISPLAY is :0, but not always (and especially not if you are connecting via ssh -X).
  • Lisael
    Lisael about 7 years
    I changed this Dockerfile to use .xinitrc instead of .bashrc: RUN echo "exec firefox" > ~/.xinitrc && chmod +x ~/.xinitrc. x11vnc -create ... opens a new display and tries to run .xinitrc
  • dashesy
    dashesy about 7 years
    To run a desktop in docker under vnc ConSol has a nice solution.
  • ingomueller.net
    ingomueller.net about 7 years
    Instead of changing X11UseLocalhost, you can also use the additional option --net=host for the docker run command (found here).
  • deller
    deller almost 7 years
    i didnt understand what you meant by the bash script - how do i run it in windows?
  • Nick
    Nick almost 7 years
    @deller I do software development on windows using GIT, so I have the GIT-bash shell available to me.
  • mguijarr
    mguijarr almost 7 years
    Just for people landing here: @PiotrAleksanderChmielowski comment did not work for me, and I also had to add --net=host
  • guilhermecgs
    guilhermecgs almost 7 years
    has anyone tested this?
  • dashesy
    dashesy almost 7 years
    @guilhermecgs yes, and works fine. Since then I also tried xpra in docker, which is root-less X. xpra was the best suited IMO and is more efficient than VNC.
  • guilhermecgs
    guilhermecgs almost 7 years
    Just to be clear... Can I have a full desktop experience (GNOME, KDE) with this image?
  • dashesy
    dashesy almost 7 years
    I only tried the Xfce4 and IceWM (which is in that repo). Of course the experience will be limited, for example mounting devices will not show up in the desktop (gvfs) unless you pass --device /dev/... to the docker and set necessary --cap privileges. That defeats the purpose of containment, but you can pass through devices. With some tweaking it should be possible I believe to run GNOME/KDE under VNC. I ran multiple X in docker with nvidia cards (no VNC or Xpra), so that is certainly doable.
  • Abai
    Abai over 6 years
    On Ubuntu 16.04 xauth creates the /tmp/.docker.xauth file with 600 permissions. This results in xauth inside docker container not being able to read the file. You can verify by running xauth list within the docker container. I have added chmod 755 $XAUTH after the xauth nlist :0 | ... command to resolve this.
  • user3275095
    user3275095 over 6 years
    I followed the steps. However, I get error: XDG_RUNTIME_DIR not set in the environment. and Error: cannot open display: VAIO:0.0. Did you encounter something like this?
  • Daniel Alder
    Daniel Alder about 6 years
    @Abai Why using 755, if 444 or 644 is enough?
  • toschneck
    toschneck about 6 years
    We didn't tried it so far. The biggest challenge on this would be to bring up a working D-Bus daemon. Most of the gnome or KDE desktops will need them. May the ubuntu-desktop-lxde-vnc project helps you there.
  • readytotaste
    readytotaste almost 6 years
    How can I do this on windows 7? Do I need to install an X server?
  • A. Binzxxxxxx
    A. Binzxxxxxx almost 6 years
    As most answers here this applies only to unix I think - until windows supports X server window system.
  • readytotaste
    readytotaste almost 6 years
    Do you think it could work if I installed X server on windows or even bundled an X server into my Docker container?
  • A. Binzxxxxxx
    A. Binzxxxxxx almost 6 years
    installing X server into your docker does not make much sense since this is what I try to avoid and you would still need to render it to the display then. One of the vnc answers may fit you in your case.
  • A. Binzxxxxxx
    A. Binzxxxxxx almost 6 years
    However I could imagine it may work with Xming or Cygwin/X. Please write a comment if you got it working.
  • readytotaste
    readytotaste almost 6 years
    Okay will try installing Xming on windows and then try this.. One thing Im confused about is that the docker toolbox for windows runs inside Boot2Docker, which is a stripped down version of Linux for the Docker daemon.. Do you think I could install X server on this and run it with the exact same flags as above?
  • readytotaste
    readytotaste almost 6 years
    How can I make this work on Windows 7? Since, it does not have X server capability?
  • readytotaste
    readytotaste almost 6 years
    Has anyone figured out X forwarding for windows?
  • readytotaste
    readytotaste almost 6 years
    I get an error pertaining to the user not being found i.e. "no matching entries in passwd file" Any leads?
  • readytotaste
    readytotaste almost 6 years
    I was actually able to get it to work using MobaXTerm by using the Dockerfile as above and modifying the docker run command to mount /tmp/.X11-unix to /c:/Users/username and set the host IPv4 address for the DISPLAY environment variable..
  • Alejandro Galera
    Alejandro Galera almost 6 years
    I think you also need to install in Dockerfile apt-get -y install sudo to create /etc/sudoers.d folder.
  • vladkras
    vladkras almost 6 years
    works perfect with noVNC client directly in browser. Tested: consol/ubuntu-xfce-vnc
  • CMCDragonkai
    CMCDragonkai over 5 years
    I have found that you don't even eed to pass the /tmp/.X11-unix socket at all. It just works with mounting .Xauthority and --net=host.
  • Jan Hudec
    Jan Hudec over 5 years
    @walksignison, Install X server. There are three options: VcXsrv, Xming and Cygwin/X. xauth acts up a bit for me though; due to lack of unix domain sockets, the DISPLAY ends up being 127.0.0.1:0 and xauth does not accept it in some commands.
  • readytotaste
    readytotaste over 5 years
    @janhudec I was able to get it to work with Moba XTerm! Thanks a lot anyway!
  • Christian Hujer
    Christian Hujer over 5 years
    This will probably work everywhere. But If the host is Linux with X11, this is overkill. If the host is Linux with X11, X11 based solutions will be more light-weight.
  • Christian Hujer
    Christian Hujer over 5 years
    This does not work in the latest versions of docker. Docker refuses to mount from volumes where the host has the sticky bit set.
  • Christian Hujer
    Christian Hujer over 5 years
    This is actually the only solution that works these days. Using /tmp/.X11-unix as volume no longer works, as docker silently refuses volume mounts from sticky directories.
  • kgibm
    kgibm over 5 years
    The following worked for me (in particular, adding -e DISPLAY=$DISPLAY), replacing the last four lines with: xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f /tmp/.docker.xauth nmerge - && docker run -it -v /tmp/.X11-unix:/tmp/.X11-unix -v /tmp/.docker.xauth:/tmp/.docker.xauth -e XAUTHORITY=/tmp/.docker.xauth -e DISPLAY=$DISPLAY xeyes
  • stelios
    stelios about 5 years
    @Abai Good point! However you need chmod before xauth nlist ...
  • orodbhen
    orodbhen almost 5 years
    I think it depends on what distro you're using. You definitely can bind-mount the X11 Unix socket on CentOS. It's also important to understand what --network=host does. It gives your container full access to the host's network stack, which may be undesirable, depending on what you're trying to do. If you're just tinkering with running containerized GUIs on your desktop, then it shouldn't matter.
  • user1145922
    user1145922 over 4 years
    This is the only one that would work for me. For my purposes, I was able to minimize it to this: docker run --network=host --volume=echo ~:/home/${USER} --user=id -u ${USER} --env="DISPLAY" --volume="/etc/passwd:/etc/passwd:ro" -it REPO:TAG /bin/bash
  • Bandoos
    Bandoos about 4 years
    it may also be necessary to allow connections to X from any host with $ xhost +
  • Admin
    Admin about 4 years
    running this over ssh, I had to add "--network host" to the docker run command as well. (to avoid "Error: Can't open display: localhost:10.0")
  • MrR
    MrR almost 4 years
    --net=host is a bad idea as now if you open a port in the container it will be open in the host as well...
  • MrR
    MrR almost 4 years
    "Create the X11 Unix socket and the X authentication file" doiesn't create any files, it just defines variables?
  • dragon788
    dragon788 almost 4 years
    I don't think xhost + is more private, I think that actually opens up the server to any connection per the second highest voted answer. stackoverflow.com/a/25280523
  • eosphere
    eosphere about 3 years
    I followed the instructions given in medium.com/@SaravSun/… and it worked flawlessly with this command line : sudo docker run --net=host --env="DISPLAY" --volume="$HOME/.Xauthority:/root/.Xauthority:rw" xeyes
  • Leopd
    Leopd about 3 years
    I didn't have a ~/.Xauthority file for some reason, so I had to generate one by running xauth generate $DISPLAY . trusted
  • ai2ys
    ai2ys almost 3 years
    @Nick what kind of modifications were required in the dockerfile? Like mentioned in the previous comment I am getting the same error "unable to find user <username>: no matching entries in passwd file."
  • Nick
    Nick almost 3 years
    @ai2ys, I think I must have added users to the container.
  • Artur Opalinski
    Artur Opalinski over 2 years
    "If you run xauth list on the host and container, with the same Xauthority file, you'll see different entries listed. " -> if you REALLY see this, then this is a bug. "The SSH server running on a remote machine emulates its own X server." -> no, it does not. It only opens a TCP port on the remote end and forwards the traffic to the local end, where an X server is needed to process it.
  • Admin
    Admin about 2 years
    Your Dockerfile instructions don't working, be cause I build the instruction and can't start de container :( # nano Dockerfile (and put the information) # docker build -t mycontainervnc . # docker run -p 5900:5900 --name vnc -e HOME=/ mycointainervnc x11vnc -forever -usepw -create # and not working :(