VNC Virtual Desktop on a Headless Server

I recently worked on a project that required me to run a program that required a GUI to run. This was a bit of a challenge because I was working on a remote server that did not have a physical display (it was “headless”). After many hours of searching/trying, I found a solution that worked. The following are my notes on how to get it working; I hope it helps you if you are in a similar situation!

Note: I have seen a few other people using programs like TeamViewer to access a remote server with a virtual desktop. I personally never got this working because it requires a physical display to be connected to the server, but it may work for you.

Installation & Setup

Install TigerVNC on the server

sudo apt install tigervnc-standalone-server -y

TigerVNC is just one of many VNC servers available. I tried several and found it to be the easiest to setup and use.

Start the VNC server

When you start the VNC server, you will be prompted to set a password. This password will be used to connect to the server from a client.

You can also optionally choose to set

  • a virtual display number, e.g. :9 (default is :1)
  • a “geometry” for the screen (e.g. 1920x1080)
# create a virtual display (#9) with a screen size of 1920x1080
vncserver -localhost no -geometry 1920x1080 :9

The final output should be something like:

New 'MACHINE:9 (USER)' desktop at :9 on machine MACHINE

Once the display is created, you can connect to it using a VNC client.

Headless Linux Desktop Environment

If you are connecting to a Linux server without a physical display, you will need to install a dummy XServer for the VNC server to use.

sudo apt install xterm xserver-xorg-video-dummy

Viewing the VNC display

To view the VNC display, you will need a VNC client. There are many available, select the one that works best for you. I personally use the built in one on Mac. Instructions below:

Mac VNC Viewer

You need to forward the port of the VNC server (5909 above) to your local machine over SSH, and have a stable connection open. Then you can open the viewer with:

open vnc://localhost:5909

Note: the port number is 5900+N where N is the display number you chose when starting the VNC server.

Programmatic Access to the Virtual Display

In order for programs to access the virtual display, you need to set the DISPLAY environment variable to the virtual display number (e.g. :9).

export DISPLAY=:9

With this set, you can run code that requires a display (e.g. matplotlib, ai2thor, etc.) without ever needing to physically interact with the server/machine. Super useful for working on the cloud!

Note: Within your code itself, you may also need to set the DISPLAY environment variable to the corresponding display number to get it to run correctly (e.g., in Python: os.environ['DISPLAY'] = ':9').

Troubleshooting / Tips

Fixing issues with the virtual screen

Status of all VNC displays

You can check the status of the VNC server and all virtual displays with:

vncserver -list

The following is an example of the output with a stale screen:

TigerVNC server sessions:

X DISPLAY #	PROCESS ID
:9	30309 (stale)

Kill the virtual display

If the virtual display is stale, you can kill it with:

vncserver -kill :9

Change the password

If you need to change the password, run:

vncpasswd

References