1. Overview

In this tutorial, we’ll see how to remotely start the GNOME session of a user whose Ubuntu 22.04 desktop is shared via SSH among any number of computers. This can be done either in view-only mode or by allowing all connected computers to interact with the same desktop, with copy and paste between remote and local computers enabled.

We’ll focus on scenarios where physical access to the Linux server isn’t possible. We’ll also assume that we can’t take advantage of any existing remote desktop solutions. As a result, we can only use the terminal over SSH to configure the remote server.

With a little tweaking, our commands can work with any recent Linux distribution and graphical environment.

2. Preparing the Server

Our test machine running Ubuntu Server 22.04 has IP 95.179.179.225 and initially has root access only. First, let’s make sure all packages are up to date:

$ ssh [email protected]
# apt update && apt upgrade
# reboot

We rebooted because there was a new kernel among the updates. Let’s check the status of the firewall, which in our case is UFW:

$ ssh [email protected]
# ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
22/tcp (v6)                ALLOW       Anywhere (v6)

UFW tells us that only SSH connections are allowed because SSH port 22 is the only one open. For our purposes, this is good and desirable.

Before moving on, let’s use adduser and usermod to add a regular user with sudo privileges, as we’ll need it for all the following steps:

# adduser francesco
# usermod -aG sudo francesco
# exit
logout
Connection to 95.179.179.225 closed

Now let’s log in as the new user:

$ ssh [email protected]

Finally, we’re ready to install the GNOME graphical environment using the ubuntu-desktop task:

$ sudo apt install ubuntu-desktop^ # the char ^ indicates that it's a task
[...]
2 upgraded, 1073 newly installed, 0 to remove and 1 not upgraded.
Need to get 636 MB of archives.
After this operation, 2174 MB of additional disk space will be used.
[...]

At the end of the installation, let’s reboot the system.

3. VNC Over SSH Tunnel

VNC (Virtual Network Computing) allows us to remotely control a computer as if we’re sitting in front of it. It sends the keyboard and mouse inputs from our client to the remote Linux server, and in return, it sends back the graphical screen updates. It can also support copy and paste from local to remote machines and vice versa, and can also dynamically adjust the screen resolution to the client’s window size. Under the hood, it can also optimize the technical transmission details based on the bandwidth.

When we establish a VNC session through an SSH tunnel, it creates a secure pathway for transmitting the server’s graphical desktop interface over the Internet.

We’ll use TigerVNC, a robust and actively maintained VNC server and client. It supports all the features we can expect from a VNC.

3.1. Recommendations

Before using TigerVNC, we need to be clear about these things:

  • We cannot start the TigerVNC server for a user who is already logged into a graphical session
  • Let’s avoid running TigerVNC as root, as some things may not work properly
  • Instead, TigerVNC is designed to run as a systemd service started by a non-root user with sudo privileges
  • The display server must be X11 since there is no support for Wayland

In our case, none of these recommendations should be a problem. Currently, there are no users already logged into GNOME, we’re logged in via SSH as a regular user with sudo privileges, and GNOME sessions are bootable in both X11 and Wayland.

As for the display server, let’s check the contents of the /usr/share/xsessions folder:

$ ls /usr/share/xsessions
ubuntu-xorg.desktop  ubuntu.desktop

Each .desktop file represents a different session or desktop environment that we can choose to log into:

  • ubuntu-xorg.desktop → GNOME with the X11 display server
  • ubuntu.desktop → GNOME with the Wayland display server

So, in the TigerVNC configuration, we need to specify to use the ubuntu-xorg session, as we’ll see in a moment.

3.2. Setting up TigerVNC Server

First, let’s install it:

$ sudo apt install tigervnc-standalone-server

Next, let’s use vncpasswd to set a password for the current user’s VNC session. As for the optional view-only password, it allows us to see the desktop, but without any interaction:

$ vncpasswd
Password:
Verify:
Would you like to enter a view-only password (y/n)? n
A view-only password is not used

Just out of curiosity, we can see that vncpasswd created this file:

$ file ~/.vnc/passwd
/home/francesco/.vnc/passwd: OpenPGP Public Key

Then, we’ll need to edit /etc/tigervnc/vncserver.users to specify the mapping of user, port, and display numbers, starting from display 2 onward. Let’s use tee:

$ echo ':2=francesco' | sudo tee -a /etc/tigervnc/vncserver.users
:2=francesco

$ cat /etc/tigervnc/vncserver.users
# TigerVNC User assignment
[...]
:2=francesco

This means that the user francesco can start or connect to the VNC session identified as display number 2, which is essentially a unique identifier for francesco‘s session. This also means that francesco will connect to the VNC server using port number 5902 because the port number is given by the sum of the display number to 5900.

