20 March 2019 / Last updated: 29 Jan 2021

Running a GUI application with balenaCloud

Execution time: 1hr - 2hr
Difficulty: Medium
Cost: Low
Have you ever got to a point while working on a project where you absolutely had to run a graphical user interface (GUI) application when you only have access to a headless device? This is an issue that one of our engineers Chris faced a while back while working on the Festive Lighting project, where the software to control the lights only had a GUI version.
One solution to this problem lies in running the application on an X11 Window System and accessing it via VNC, and that's what today's post is about!
To get started, you will need an account for balenaCloud. If you are new to the balena ecosystem, take a look at the introduction first, as the initial setup of your account and provisioning a device is outside the scope of this guide.
The goal for this project is to deploy a multi-container project on balenaCloud where we will run a sample GUI application (for this example, a calculator) and access it via VNC.
We won't get into detail on how to create an application on balenaCloud or how to provision a device as it is all well explained in the getting started guide, but if you ever have any questions please let us know on our forums.

Downloading and running the application

The next step is to download the code for this project from GitHub. Go to: https://github.com/balena-io-playground/balena-vnc-example and download the project as shown in the image below:
The blue button pictured will download a .zip file containing the project files, but if you're familiar with Git you can use git clone in the usual way.

Pushing the code to your device

We will first push the code to the device without changing any configuration in order to make sure everything is working.
For this, we will use the balena cli tool, where you can push the code by running balena push <ApplicationName> in the same folder as the project. You can read more about the CLI here.
If everything worked OK, you'll see the unicorn 🦄:
Go back to the dashboard and you’ll be able to see the status of your device downloading and installing everything.
If everything is up and running correctly, you will be able to see a log message saying that gnome-calculator and x11vnc are both running. Good job, now let's go ahead and try to connect to the device and use the calculator.
In order to connect to the device and use the calculator, you will need to download a VNC client. There are many VNC viewer clients out there, but for this tutorial, we'll use RealVNC viewer.
Once VNC Viewer is installed, open it and connect to the **on port 8080**. A few things to keep in mind is that initially, you will only be able to connect to the device locally, meaning that you need to be in the same network. You can find the devices IP address on balenaCloud dashboard as shown in the image below:
In this example, you would connect to: (note that if you are using RealVNC you will need to use double : to specify a non-standard port).

Deploying your own application

In order to change the application to one of your choice, you need to edit the file vnc-app/Dockerfile.template and add the application you want to run to the end. For example, changing it to x11-apps, which installs some x11 sample applications.
FROM balenalib/%%BALENA_MACHINE_NAME%%-debian:stretch-run

RUN install_packages x11vnc \
x11-utils \
xvfb \
wmctrl \
supervisor \
For this project, we are using supervisor, a software made to help run and manage multiple applications within one docker container. As soon as the containers initialize, it starts the supervisor application, which then starts the VNC server and all other applications. The configuration for the default application can be found at vnc-app/supervisor/app.conf. To change the software from gnome-calculator to xeyes, the app.confwill be as shown below:

Adding a password to VNC

If you can't trust your network, the first thing you should consider doing is running the VNC Server with a connection password. Luckily adding a password very simple, in balenaCloud dashboard, go to the Device Environment Variables and add a new value with the name VNC_PASS and value of your password. After adding the password, the VNC container will restart and from now on it will request a password to connect.

Accessing your machine from outside the local network

Being able to only access the application from within your local network may work for your application, but a benefit of balenaCloud is that we can easily set up a way to securely connect to your device over the internet.
For this, you will need to have Balena CLI version v12.38.5 or newer installed. Keep in mind that this feature is currently experimental, so if you find any inconsistency please let us know! 😉
To get started, copy the UUID (universally unique identifier), as shown image above.
Then head to the terminal and run the command (replacing UUID with the device actual value): balena tunnel <UUID> -p 8080:8080
The command creates a tunnel connection from the device on port 8080 to your computer localhost on the same port. So now once the tunnel is activated, open VNC Viewer and connect to localhost:8080, like magic you will be able to control the application remotely 🔮🧙✨.
Done, you are connected!


In this post, we showed how you can run a graphics application on a headless device with the use of a VNC server. We would love to know what GUI programs are you running and hope this project helped you get closer to your goals!
If you have any questions or suggestions about this post, let us know in our forums at https://forums.balena.io, on Twitter @balena_io, on Instagram @balena_io or on Facebook.
Until next time! ;)

Share this post