Running Xorg Virtual Framebuffer, VNC Server, Websocket server and Web/browser-based VNC client from Docker
Base VNC + WebSocket server docker image that aims to simplify the initial setup of a containerized Graphical environment
- x11vnc : VNC server
- websockify : WebSocket server
- novnc : Web/Browser-based VNC client
- Xorg : Display Server
- xauth : Xorg Authorization CLI utility
- Xvfb : Xorg Virtual Framebuffer; Used to create a virtual framebuffer in the memory to allow you to draw/render graphical applications in a virtual environment within the background as a process
- Image Build
- Setup
- Installs dependencies
- Creates a brand new Xauthority cookie file in the HOME directory (default = root, /root)
- Adds a randomly-generated number using the MAGIC-COOKIE-1 algorithm used by xauth into the xauth database
- Entry Point
- Set the DISPLAY environment variable that provides the virtual monitor display to be used by the DISPLAY server
- Startup Virtual Framebuffer environment pointing to the 'DISPLAY' monitor number environment variable
- Startup VNC server pointing to the Virtual Framebuffer environment variable and options
- Startup Websocket server mapping the Websocket server's listening port to the VNC server's host address and port number
- Setup
- docker
- docker-compose
- git
- Select your base image distribution of choice
- alpine
- debian
- nix
- Select your base image
- x11vnc (Recommended)
- tigervncserver (aka xtigervnc)
- (Optional) Change permissions of script (if any)
chmod -R u+x scripts/[base-image-distribution]/
-
Build (Base) Docker image
docker build \ -t thanatisia/websocket-x:latest \ --build-arg VNC_SERVER_PASS=[VNC-server-password] \ --build-arg "FRAMEBUFFER_SCREEN_SPECS=-screen 0 1920x1080x16" \ -f docker/Dockerfiles/[distribution-name]/base/[vnc-server].Dockerfile \ .
-
(Optional) Build multi-stage examples
- Notes
- This is just an example, substitute this with your multi-stage Dockerfiles
- In this example, I will be using the 'docker/Dockerfiles/[distribution-name]/stage-2/examples/bspwm.Dockerfile' dockerfile
docker build \ -t thanatisia/websocket-x:latest \ -f docker/Dockerfiles/[distribution-name]/stage-2/examples/bspwm.Dockerfile \ .
- Notes
- Startup Docker container
- Explanation
-e SHELL=${SHELL}
: Default shell environment variable-p 5900:5900
: Websocket server port-p 6080:6080
: VNC server port-v "/dev/shm:/dev/shm"
: Mount the shm device driver-v "/run/dbus:/run/dbus"
: Mount the host system's device buses--device /dev/snd:/dev/snd
: Passthrough the host system soundcard
docker run -itd \ --name=browser-x \ --restart=unless-stopped \ -e SHELL=${SHELL} \ -p 5900:5900 \ -p 6080:6080 \ -v "/dev/shm:/dev/shm" \ -v "/run/dbus:/run/dbus" \ --device /dev/snd:/dev/snd \ thanatisia/websocket-x:latest
- Explanation
-
Stop container
docker stop browser-x
-
Remove container
docker rm browser-x
-
Using make script
./make.sh
-
Command Line
docker build -t thanatisia/websocket-x:latest --build-arg VNC_SERVER_PASS=[VNC-server-password] -f Dockerfile . && \ docker stop browser-x && docker rm browser-x; \ docker run -itd \ --name=browser-x \ -p 6080:6080 \ -p 5900:5900 \ thanatisia/websocket-x:latest
- Enter container TTY
docker exec -it browser-x /bin/bash
- To use as a base image
- Build the image
- Include the following
- in your Dockerfile
FROM thanatisia/websocket-x:latest AS new-image
- in your docker-compose
image: thanatisia/websocket-x:latest
- in your Dockerfile
- Multi-stage Build Example
- Dockerfiles
- Embedding as a reference (in stage-2.Dockerfile)
FROM thanatisia/websocket-x:latest AS test-container ## Copy files COPY ./test.sh /tmp/test.sh ## Run on startup RUN /bin/bash -c "/tmp/test.sh"
- Building using 'docker build'
# Build Stage 1 image docker build \ --tag thanatisia/websocket-x:latest \ --build-arg VNC_SERVER_PASS=[VNC-server-password] \ --build-arg "FRAMEBUFFER_SCREEN_SPECS=-screen 0 1920x1080x16" \ -f docker/Dockerfiles/[distribution-name]/base/[vnc-server].Dockerfile \ [context] # Build Stage 2 image docker build --tag thanatisia/websocket-x:latest -f stage-2.Dockerfile [context] ... # Build Stage N image docker build --tag thanatisia/websocket-x:latest -f stage-N.Dockerfile [context]
- Starting up container
- Explanation
-e SHELL=${SHELL}
: Default shell environment variable-p 5900:5900
: Websocket server port-p 6080:6080
: VNC server port-v "/dev/shm:/dev/shm"
: Mount the shm device driver-v "/run/dbus:/run/dbus"
: Mount the host system's device buses--device /dev/snd:/dev/snd
: Passthrough the host system soundcard
docker run -itd \ --name=[container-name] \ --restart=unless-stopped \ -e SHELL=${SHELL} \ -p 5900:5900 \ -p 6080:6080 \ -v "/dev/shm:/dev/shm" \ -v "/run/dbus:/run/dbus" \ --device /dev/snd:/dev/snd \ thanatisia/websocket-x:latest
- Explanation
- Embedding as a reference (in stage-2.Dockerfile)
- docker-compose
- Explanation
- The service application 'websocket-x-stage-1' is Stage 1 of the Multi-stage Build
- which will build the image 'thanatisia/websocket-x:latest' using the specified dockerfile (in this case - docker/Dockerfiles/[distribution-name]/base/[vnc-server].Dockerfile)
- The focus of the Dockerfile recipe is on installing dependencies and establishing the ENTRY POINT
- The service application 'websocket-x-stage-2' is Stage 2 of the Multi-stage Build, as well as any other additional stages you require when importing this framework as an image recipe
- For example
- websocket-x-stage-2 could be for installing additional dependencies to be ran and started after the container is built and started up
- For example
- The service application 'browser-x' is your main application after every previous build stages have been completed
- In this service, you do not need to use the 'build' key-value and instead, call for the image directly
- Important Options
tty: true
: The 'tty' key-value in docker-compose is equivalent to the '-t' option/flag in 'docker run', which basically tells docker to keep the TTY/terminal enabled even after the command has ended
- The service application 'websocket-x-stage-1' is Stage 1 of the Multi-stage Build
# Docker compose recipe for running both x11vnc and tigervncserver version: "3.7" services: websocket-x-stage-1: image: thanatisia/websocket-x:latest build: context: . args: - "VNC_SERVER_SPECS=[additional-vnc-server-specifications]" - VNC_SERVER_PASS=[your-vnc-server-password] - "FRAMEBUFFER_SCREEN_SPECS=-screen 0 1920x1080x16" dockerfile: docker/Dockerfiles/debian/base/[vnc-server].Dockerfile websocket-x-stage-2: image: thanatisia/websocket-x:latest build: context: . dockerfile: docker/Dockerfiles/debian/stage-2.Dockerfile #### ... websocket-x-stage-N: image: thanatisia/websocket-x:latest build: context: . dockerfile: docker/Dockerfiles/debian/stage-N.Dockerfile browser-x: image: thanatisia/websocket-x:latest container_name: browser-x restart: unless-stopped environment: ## Environment Variables - SHELL=${SHELL} tty: true ports: ## Port Forward/Translate/Map host system port to container port ## [ip-address]:[host-system-port]:[container-port] - 5900:5900 # VNC Server listening port - 6080:6080 # Websocket server listening port volumes: ## Mount volumes from host system to container ## [host-system-volume]:[container-volume] - /dev/shm:/dev/shm # SHM device - /run/dbus:/run/dbus # Device Buses devices: - /dev/snd:/dev/snd # Passthrough soundcard for audio output
- Explanation
- Dockerfiles
- To invoke and specify:
docker build --build-arg [ARGUMENT_VARIABLE]=[ARGUMENT_VALUE]
- FRAMEBUFFER_OPTS="[DISPLAY-monitor-number] -screen [monitor-number] [width]x[height]x[color-depth/bitrate]" : Set the X Virtual Framebuffer (Xvfb) startup options
- Positionals
- DISPLAY : Specify the $DISPLAY monitor number environment variable (i.e. :0, :1)
- Options
- screen
- monitor-number : Specify the virtual monitor number to display the window; i.e. :0 = 0, :1 = 1
- resolution
- width : Specify the width (horizontal length) of the Virtual Framebuffer's canvas window (i.e. 1920)
- height : Specify the height (vertical height) of the Virtual Framebuffer's canvas window (i.e. 1080)
- color-depth/bitrate : Specify the color density of the Virtual Framebuffer's canvas window (i.e. 16-bit, 32-bit)
- screen
- Positionals
- VNC_SERVER_PASS : Set the VNC server's password to use (Optional; Set '-nopw' in VNC_SERVER_OPTS to not use passwords)
- VNC_SERVER_OPTS="-display :0 -rfbport 5900 -usepw -passwd ${VNC_SERVER_PASS} -xkb -forever -shared" : Set the VNC server's options to startup with
- Notes
- '-bg' is not used to ensure that the ENTRY POINT has a foreground application to keep the container running
- In the case where you would like to use '-bg',
- you can add 'bash' to the last application within the ENTRY POINT block
- Notes
- To invoke and specify:
[ENVIRONMENT_VARIABLE]=[VALUE] docker build
- System
DISPLAY=:0
: DISPLAY virtual monitor number used for Graphical application rendering by the display server (Xorg/Wayland)
- VNC Server
VNC_SERVER_HOST=127.0.0.1
: Set the VNC server's Hostname/IP addressVNC_SERVER_PORT=5900
: Set the VNC server's listening port numberVNC_SERVER_PASS=[your-vnc-server-password]
: Set the VNC server's password
- Websocket server
WEBSOCKET_CLIENT_PATH=/usr/share/novnc
: Set the Web/Browser-based VNC client you wish to access in the websocket serverWEBSOCKET_SERVER_PORT=6080
: Set the WebSocket server's listening port number; This is the port number you access to view the Web/Browser-based VNC/SPICE client
-
x11vnc.Dockerfile : Recommended
- Base Image: docker
- Display Server: Xorg
- VNC server: x11vnc
- Websocket server: websockify
-
xtigervnc.Dockerfile
- Base Image: docker
- Display Server: Xorg
- VNC server: Xtigervnc (Package: tigervnc-standalone-server; aka tigervncserver)
- Websocket server: websockify
- Ports to expose
- 5900 : Default VNC server listening port
- 6080 : Default WebSocket server listening port
- IMAGE_NAME : Specify the name of the image to build
- IMAGE_TAG : Specify the tag/version of the image
- BUILD_ARGS : Set the build arguments to parse into the build process
- Defaults
- --build-arg "VNC_SERVER_PASS=[your-vnc-server-password]"
- --build-arg "FRAMEBUFFER_SCREEN_SPECS=-screen 0 1920x1080x16"
- Defaults
- STAGE_1_DOCKERFILE : Specify the Stage 1 (Base) Dockerfile to build the image with
- CONTEXT : Specify the context (working directory)
- Defaults
- . (Current Working Directory)
- Defaults
- CONTAINER_IMAGE_NAME : Specify the name of the image to startup the container with
- CONTAINER_IMAGE_TAG : Specify the tag/version of the image to startup the container with
- CONTAINER_NAME : Specify the name of the container to startup
- CONTAINER_OPTS : Specify the options to startup the container with
- Defaults
- --restart=unless-stopped
- Defaults
- CONTAINER_PORT_FORWARDING : Specify the ports to forward/translate/map from host system to the container; Format each port entry with '-p [ip-address]:[host-system-port]:[container-port]' and separate each entry with a space delimiter
- Defaults
- -p 5901:5900
- -p 6080:6080
- Defaults
- CONTAINER_MOUNT_VOLUMES : Specify the volumes to mount from host system to the container; Format each mount point entry with '-v [host-system-volume]:[container-volume]:[permission]' and separate each entry with a space delimiter
- Defaults
- -v "/dev/shm:/dev/shm"
- -v "/run/dbus:/run/dbus"
- Defaults
- CONTAINER_PASSTHROUGH_DEVICE : Specify the devices to passthrough from the host system to the container; Format each device entry with '--device [host-system-device]:[container-mount-point]' and separate each entry with a space delimiter
- Defaults
- --device "/dev/snd:/dev/snd"
- Defaults
- build-stage-1: Build image from Dockerfile
- run: Startup a container from an image
- start: Start the container if stopped and exists
- stop: Stop the container if running
- restart: Restart the container if running
- remove: Remove the container if exists
- logs: Display logs of the container
- gif: Make/generate the demo animation gif for the software documentations using VHS (by charmbracelet)
-
Full run
- Explanation
- Parameters
- -k : Continue and keep going even if errors are encountered
- Targets
- stop : Stop the container
- remove : Remove the container
- build-stage-1 : Build the stage 1 image
- run : Startup a container using the image
- logs : Display logs after running
- Parameters
make -k stop remove build-stage-1 run logs
- Explanation
-
Parse customized optional values
ENVIRONMENT_VARIABLE="new_value" ... make -k [targets]
-
Restart container manually
make restart
-
Build a new image
make -k stop remove build-stage-1
-
Build a new image and run
make stop remove build-stage-1 run
-
Generate a demo animation gif for software documentations using the docker image of the 'vhs' CLI utility by charmbracelet
make gif
- To change the base image support
- Notes
- The following is assuming that
- You are using the repository in its current structure, you can change it according to your needs by following the structure/format
- You are using the same naming (i.e. container name or image name), take note of your custom image/container names if you are changing it
- The following is assuming that
- Open the Makefile
$EDITOR Makefile
- Edit the following
- IMAGE_TAG : Set this to the base image you wish to use
- CONTAINER_IMAGE_TAG : Same as 'IMAGE_TAG'
- STAGE_1_DOCKERFILE : Specifically change the base image directory name in 'docker/Dockerfiles/[base-image-directory]'
- Notes
- root/ : Project root directory
- docker/ : Contains all docker contents
- Dockerfiles/ : Contains all Dockerfile recipes
- debian/ : Contains debian-based base images for the websocket + VNC server project; You can use these as references and build your own
- stage-2/ : Contains all Stage-2 (aka Post-Installation) Dockerfiles that you use to build on top of the base images (in a multi-staged build); You can use these as references and build your own
- examples/ : This is the example directory containing example Dockerfiles for the multi-stage builds
- Dockerfiles/ : Contains all Dockerfile recipes
- scripts/ : Place all your launcher/runner helper scripts that will be executed in the containers here
- alpine/ : Place all alpine-based helper scripts here
- debian/ : Place all debian-based helper scripts here
- nix/ : Place all nix-based helper scripts here
- '*' : All other remainder scripts
- docker/ : Contains all docker contents
-
docker/Dockerfiles/[distribution-name]/base/
- x11vnc.Dockerfile : Stage-1 dockerfile that builds up a (Websocket Server + VNC Server + Xorg(11) headless backend via Xvfb) stack using (websockify + x11vnc + Xvfb)
-
docker/Dockerfiles/[distribution-name]/stage-2/examples/
- bspwm.Dockerfile : Stage-2 example dockerfile that installs and starts up BSPWM and SXHKD