TigerVNC Setup on NVIDIA JetPack

Introduction

In this article, we’ll be setting up a VNC server and client on a Jetson Xavier NX that will allow us to connect to an XFCE4 desktop environment. While the tutorial is specific to the aforementioned platform, the instructions should also work for other Jetson products running Ubuntu 18.04.

For most of my development work, SSH terminals are enough to accomplish what I need. But when visualizations are required, or the data output is graphical in nature, then it’s extremely helpful to have a GUI.

TigerVNC Logo

Developing on a headless server means that we need to be able to create a desktop environment instance and somehow pipe that monitor over a secure tunnel to the client computer. This is exactly what TigerVNC does, and we’ll be using it to create a remote desktop environment on a Jetson Xavier NX. TigerVNC is also still being actively developed, and so I can expect improvements and security patches as time goes on.

I’ll also note that the default VNC server on NVIDIA JetPack is currently vino. In order to get this to work, you have to enable automatic login on your Xavier NX, since the VNC server only initializes after login. I didn’t want to sacrifice security to setup the VNC, especially since so many other solutions don’t have this requirement, like TigerVNC.

The NVIDIA Jetson Xavier NX

Before we go into the server and client setup, for those that are not aware of the Jetson-series of products, the Jetson Xavier NX is a System-on-Module (SOM), a computer, with:

  • 384 NVIDIA CUDA cores
  • 48 Tensor cores
  • 6 Carmel ARM CPUs
  • 2 NVIDIA Deep Learning Accelerators (NVDLA) engines
  • 8GB 128-bit LPDDR4x for 51.2GB/s of memory bandwidth
  • Micro-SD card slot (the module version has 16 GB of eMMC 5.1)
  • 2x MIPI CSI-2 D-PHY lanes (for cameras)
  • 4x USB 3.1 ports, 1x USB 2.0 Micro-B
  • HDMI & DP
  • GPIOs, I2C, I2S, SPI, UART

It’s quite a capable SOM that can be used for a variety of tasks, such as developing deployable vision solutions at the edge. It makes a perfect, low-cost, low-energy development server for a variety of tasks, but especially computer vision and deep learning tasks.

Server Side Setup

Open a terminal on the Jetson Xavier NX and install the dependencies:

# Ubuntu/Debian
$ sudo apt install tigervnc-standalone-server tigervnc-xorg-extension xfce4 xfce4-goodies
# Manjaro/Arch
$ sudo pacman -S xfce4-gtk3 xfce4-goodies xfce4-terminal network-manager-applet xfce4-notifyd-gtk3 xfce4-whiskermenu-plugin-gtk3 tumbler engrampa

Setup a VNC password:

$ vncpasswd

Create a ~/.vnc/xstartup file and place the following contents:

#!/bin/sh# Start XFCE4 Desktop
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
export XKL_XMODMAP_DISABLE=1
autocutsel -fork
startxfce4 &
  • SESSION_MANAGER suppresses complaints from the desktop environment
  • DBUS_SESSION_BUS_ADDRESS must be unset to segregate the remote session from existing session, essentially sandboxing the remote desktop session.
  • XKL_XMODMAP_DISABLE prevents differing keyboard layouts from becoming overriden by the server’s default keyboard layout.
  • autocutsel -fork attempts to share the clipboard between the two sessions.
  • startxfce4 starts the desktop environment.

Now, all we need to do is to startup TigerVNC (1920x1080, 24-bit color, display 1):

$ vncserver -depth 24 -geometry 1920x1080 :1

But, we don’t want to have to run this command at startup if this is going to be the main way to interact with the Xavier NX. So instead, we will create a SystemD service template to accomplish this task.

First, create a /etc/systemd/system/vncserver@.service file and add these contents, where your_username is the username of the server’s VNC user that will own the session:

[Unit]
Description=Systemd VNC server startup script
After=syslog.target network.target
[Service]
Type=forking
User=simeon
ExecStartPre=-/usr/bin/vncserver -kill :%i &> /dev/null
ExecStart=/usr/bin/vncserver -depth 24 -geometry 1920x1080 :%i
PIDFile=/home/<your_username>/.vnc/%H:%i.pid
ExecStop=/usr/bin/vncserver -kill :%i
[Install]
WantedBy=multi-user.target