Finally, let’s use nano to create the configuration file ~/.vnc/config:

$ nano ~/.vnc/config

Inside the file opened with nano, let’s write and save these general options:

session=ubuntu-xorg
alwaysshared
localhost
geometry=1280x800

Let’s break down each line:

  • session=ubuntu-xorg → as discussed above, this should match one of the files in /usr/share/xsessions
  • alwayssharedallows multiple VNC clients to connect to the server at the same time and share the same user session
  • localhost → permits SSH connections and blocks non-SSH connections
  • geometry=1280×800 → starting resolution of the VNC session

Other possible options are documented in the xvnc man page.

3.3. Starting TigerVNC Server

Let’s create the TigerVNC service unit file by copying [email protected], which is just a template:

$ cd /usr/lib/systemd/system
$ sudo cp [email protected] tigervncserver@:2.service

Thus, tigervncserver@:2.service is a new service file specifically for display number 2, assigned to francesco according to our previously edited vncserver.users file.

Let’s start the service as francesco and check its status:

$ systemctl start tigervncserver@:2.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to start 'tigervncserver@:2.service'.
Multiple identities can be used for authentication:
 1.  guest (ubuntu)
 2.  francesco,,, (francesco)
Choose identity to authenticate as (1-2): 2
Password: 
==== AUTHENTICATION COMPLETE ===

$ systemctl status tigervncserver@:2.service
● tigervncserver@:2.service - Remote desktop service (VNC)
     Loaded: loaded (/lib/systemd/system/tigervncserver@:2.service; disabled; vendor preset: enabled)
     Active: active (running) since Fri 2023-12-15 19:04:45 UTC; 19s ago
    [...]
             ‣ 4341 /usr/sbin/tigervncsession francesco :2

The VNC server is up and running. Let’s do another check by listing all running tigervncserver sessions:

$ tigervncserver -list

TigerVNC server sessions:

X DISPLAY #    RFB PORT #    RFB UNIX PATH    PROCESS ID #    SERVER
2             5902                           4348            Xtigervnc

Optionally, we can also instruct the system to automatically start the TigerVNC server for display :2 every time the system boots to ensure that the VNC server is always running and available for remote connections:

$ systemctl enable tigervncserver@:2.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-unit-files ===
Authentication is required to manage system service or unit files.
Multiple identities can be used for authentication:
 1.  guest (ubuntu)
 2.  francesco,,, (francesco)
Choose identity to authenticate as (1-2): 2
Password: 
==== AUTHENTICATION COMPLETE ===
Created symlink /etc/systemd/system/multi-user.target.wants/tigervncserver@:2.service → /lib/systemd/system/tigervncserver@:2.service.
==== AUTHENTICATING FOR org.freedesktop.systemd1.reload-daemon ===
[...]
==== AUTHENTICATION COMPLETE ===

The VNC server is ready and waiting for connections.

3.4. Creating an SSH Tunnel

We can use the VNC client we prefer. Either way, xtigervncviewer makes creating an SSH tunnel as easy as possible. Let’s install it:

$ sudo apt update
$ sudo apt install tigervnc-viewer

*This command is sufficient to connect to our VNC server at IP 95.179.179.225, francesco‘s session :2, port 5902, via SSH tunnel:*

$ xtigervncviewer -via 95.179.179.225 localhost::5902

TigerVNC Viewer 64-bit v1.12.0
Built on: 2022-03-25 17:06
Copyright (C) 1999-2021 TigerVNC Team and many others (see README.rst)
See https://www.tigervnc.org for information on TigerVNC.
[email protected]'s password: 
[...]

The first password prompt in the terminal refers to the SSH connection, the second in a graphical window refers to the VNC session password previous created with vncpasswd.

Let’s experiment with our VNC connection and verify that we have the full Ubuntu desktop with everything working:

Copying and pasting from the VNC client to the local machine and vice versa works. Also, if we close the VNC connection, when we reopen it, we find the desktop as we left it.

If we repeat the same xtigervncviewer command, we can connect to the same session from different machines without any problem.

4. Conclusion

In this article, we’ve seen how to start a GNOME session on an Ubuntu 22.04 remote desktop shared via SSH. We assumed that physical access to the Linux server wasn’t possible and that we couldn’t use existing remote desktop solutions.

By preparing the server and setting up TigerVNC over an SSH tunnel, we established a secure and efficient way to access the remote desktop. This approach allows not only a view-only mode but also interactive sessions where multiple users can collaborate on the same desktop. The added functionality of copy and paste between remote and local systems further enhances the usability of this setup.

The methods and commands introduced are adaptable to various Linux distributions and graphical environments, making this tutorial broadly applicable.