VNC (Virtual Network Computing) shares a graphical desktop over the network, and TigerVNC is the most widely used VNC server on Linux. In this tutorial you will install TigerVNC and the lightweight Xfce desktop on an Ubuntu 24.04 server, run the VNC server as a systemd service that starts at boot, and connect to it through an SSH tunnel so the desktop is never exposed to the internet.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS with at least 2 GB of RAM, for example a CubePath VPS.
  • A non-root user with sudo privileges. This guide uses your_user; replace it with your username everywhere.
  • SSH access to the server from your computer.
  • A VNC client on your computer, such as TigerVNC Viewer (Windows, macOS, Linux) or Remmina (Linux).

Step 1 - Installing Xfce and TigerVNC

Update the package index and install the Xfce desktop together with the D-Bus launcher it needs:

sudo apt update
sudo apt install xfce4 xfce4-goodies dbus-x11

If apt asks which display manager to use, choose either one. VNC does not use it, and the next command keeps it from starting at boot:

sudo systemctl set-default multi-user.target

Install the TigerVNC server:

sudo apt install tigervnc-standalone-server tigervnc-tools

tigervnc-standalone-server provides the Xtigervnc server and the vncserver wrapper script, and tigervnc-tools provides vncpasswd. Check the installed version:

vncserver -version

The output shows the Xtigervnc version, 1.13 on Ubuntu 24.04.

Step 2 - Setting the VNC password

VNC has its own password, separate from the Linux account password. Run the following as your_user, not with sudo, so the file is created in your home directory:

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

The password is stored obfuscated in ~/.vnc/passwd. VNC only uses the first eight characters, which is one more reason to never expose the VNC port directly: in this setup, SSH is the real authentication barrier and the VNC password is a second layer.

Step 3 - Configuring the desktop session

Each time a VNC session starts, the server runs ~/.vnc/xstartup to launch the desktop. Create it:

nano ~/.vnc/xstartup
#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
exec startxfce4

The two unset lines stop the new session from attaching to another desktop's session manager or D-Bus instance, which is the usual cause of a grey screen. startxfce4 starts its own D-Bus session. Make the file executable:

chmod +x ~/.vnc/xstartup

Step 4 - Testing the server manually

Start a session on display :1. VNC display numbers map to TCP ports starting at 5900, so display :1 listens on port 5901:

vncserver :1 -localhost yes -geometry 1600x900 -depth 24
New Xtigervnc server 'your_hostname:1 (your_user)' on port 5901 for display :1.
Use xtigervncviewer -SecurityTypes VncAuth -passwd /home/your_user/.vnc/passwd :1 to connect to the VNC server.

-localhost yes binds the server to the loopback interface only. Confirm it:

ss -tlnp | grep 5901
LISTEN 0      5          127.0.0.1:5901      0.0.0.0:*    users:(("Xtigervnc",pid=5321,fd=7))

The address must be 127.0.0.1 (or [::1]), never 0.0.0.0. List the running sessions and then stop this test one, since systemd will manage it from the next step:

vncserver -list
vncserver -kill :1

Step 5 - Running TigerVNC as a systemd service

A systemd unit starts the VNC session at boot and restarts it if it crashes. Create a template unit, where %i is the display number:

sudo nano /etc/systemd/system/[email protected]
[Unit]
Description=TigerVNC server for your_user on display :%i
After=network.target

[Service]
Type=forking
User=your_user
Group=your_user
WorkingDirectory=/home/your_user
ExecStartPre=-/usr/bin/vncserver -kill :%i
ExecStart=/usr/bin/vncserver :%i -localhost yes -geometry 1600x900 -depth 24
ExecStop=/usr/bin/vncserver -kill :%i
Restart=on-failure

[Install]
WantedBy=multi-user.target

Type=forking matches how vncserver works: it starts Xtigervnc in the background and exits. The leading - on ExecStartPre tells systemd to ignore the error when there is no old session to kill.

Reload systemd and start the service on display 1:

sudo systemctl daemon-reload
sudo systemctl enable --now [email protected]

Check its status:

sudo systemctl status [email protected] --no-pager
● [email protected] - TigerVNC server for your_user on display :1
     Loaded: loaded (/etc/systemd/system/[email protected]; enabled; preset: enabled)
     Active: active (running) since Thu 2026-09-24 11:02:17 UTC; 4s ago
...

If it fails, read the service log and the session log:

sudo journalctl -u [email protected] -n 30 --no-pager
cat ~/.vnc/*:1.log

Step 6 - Connecting through an SSH tunnel

Since the server only listens on localhost, you reach it by forwarding a port over SSH. Make sure UFW allows SSH and nothing else is needed for VNC:

sudo ufw allow OpenSSH
sudo ufw enable

On your computer, open the tunnel. This works in a Linux or macOS terminal and in PowerShell on Windows 10 and 11:

ssh -N -L 5901:localhost:5901 your_user@your_server_ip

The command keeps running with no output while the tunnel is open. Now open your VNC client and connect to localhost:5901. In TigerVNC Viewer you can also type localhost::5901 (two colons followed by the port). Enter the VNC password from Step 2 and the Xfce desktop appears.

The client may warn that the connection is not encrypted. That refers to the VNC protocol itself; the traffic travels inside the SSH tunnel, which is encrypted.

To keep the tunnel from dropping on idle connections, add keepalives to ~/.ssh/config on your computer:

Host your_server_ip
    ServerAliveInterval 30
    ServerAliveCountMax 3

Step 7 - Adding a second user

Each user needs their own display number, VNC password and xstartup file. The template unit above is tied to one user, so for a second user copy it with a different name and user:

sudo cp /etc/systemd/system/[email protected] /etc/systemd/system/[email protected]
sudo sed -i 's/your_user/second_user/g' /etc/systemd/system/[email protected]

Log in as second_user, run vncpasswd and create ~/.vnc/xstartup as in Steps 2 and 3. Then start that user's session on display 2, which listens on port 5902:

sudo systemctl daemon-reload
sudo systemctl enable --now [email protected]

The second user tunnels port 5902 instead of 5901. Remember that each Xfce session uses a few hundred megabytes of RAM.

Troubleshooting

Grey or black screen after connecting: the desktop failed to start. Check that ~/.vnc/xstartup is executable and contains exec startxfce4, that dbus-x11 is installed, and read ~/.vnc/*:1.log for the error. Restart the service afterwards with sudo systemctl restart [email protected].

The service fails with "A VNC server is already running as :1": a session was started manually and is still running, or a stale lock file remains after a crash. Run vncserver -kill :1 as the user, or remove /tmp/.X1-lock and /tmp/.X11-unix/X1 if no Xtigervnc process is running, then start the service again.

The client cannot connect to localhost:5901: the SSH tunnel is not running or local port 5901 is taken. Check that the ssh -L command is still open, and on the server confirm with ss -tlnp | grep 5901 that the VNC server is listening.

ssh fails with bind: Address already in use: another VNC server or tunnel already uses local port 5901. Use another local port, such as -L 15901:localhost:5901, and connect to localhost:15901.

Conclusion

You installed TigerVNC with an Xfce desktop on Ubuntu 24.04, bound it to localhost, ran it as a systemd service that starts at boot and connected to it through an SSH tunnel. As next steps, disable SSH password authentication so the tunnel requires a key, and if you prefer the native Windows client or need session reconnection with better compression, compare this setup with XRDP.