There are a few things to note about our configuration:

  • This is an Ubuntu specific script, since vncserver is a distribution-specific script in itself for the underlying Xvnc server.
  • Kill any server currently running on display %i before launching a new server.
  • Assume a 1920x1080, 24-bit RGB color display.
  • Log the sessions in a pid file, where %H is the host name, and %i is the display number.

We’ll create a default server profile in /etc/default/vncserver:

VNCSERVERS="1:<your_username>"

You may be wondering why 1 is selected here. This is the X server’s display number. You might have to select a different one. List them out by the following command:

$ (cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done)
:1

Only display 1 is listed here, so that’s what I put into the vncserver defaults. Change the default display number — and other places in the configuration where this display number is required — to your OS’s appropriate display number.

Finally, we’ll setup a default config to be applied to any VNC server in ~/.vnc/config:

geometry=1920x1080
localhost
alwaysshared
  • geometry is the default resolution.
  • localhost only accepts connections from the localhost (server). This makes the server more secure, since it requires a local account or an SSH tunnel to access the VNC server.
  • alwaysshared means to give each connection its own session rather than disconnecting a connected user.

Setup a VNC password for the root user:

$ su - <your_username>
$ vncpasswd

Now, we’re finally ready to start and enable our server to be launched at boot:

$ sudo systemctl daemon-reload
$ sudo systemctl start vncserver@1
$ sudo systemctl enable vncserver@1

Client Side Setup

The server side setup has a few rammifications: 1) clients are only allowed to connect via localhost, and so we must setup an SSH tunnel to access the VNC server, and 2) TigerVNC is, by default, insecure, and so SSH is all but required to ensure safe access to your server. So, we will setup an SSH tunnel from the client to the server.

I chose to setup a service for this purpose, because I don’t want to type out the ssh command everytime I wanted to connect to the VNC server. If you feel uncomfortable about your own arrangement, then feel free to skip this step.

Create a/etc/systemd/system/secure-tunnel@.service file:

[Unit]
Description=Setup a secure tunnel to %i
After=network.target
[Service]
EnvironmentFile=/etc/default/secure-tunnel@%i
ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -L ${LOCAL_PORT}:localhost:${REMOTE_PORT} ${USER}@%i
# Restart every >2 seconds to avoid StartLimitInterval failure
RestartSec=5
Restart=always
[Install]
WantedBy=multi-user.target
  • -N causes the session to not execute a remote command, such as when you just want to forward ports and don’t want an interactive session.
  • -T disables psuedo-tty allocation, since stdin isn’t a terminal application.
  • ServerAliveInterval is the number of seconds to wait before sending a null packet to the server (to keep the session alive).
  • ServerAliveInterval causes the ssh session to exit (with an error) if the port forwarding fails. This will give us useful information in the syslog, if there is any trouble.
  • RestartSec=5 is set that way to allow a clean teardown before restarting the service.

Next, we’ll create a configuration for the server_hostname target. Create a /etc/default/secure-tunnel@<server_hostname> file and fill in the contents:

USER=<your_username>
LOCAL_PORT=5901
REMOTE_PORT=5901

Finally, we’re ready to start and enable our SSH tunnel. Start and enable the secure-tunnel service, where server_hostname is the IP address or hostname of the Xavier NX.

$ sudo systemctl daemon-reload
$ sudo systemctl start secure-tunnel@<server_hostname>
$ sudo systemctl enable secure-tunnel@<server_hostname>

Remmina is a nice VNC viewer that lets you save configurations easily and access different servers with a double click. But feel free to use your own; there are many. Install the prerequisites for Remmina by the following command (or use whatever is appropriate for your distribution):

$ sudo pacman -S remmina libvncserver     # Arch/Manjaro
$ sudo apt install remmina remmina-plugin-vnc # Debian/Ubuntu

Use the GUI to select a VNC-type server and input 127.0.0.1:5901 as the server address. Enter your VNC password, and if all goes well, you should see this:

XFCE4’s Desktop Environment on a Jetson Xavier NX

Success (I hope)! I’ll note that I did try to do this same procedure with Ubuntu’s default GNOME desktop environment but could not see anything but a blank screen. It’s probably for the best, since XFCE is lighter than GNOME anyways and better suited for remote desktop applications.

Happy VNC’ing!

Summary

  • Installed and configured TigerVNC server on the Jetson Xavier NX.
  • Installed and configured an SSH tunnel and a VNC viewer, Remmina, on a client computer.

Further Resources

Imaging Systems Ninjaneer, Computer Vision, Photographer and Videographer, VR Athlete, Pianist