├── .gitignore ├── Dockerfile ├── LICENSE.md ├── README.md ├── Story.md └── docker-entrypoint.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | MAINTAINER Jan Suchotzki 3 | 4 | # first create user and group for all the X Window stuff 5 | # required to do this first so have consistent uid/gid between server and client container 6 | RUN addgroup --system xusers \ 7 | && adduser \ 8 | --home /home/xuser \ 9 | --disabled-password \ 10 | --shell /bin/bash \ 11 | --gecos "user for running X Window stuff" \ 12 | --ingroup xusers \ 13 | --quiet \ 14 | xuser 15 | 16 | # Install xvfb as X-Server and x11vnc as VNC-Server 17 | RUN apt-get update && apt-get install -y --no-install-recommends \ 18 | xvfb \ 19 | xauth \ 20 | x11vnc \ 21 | x11-utils \ 22 | x11-xserver-utils \ 23 | && rm -rf /var/lib/apt/lists/* 24 | 25 | # create or use the volume depending on how container is run 26 | # ensure that server and client can access the cookie 27 | RUN mkdir -p /Xauthority && chown -R xuser:xusers /Xauthority 28 | VOLUME /Xauthority 29 | 30 | # start x11vnc and expose its port 31 | ENV DISPLAY :0.0 32 | EXPOSE 5900 33 | COPY docker-entrypoint.sh /entrypoint.sh 34 | RUN chmod +x /entrypoint.sh 35 | 36 | # switch to user and start 37 | USER xuser 38 | ENTRYPOINT ["/entrypoint.sh"] 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | Docker Image for creating a service container providing an framebuffered X11-Server ([xvfb](http://www.x.org/archive/X11R7.6/doc/man/man1/Xvfb.1.xhtml)) in conjunction with a VNC-Server ([x11vnc](http://www.karlrunge.com/x11vnc/)). It allows to get the display of an application running inside a docker container to the host or any other machine accessing the VNC-Server. 3 | 4 | It is intended to be used in conjunction with at least one other container hosting the application requiring an X-Server (aka X-Client). This differentiates it from other solutions running the X-Server, the VNC-Server and the X-Client in the same container. 5 | 6 | A base image for creating a container with an application using this X11 server container can be found [here](tbd). 7 | 8 | My intention for this image was to have a clear separation of concerns. This image is responsible for all the X-Server stuff. Another image can fully concentrate on the application and is simply linked to a container of this image. 9 | 10 | More details can be found [here](https://github.com/suchja/x11server/blob/master/Story.md). 11 | 12 | ## Usage 13 | 14 | Running a container based on this image is quite easy. It is intended to be run as daemon. So you can run via: 15 | 16 | `docker run -d --name display -e VNC_PASSWORD=newPW -e XFB_SCREEN=1280x800x24 -e XFB_SCREEN_DPI=150 -p 5900:5900 suchja/x11server` 17 | 18 | You should give it a name (here `display`), because a container running the client should be linked with this container. Forwarding the port `5900` allows you to access the VNC server from within your network. 19 | 20 | ### Environment Variables 21 | When you start the `x11server` image, you should adjust at least some of its configuration. 22 | 23 | Hint: In case you don't like to type the environment variables on the command prompt, docker run can also read it from a config file (see [here](https://docs.docker.com/reference/commandline/cli/#examples_8)). Especially for passwords (see below) this this should be done to prevent any issues with your shell history (see [here](http://linuxcommando.blogspot.de/2014/07/hide-command-from-bash-command-line.html)). 24 | 25 | `VNC_PASSWORD` 26 | 27 | This variable is mandatory and specifies the password you need to enter into your VNC-client when connecting to the VNC-Server running in a container from this image. 28 | 29 | `XFB_SCREEN` 30 | 31 | Specifies screen width, height, and depth (WxHxD). By default, screen has the dimensions 1024x768x24. 32 | 33 | `XFB_SCREEN_DPI` 34 | 35 | Specifies DPI for the display (Dots Per Inch). If not specified, uses the default DPI (100). 36 | 37 | ### docker-compose 38 | You can use `docker-compose` to avoid typing or copy-and-pasting all the stuff again and again on the command line. Here an excerpt from a `docker-compose.yml` file starting a container from this image: 39 | 40 | ``` 41 | xserver: 42 | image: suchja/x11server 43 | ports: 44 | - 5900:5900 45 | environment: 46 | VNC_PASSWORD: yourPW 47 | XFB_SCREEN: 1280x800x24 48 | XFB_SCREEN_DPI: 150 49 | ``` 50 | 51 | Save this inside `docker-compose.yml`, add a proper password and call `docker-compose up`. Now you will have a running X11 server waiting for X11 clients and VNC clients to connect. 52 | 53 | ## Maintenance 54 | The image is build on Docker hub with [Automated builds](http://docs.docker.com/docker-hub/builds/). There is no dedicated maintenance schedule for this image. It is relying on packages from `debian:jessie` and thus I do not assume to update it frequently. 55 | 56 | In case you have any issues, you are invited to create a pull request or an issue on the related [github repository](https://github.com/suchja/x11server.git). 57 | 58 | ## Copyright free 59 | The sources in [this](https://github.com/suchja/x11server.git) Github repository, from which the docker image is build, are copyright free (see LICENSE.md). Thus you are allowed to use these sources (e.g. Dockerfile and README.md) in which ever way you like. 60 | -------------------------------------------------------------------------------- /Story.md: -------------------------------------------------------------------------------- 1 | #Dockerizing X11 Applications - A multi-container approach 2 | 3 | ##What's the probelm? 4 | Trying to run an application inside a container which requires the X Window system is not really difficult, but also not as easy as it seems. There are several ways of dealing with this: 5 | 6 | - Using the host's X Server via shared X11 sockets. Here is a really good [article](https://blog.jessfraz.com/posts/docker-containers-on-the-desktop.html) showing different options. 7 | - Forwarding the display via ssh -X. An approach used by several images and described in [this](http://blog.docker.com/2013/07/docker-desktop-your-desktop-over-ssh-running-inside-of-a-docker-container/) article. 8 | - Run a VNC server along with the X server. Also for this solution several images exist. One example can be found [here](https://docs.docker.com/reference/builder/#dockerfile-examples) 9 | 10 | The solution I'm looking for shall be completely host independent so you can deploy it everywhere. This also means that for me seeing the output on the X11 server is usually only required for debugging purposes. 11 | 12 | Now my problem to solve is how to use [Wine](https://www.winehq.org) and [WiX toolset](http://wixtoolset.org) for building MSI-files (Microsoft Windows installer) inside a container. Usually it is a workflow which does not require any user interaction and thus displaying something on an X Window is not required. However, one of the first problems for me was to properly setup the complete environment. During this process I often needed to have a look into the output of wine or the applications running within. 13 | 14 | So that basically means I need to run the X11 server the whole time to ensure wine and its applications stop complaining about the missing window system. From time to time I need to have a look into the output from wine, but only if it does not work as expected. Finally I would like to run my solution anywhere and be inline with docker's best practices (e.g. avoid runing an sshd inside a container). 15 | 16 | Thus I'll go the VNC path, but ensure that the X11 server is running even if no client is connected to the VNC server. 17 | 18 | My first approach was to put everything (source code for building MSI files, WiX toolset, Wine, X11 server, VNC server, ...) inside a single docker image. This resulted in a very large and unhandy image. Rebuilding the complete image or adding a new package tooke quite some time, because around 200 packages needed to be downloaded and installed. 19 | 20 | ##SRP to the rescue 21 | Why not applying well known and good software development principles to the process of setting up docker images? So I decided to have some more docker images and following the single responsibility principle. This seems to me the docker way anyway. 22 | 23 | So the solution comprises the following docker images: 24 | 25 | - [suchja/x11server] - This image runs X11 server and VNC server. It provides a magic cookie for an X11 client to connect to the server and requires the user to set a password for the VNC connection. Additionally it is possible to configure some parameters of the X11 server via environment variables. In the future I'll have a look into further securing the access to this image. 26 | - [suchja/x11client] - Uses the magic cookie from X11 server to prepare for an authenticated connection to it. It is intended as a base image for an application requiring X11 access. 27 | - [suchja/wine] - My sample application to verify that the X11 acess works as expected. It is derived `FROM suchja/x11client`. Additionally it also uses an entrypoint script to use wine as the command which is always run when the container is started. 28 | - [suchja/x11tools] - Even though not required for my initial application, it might be a good idea to get some screenshots or maybe even videos from the running X11 server. Thus this image could provide some additional tools for accessing the X11 server. 29 | 30 | ##Keep it easy with docker-compose 31 | One of the problems with using several containers is that you need to start and properly link them. Remembering long commands and typing them again is not that nice. Therefore `docker-compose` can help you. 32 | 33 | Setting up my environment with wine requires the following `docker-compose.yml`: 34 | 35 | ``` 36 | X11server: 37 | image: suchja/x11server 38 | ports: 39 | - 5900:5900 40 | environment: 41 | VNC_PASSWORD: yourPW 42 | 43 | X11App: 44 | image: suchja/wine 45 | links: 46 | - X11Server:xserver 47 | volumes_from: 48 | - X11Server 49 | ``` 50 | 51 | 52 | ##Experience and other use cases 53 | After several experiments, I'm now satisfied with the solution. The `x11server` and `x11client` images are really flexible and dedicated to mainly one responsibility. I can also choose whether to start the server at all. When running the x11 application (e.g. my `wine` container) on a hosting plattform, I can do so without running the `x11server` and thus save resources (although the application might give some warnings about the missing X11 server). 54 | 55 | I admit that my problem with building MSI files inside a container might be very specific. Thus this is likely not that interessting for you. However, there are a lot of use cases in the area of building software and especially automated testing of software, where you might require an X11 system without actually looking at it. Here I hope the images will help you running this inside containers. -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$VNC_PASSWORD" ]; then 4 | echo >&2 'error: No password for VNC connection set.' 5 | echo >&2 ' Did you forget to add -e VNC_PASSWORD=... ?' 6 | exit 1 7 | fi 8 | 9 | if [ -z "$XFB_SCREEN" ]; then 10 | XFB_SCREEN=1024x768x24 11 | fi 12 | 13 | if [ ! -z "$XFB_SCREEN_DPI" ]; then 14 | DPI_OPTIONS="-dpi $XFB_SCREEN_DPI" 15 | fi 16 | 17 | # first we need our security cookie and add it to user's .Xauthority 18 | mcookie | sed -e 's/^/add :0 MIT-MAGIC-COOKIE-1 /' | xauth -q 19 | 20 | # now place the security cookie with FamilyWild on volume so client can use it 21 | # see http://stackoverflow.com/25280523 for details on the following command 22 | xauth nlist :0 | sed -e 's/^..../ffff/' | xauth -f /Xauthority/xserver.xauth nmerge - 23 | 24 | # now boot X-Server, tell it to our cookie and give it sometime to start up 25 | Xvfb :0 -auth ~/.Xauthority $DPI_OPTIONS -screen 0 $XFB_SCREEN >>~/xvfb.log 2>&1 & 26 | sleep 2 27 | 28 | # finally we can run the VNC-Server based on our just started X-Server 29 | x11vnc -forever -passwd $VNC_PASSWORD -display :0 30 | --------------------------------------------------------------------------------