What is this about?
Docker has dozents of advantages and so is one of them to be able to use apps with a GUI isolated in a docker container. For example your Browser, TextEditor or something else.
Neatless to say that this will enable you to use linux / macOS software on your windows host without messing with some hacks. Also this will prevent your maschine from having leftover dependencies when removing the app because it all stays wrapped up in a docker container.
Why would someone even try to do that?
I use Arch Linux on my private computer at home and Windows 10 at work. I wanted to be able to use the Evolution mail client and other handy linux apps on my windows maschine.
So there are various tutorials on how to share an X11-Session from a linux host with a linux container. But:
How to share the display from a windows host?
Install VcXsrv and configure it
First of all, install VcXsrv Windows X Server. We could use Xming also, but the package for windows hasn't been updated since 2013. The easiest way would be to use Chocolatey which is by the way my favorite package manager for windows!
So fire up a powershell session and run:
choco install vcxsrv
Then run Xlaunch from the start menu and follow the initial configuration steps:
Make sure to save to configuration file before you click finish!
Save it to one of the following locations:
- %appdata%\Xming
- %userprofile%\Desktop
- %userprofile%
Create a Dockerfile
To use a simple example, create a new folder and place a Dockerfile with the following content in it:
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y firefox
CMD /usr/bin/firefox
Build and run the container
For advanced docker users, here the quick commands:
docker build -t firefox .
set-variable -name DISPLAY -value YOUR-IP:0.0
docker run -ti --rm -e DISPLAY=$DISPLAY firefox
With some explaination:
Now build the new container and label it firefox:
docker build -t firefox .
Because the container has its own localhost interface, we need to use the IP-address of our network adapter.
Find out your ip address with
ipconfig
Set the environment variable (replace IP with yours):
set-variable -name DISPLAY -value 10.11.128.118:0.0
Run the container:
docker run -ti --rm -e DISPLAY=$DISPLAY firefox
You should now see a firefox window:
This will work most other apps.
Persisting data
To persist data (like for evolution mail), start the container with the correct locations mounted via a docker volume.
Find out all the locations, where your app stores data you want to persist and mount them:
docker run -v c:/docker/evolutionmail/home/user/.local/share/evolution:/root/.local/share/evolution -v c:/docker/evolutionmail/home/user/.config/evolution:/root/.config/evolution -ti --rm -e DISPLAY=$DISPLAY evolution
Example Dockerfile for evolution mail
Here is my evolution Dockerfile in case someone needs it:
FROM debian
# Setup enviroment variables
ENV DEBIAN_FRONTEND noninteractive
# Installing fuse filesystem is not possible in docker without elevated priviliges
# but we can fake installling it to allow packages we need to install for GNOME
RUN apt-get install libfuse2 -y && \
cd /tmp ; apt-get download fuse && \
cd /tmp ; dpkg-deb -x fuse_* . && \
cd /tmp ; dpkg-deb -e fuse_* && \
cd /tmp ; rm fuse_*.deb && \
cd /tmp ; echo -en '#!/bin/bash\nexit 0\n' > DEBIAN/postinst && \
cd /tmp ; dpkg-deb -b . /fuse.deb && \
cd /tmp ; dpkg -i /fuse.deb
# Upstart and DBus have issues inside docker.
RUN dpkg-divert --local --rename --add /sbin/initctl && ln -sf /bin/true /sbin/initctl
# Install GNOME
RUN apt-get update && apt-get install -y xorg gnome-core gnome-session-fallback
# Pull in the hack to fix keyboard shortcut bindings for GNOME 3
ADD https://raw.githubusercontent.com/CannyComputing/Dockerfile-Ubuntu-Gnome/master/gnome-keybindings.pl /usr/local/etc/gnome-keybindings.pl
RUN chmod +x /usr/local/etc/gnome-keybindings.pl
# Add the script to fix and customise GNOME for docker
ADD https://raw.githubusercontent.com/CannyComputing/Dockerfile-Ubuntu-Gnome/master/gnome-docker-fix-and-customise.sh /usr/local/etc/gnome-docker-fix-and-customise.sh
RUN chmod +x /usr/local/etc/gnome-docker-fix-and-customise.sh
RUN apt-get update -y && apt-get install -y dbus-x11 gnome-keyring evolution evolution-data-server seahorse sudo
RUN apt-get install -y libnotify-cil-dev
CMD ["evolution"]
I am curious to see what you dockerized in the comments!
~Cheers
Top comments (57)
Hi Robin,
Thanks for the tutorial. When I run docker run -ti --rm -e DISPLAY=$DISPLAY firefox I get the following error. I have set my $DISPLAY variable equal to 10.17.12.01:0.0 (note this is a fake IP I just made up, I'm using my actual IP in the script). Here's the error.
error: XDG_RUNTIME_DIR not set in the environment.
Error: cannot open display: $DISPLAY
Any thoughts?
Got it! I was running everything in CMD instead of PowerShell. That was dumb.
Glad you figured it out by yourself, my first idea would have been to ask if you're using powershell or cmd :)
I get the above error also through PowerShell
Rauno, did you try running your PowerShell in elevated mode?
Yes, I tried both. I suspect my issue has something to do with Windows Firewall (and corporate antivirus software which has taken control of that).
Hi Rauno,
Did you fix this issues?
I had the same issue and I solve it just adding the :0.0 after my IP
funSkill, could this comment solve it?
I notice that windows firewall can block the connection to the container.
You can allow this access via firewall settings for "VcXsrv windows xserver".
Also, if you only want to give your xserver private network access, you can use:
src
Hi Robin,
I tried it to but issue solved after adding the :0.0 after my IP
Thanks for article. It' very helpful for me!
Good you figured it out, you're welcome :)
Got it! I was running in CMD shell vs Powershell. That fixed the issue.
I'm finding it difficult to auto-insert the DockerNAT IP inside the container, but this seems to work:
or
EDIT: this works too:
Hi Robin,
Thanks for the tutorial!
I managed to get Evolution up & running but I'm facing a problem related to gnome-keyring-daemon, which prevents me from storing my credentials and, in turn, login into my account. In Evolution I get the following error:
"Error calling StartServiceByName for org.freedesktop.secrets: GDBus.Error:org.freedesktop.DBus.Error.Spawn.ExecFailed: Failed to execute program org.freedesktop.secrets: Operation not permitted"
If I open a terminal into the container and try to execute the daemon by hand I get:
root@96c2c004a2cb:~# gnome-keyring-daemon
bash: /usr/bin/gnome-keyring-daemon: Operation not permitted
root@96c2c004a2cb:~# echo $?
126
Any ideas?
Hi Juan,
from what I know gnome-keyring needs an active GDM session - which we don't have in this case.
Please try to attach these lines to
/etc/pam.d/login
:auth optional pam_gnome_keyring.so
session optional pam_gnome_keyring.so auto_start
The daemon needs to be running. Either use --daemonize or run the following command:
gnome-keyring-daemon --login
Maybe you need your password (of the ubuntu user):
echo -n "somewildpasswrd" | gnome-keyring-daemon --login
I did not test it because I switched my work notebook also to linux but please try this and let me know :)
Hi Robin,
Thank you for your answer.
I tried the steps you suggested, but to no avail. I added the following lines to the Dockerfile:
RUN echo "auth optional pam_gnome_keyring.so" >> /etc/pam.d/login
RUN echo "session optional pam_gnome_keyring.so auto_start" >> /etc/pam.d/login
But it did not make any difference. I also tried to execute gnome-keyring-daemon with the options you mentioned, but it keeps failing with "Operation not permitted" and exit code 126:
root@bd0d9115600d:/# gnome-keyring-daemon --login
bash: /usr/bin/gnome-keyring-daemon: Operation not permitted
root@bd0d9115600d:/# gnome-keyring-daemon --daemonize
bash: /usr/bin/gnome-keyring-daemon: Operation not permitted
root@bd0d9115600d:/# echo -n "notmypassword" | gnome-keyring-daemon --login
bash: /usr/bin/gnome-keyring-daemon: Operation not permitted
I even found the command D-Bus uses to start the daemon and tried to use it on my own, but again no luck:
root@bd0d9115600d:/# cat /usr/share/dbus-1/services/org.freedesktop.secrets.service
[D-BUS Service]
Name=org.freedesktop.secrets
Exec=/usr/bin/gnome-keyring-daemon --start --foreground --components=secrets
root@bd0d9115600d:/# /usr/bin/gnome-keyring-daemon --start --foreground --components=secrets
bash: /usr/bin/gnome-keyring-daemon: Operation not permitted
I ended up firing up a Vagrant box over VirtualBox to get this working, since my goal was not to use it on a daily basis, but merely makin a PoC of using Evolution and the evolution-ews plugin with Outlook in Office 365 with MFA enabled (something you cannot do in Thunderbird, for example). My PoC was successful, BTW! :)
Sad this didn't work out, it was neater using Docker :(
Thank you for your help!
Hi Juan,
you're welcome! Good to see your POC worked out! :)
I took an hour to do some research on this and it seems like more people are encountering this limitation. Even Docker is not intended to do such things, it would be really nice to use it.
I agree with you that vagrant is a way but Docker would be much nice to use :)
Here it is the solution > unix.stackexchange.com/questions/4...
I notice that windows firewall can block the connection to the container.
You can allow this access via firewall settings for "VcXsrv windows xserver".
Also, if you only want to give your xserver private network access, you can use:
src
Hey Chris thanks for making me aware of this!
The PowerShell command can come in handy, thanks 😊
Hi Robin,
Thanks for the nice explanation. I was wondering if you or any other reader has ever tried running this on a windowsservercore container on Docker for Windows?
On Ubuntu I got it working the way you described. For certain reasons I am now trying to run Firefox on windowsservercore but without succes.
Thanks,
Arie
Hi Arie,
as of my understanding windows server core it not capable of running such GUI applications by default. I researched that and came across this article on medium which has some information on how to add GUI capabilities to windows server core.
But I think more of interest for you would be this youtube video where they try Chrome, Firefox and Opera on Windows Server Core. (v.1709)
Result of video:
Hi Robin,
Thanks for this tutorial! I was missing the ip address part - now it works!
I needed this in order to use the android studio docker container on a windows machine.
Thanks again!
Alexandru
Great to hear it helped you, Alexandru :)
Hi Robin,
when running: docker run -ti --rm -e DISPLAY=$DISPLAY firefox i get the following error. I am using admin powershell and i set DISPLAY to my IP.
Unable to find image 'firefox:latest' locally
docker: Error response from daemon: pull access denied for firefox, repository does not exist or may require 'docker login': denied: requested access to the resource is denied.
I ran docker login successfully but that didnt change anything. I'm trying to get a vncserver with xterm working in a docker container but im very new to all of this. I wanted to test your code to see if i can get a GUI up and running.
Help would be much appreciated!
Hi oaparfene,
can you please post the content of your Dockerfile?
Also, it is important which name you gave your build.
So you should have the
Dockerfile
in a folder and then run a PowerShell instance (as admin), change into the directory where your Dockerfile is and run thedocker build -t firefox .
command first. Thefirefox
at the end is the name the image will be labeled with after the build and this name should be used in the docker run command.Hi Robin,
thank you for the reply. Turns out the mistake i made was naming my Dockerfile "firefox" instead of "Dockerfile"
Is it possible to do this with Docker Toolbox with VirtualBox?
What should be changed?
This should also be possible with Docker Toolbox.
I can't test it with VirtualBox at the moment. But I can imagine that there could be some issues regarding administrative rights, so maybe you need to run everything elevated to get it working.
I will try to test this myself this week.
I have concerns about connecting graphics in VirtualBox with the host system.
Docker Toolbox uses seperate virtual system (based on Linux) so maybe graphics will be forwarded only to it not to Windows.
But if graphics can be forwarded directly to Windows, it will probably work.
I will post the solution when I find it.
You're right, this could be a problem with forwarding stopping at the virtual system.
I am curious what your results will be!
I tested this and it works!
Display variable should be set to address of host (Windows) computer.
When using
boot2docker
image, newVirtualBox Host-Only Network
will be created. In it, host computer will probably have address192.168.99.1
, soDISPLAY
should be set to192.168.99.1:0.0
If that won't work, new bridged network can be added to
boot2docker
image andDISPLAY
should be set to local address of host.Also, because
boot2docker
image has very low RAM and GPU memory, GUI apps will often crash. This could probably be fixed with higher RAM and GPU memory settings in VirtualBox.Hi Robin!
Thank you for your article but I still have the problem
error: XDG_RUNTIME_DIR not set in the environment.
I have done all you discussed but I cannot make it work, any suggestion?
Thank you
Hey Raquel,
normally this would be set by your WM but sometimes - especially under wsl - sometimes this is not the case.
Try adding the following to your
~/.bashrc
file (applies for your current wsl user):You can choose any folder for
XDG_RUNTIME_DIR
.In case you are wondering what the hell
XDG_RUNTIME_DIR
is...This is an environment variable that any program will access to determine the user specific directory to store small temporary files to. Normally it is set automatically when you log in.
Thanks Robin, I tried it but the error persists....any other ideas? :(
I found this log .... maybe it can help:
Welcome to the VcXsrv X Server
Vendor: The VcXsrv Project
Release: 1.20.8.1
OS: Windows NT 6.2 build 9200 (64-bit)
Contact: marha@users.sourceforge.net
LoadPreferences: C:\Users\RaquelRodriguez\AppData\Roaming.XWinrc not found
LoadPreferences: Loading C:\Program Files\VcXsrv\system.XWinrc
Warning: Locale not supported by X, falling back to 'C' locale.
(II) AIGLX: Testing pixelFormatIndex 1
(II) GLX: enabled GLX_SGI_make_current_read
(II) GLX: enabled GLX_SGI_swap_control
(II) GLX: enabled GLX_MESA_swap_control
(II) GLX: enabled GLX_SGIX_pbuffer
(II) GLX: enabled GLX_ARB_multisample
(II) GLX: enabled GLX_SGIS_multisample
(II) GLX: enabled GLX_ARB_fbconfig_float
(II) GLX: enabled GLX_EXT_fbconfig_packed_float
(II) GLX: enabled GLX_ARB_create_context
(II) GLX: enabled GLX_ARB_create_context_profile
(II) GLX: enabled GLX_ARB_create_context_robustness
(II) GLX: enabled GLX_EXT_create_context_es2_profile
(II) GLX: enabled GLX_ARB_framebuffer_sRGB
(II) AIGLX: enabled GLX_MESA_copy_sub_buffer
(II) 105 pixel formats reported by wglGetPixelFormatAttribivARB
(II) GLX: Initialized Win32 native WGL GL provider for screen 0
winClipboardThreadProc - DISPLAY=127.0.0.1:0.0
Using Composite redirection
OS maintains clipboard viewer chain: yes
winMultiWindowXMsgProc - Fatal error 1 on xcb connection
winClipboardIOErrorHandler!
winClipboardProc - setjmp returned for IO Error Handler.
(II) Server terminated successfully (0). Closing log file.
Hi Robin!
Finally I made it work :)
I'm not sure what was the problem, I just decided to remove the docker image and container, install it again and ...... worked!
Thank you very much :)
Great news! Sometimes it's the best solution to just start over. Glad you got it working 👍😊
Hi,Robin
I'm want to access the webcam **but I cant
**This is docker run command
docker run --privileged --rm -it -e DISPLAY=192.168.56.1:0.0 --device=/dev/video0:/dev/video0 -v /tmp/.X11-unix:/tmp/.X11-unix face2_mysql
This is the error I got
VIDEOIO ERROR: V4L: can't find camera device
VIDEOIO ERROR: V4L: can't find camera device
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/local/lib/python3.7/tkinter/init.py", line 1705, in call
return self.func(*args)
File "/usr/app/Facerec.py", line 105, in FaceRecognition
fraud=self.ObjectDetectionP2(img,c)
File "/usr/app/Facerec.py", line 48, in ObjectDetectionP2
blob = cv2.dnn.blobFromImage(img, 1 / 255, (WidthHeightTarget, WidthHeightTarget), [0, 0, 0], 1, crop=False)
cv2.error: OpenCV(3.4.2) /opt/opencv-3.4.2/modules/imgproc/src/resize.cpp:4044: error: (-215:Assertion failed) !ssize.empty() in function 'resize'
Some comments may only be visible to logged-in visitors. Sign in to view all comments.