Set Up a VNC Server on Ubuntu 24.04 with TigerVNC and SSH

On Ubuntu 24.04, install Xfce and tigervnc-standalone-server, start tigervncserver :1, and come in through an SSH tunnel. The server listens on TCP 5901 on loopback only, so you forward that port from your own machine and point the viewer at localhost::5901.

You start everything through a Perl wrapper. tigervncserver starts Xtigervnc, an X server with a virtual screen that doubles as the VNC server your viewer talks to, then launches the desktop named on the session= line of ~/.vnc/config inside it. The password, log and PID files all sit in ~/.vnc/. At boot, the packaged unit runs tigervncsession, which starts tigervncserver -fg as the user mapped to that display, so the service reads the same files as your manual start.

What you need first

You need a sudo account on Ubuntu 24.04, an SSH login to it, a desktop environment and a VNC viewer on your own machine. The desktop is the one people skip: the VNC session starts a desktop inside its own X server, and with none installed Xsession gives up with unable to start X session and the display goes down a moment after it starts.

A person at a laptop beside a checklist panel and a small server unit marking prerequisite items.

  • Noble ships version 1.13.1 of tigervnc-standalone-server, so expect 1.13.1's file names and its ~/.vnc/ paths, and Xfce 4.18 is in the archive as xfce4 plus xfce4-goodies. It's light, so lead with it. You can name GNOME or KDE Plasma on the session= line instead, but test that by hand first, and not with an account that's logged in at the console: TigerVNC won't start a session for a user who already has a graphical one.
  • For the viewer, sudo apt install tigervnc-viewer on an Ubuntu desktop gives you xtigervncviewer, and Remmina works too. From a Windows or macOS machine, any viewer that does standard VNC password authentication will do.

Get the desktop running by hand

Get the desktop right with a manual start before you touch systemd. The service only replays the same config, so whatever is broken by hand is broken at boot too. Run everything on the server as the account that will own the session, with sudo only where shown; the tunnel and the viewer run on your own machine.

A labeled six-step horizontal flow diagram showing the TigerVNC setup sequence, with a purple start block and two highlighted decision steps.

Install Xfce and the TigerVNC server

install xfce and the tigervnc server
sudo apt update
sudo apt install xfce4 xfce4-goodies
sudo apt install tigervnc-standalone-server tigervnc-tools

The Xfce install takes several minutes. Name tigervnc-tools explicitly: it carries the password tool, and the server package only recommends it, so an install with --no-install-recommends leaves you without the password tool.

Set the VNC password

set the vnc password
tigervncpasswd

Run it as yourself, not with sudo. You get Password:, Verify: and a question about a view-only password; answer n unless someone should watch without control. It wants at least six characters and takes a longer one without complaint, but only the first eight count, and it writes ~/.vnc/passwd readable by you alone. That file is obfuscated, not securely encrypted, which is one more reason to keep the session behind SSH. If you skip this, the first tigervncserver start runs tigervncpasswd for you.

Point the session at Xfce

point the session at xfce
ls /usr/share/xsessions
mkdir -p ~/.vnc
echo 'session=xfce' >> ~/.vnc/config

ls should list xfce.desktop, which xfce4-session installs there, and the session name is that file name without .desktop. For GNOME or Plasma, use whatever file they put in the same directory. Get the name wrong and, when the session starts, the wrapper's session lookup prints Warning: No X session desktop file or command for followed by the name.

Two leftovers can override that line. If ~/.vnc/tigervnc.conf exists, the wrapper reads that Perl-syntax file and ignores ~/.vnc/config. If an older guide left you a ~/.vnc/xstartup, it runs instead of the packaged session script, and session= stops deciding your desktop.

Start display :1 on loopback

start display :1 on loopback
tigervncserver :1 -localhost yes

The wrapper's startup message reads New Xtigervnc server with your host and user, then on port 5901 for display :1: 5900 plus the display number. Confirm the listening socket:

start display :1 on loopback
ss -ltn | grep 5901

The local address should be loopback with port 5901, never 0.0.0.0:5901. To stop this manual session, run tigervncserver -kill :1, which answers Killing Xtigervnc process ID <pid>... success!.

Tunnel in over SSH and connect

On your own machine:

tunnel in over ssh and connect
ssh -N -L 5901:localhost:5901 <user>@<server-host>

The local forward carries local port 5901 through the SSH connection to 5901 on the server's loopback, and -N skips the remote shell, so the terminal just sits there while the tunnel is up. In a second terminal:

tunnel in over ssh and connect
xtigervncviewer localhost::5901

The double colon takes a TCP port, while a single colon followed by a number under 100 takes a display number, so localhost:1 lands in the same place. You get the VNC password prompt, then your Xfce desktop. If you'd rather not keep a separate ssh running, xtigervncviewer -via <user>@<server-host> localhost:1 opens the tunnel itself, and localhost there means the server.

Start it at boot with the packaged unit

Noble's package already ships the unit as /lib/systemd/system/tigervncserver@.service, so don't write your own. Kill the manual session first, because the service wants the same display:

start it at boot with the packaged unit
tigervncserver -kill :1
echo ':1=<user>' | sudo tee -a /etc/tigervnc/vncserver.users
echo 'localhost=yes' >> ~/.vnc/config
sudo systemctl enable --now tigervncserver@:1.service
systemctl status tigervncserver@:1.service

vncserver.users maps each display to one account, one line per display. The localhost=yes line pins the loopback binding for the service, which runs the same wrapper and reads the same ~/.vnc/config. Look for active (running) in the status output, then connect through the tunnel exactly as before.

Check the session and read the failures

If the viewer asks for the VNC password and then shows your Xfce desktop, you're done. If it doesn't, these two tell you whether the server or the desktop is the broken half:

check the session and read the failures
tigervncserver -list
tail -n 30 ~/.vnc/*:1.log

-list prints a TigerVNC server sessions: table with display 1 and RFB port 5901. (stale) next to the process ID means the server died and left its PID file behind. The log collects the output of Xtigervnc and of the desktop session, so a desktop that crashes on start leaves its error there.

Symptom Cause Fix
Viewer times out or is refused at localhost::5901 The tunnel is down, or nothing listens on 5901 Rerun the ssh -N -L command, then check tigervncserver -list on the server
Direct connection to the server’s address fails while the tunnel works The session listens on loopback only Restart it with -localhost no and open 5901 in UFW, as below
Password rejected What you typed doesn’t match ~/.vnc/passwd Run tigervncpasswd as the session owner, then tigervncserver -kill :1 and start again
The display dies a moment after tigervncserver :1, and the log shows unable to start X session No desktop installed, so Xsession gives up and the session script kills the display Install xfce4 and xfce4-goodies, then start :1 again
Black or grey screen session= matches no file, or a leftover ~/.vnc/xstartup runs instead Run ls /usr/share/xsessions, fix the session= line, move ~/.vnc/xstartup aside, restart the display
tigervncserver :1 exits with A Xtigervnc server is already running for display :1 (or A X11 server ...) Another VNC or X server holds display :1 Run tigervncserver -list, then kill the old session or start on :2 (port 5902)
systemctl status tigervncserver@:1.service shows No user configured for display :1 No :1= line in vncserver.users, so the start script finds no user Add the mapping, then sudo systemctl restart tigervncserver@:1.service
The unit fails or stops right away for an account that is logged in at the console The server won’t start for a user already logged into a graphical session Log that account out of the local desktop or map another account

Open it for a direct connection

With -localhost yes, display :1 only takes connections from the server itself, so the tunnel is the only way in. Drop the option and the wrapper still binds to loopback unless your security types include a TLS or X509 type and no None type. That's the one setting that decides who can reach you.

On a network you trust, restart with -localhost no -SecurityTypes TLSVnc and open the port in UFW. Leave -SecurityTypes off and -localhost no offers VncAuth,TLSVnc; the viewer picks the type from that list, so it can still take plain VNC auth, and then nothing protects the data stream. Ubuntu ships UFW disabled, so until you enable it the rule just waits:

open it for a direct connection
tigervncserver -kill :1
tigervncserver :1 -localhost no -SecurityTypes TLSVnc
sudo ufw allow proto tcp from <subnet> to any port 5901
sudo ufw status

From a machine in that subnet, connect to the display directly:

open it for a direct connection
xtigervncviewer <server-host>:1

If you enable UFW for this, run sudo ufw allow 22 first. sudo ufw enable flushes the chains and can drop your SSH session, and the rule has to exist before the firewall comes up. For the service, change the line to localhost=no in ~/.vnc/config, add securitytypes=tlsvnc for the same reason, and restart tigervncserver@:1.service; the restart ends the running desktop, so save your work in it first. The unit file carries a warning against running the service on an untrusted LAN at all, so anything that crosses a network you don't control stays on the tunnel.

Share the desktop already on the monitor instead

Use TigerVNC for a headless server or a desktop of the VNC user's own. Use x11vnc when you need to see or drive the session already on the machine's monitor: it attaches to the running X display instead of starting a new one, and Noble has 0.9.16 (sudo apt install x11vnc). That has to be an X11 display, and the 24.04 GNOME login is Wayland by default, so switch the login to Xorg first: uncomment WaylandEnable=false in /etc/gdm3/custom.conf and reboot. GNOME's own Remote Desktop sharing doesn't help a VNC viewer here, because on 24.04 it speaks RDP only.

Route What the viewer shows Start command Choose it when
TigerVNC session A new standalone desktop on display :1 tigervncserver :1 -localhost yes You want a desktop of its own for the VNC user
x11vnc The real X display already running, :0 in the basic command x11vnc -display :0 An Xorg desktop is already running and you want to share it

If x11vnc can't authenticate to the display, point -auth at the X authority file: x11vnc -display :0 -auth <Xauthority-file>. To keep it on loopback and listening after a viewer disconnects, run x11vnc -localhost -forever -display :0. Here -localhost works like -allow 127.0.0.1 and implies -listen localhost. You can start it and tunnel in from your own machine in one go with ssh -t -L 5900:localhost:5900 <user>@<server-host> 'x11vnc -localhost -display :0'. x11vnc holds that terminal while it runs, so point the viewer at localhost:0 from a second one. x11vnc's README says the project is unmaintained and looking for a new maintainer; its latest release, 0.9.17, shipped in May 2025. For long-lived console sharing, reach for TigerVNC's x0tigervncserver from tigervnc-scraping-server, the maintained equivalent, which needs the same Xorg login. Noble has no packaged way to share a Wayland desktop over VNC: TigerVNC's w0vncserver arrived in 1.16.0, and Noble ships 1.13.1.

RealVNC Server's Service Mode remotes the console, login screen included, and it doesn't support Wayland either, so it needs the same WaylandEnable=false switch.

What changes on 22.04 and 26.04

22.04 takes the same steps unchanged. 26.04 moves the per-user files out of ~/.vnc/. On Debian 13, which packages TigerVNC 1.15, follow the TigerVNC setup guide for Debian 13 instead.

Ubuntu release TigerVNC Config, password and log Boot unit
22.04 (Jammy) 1.12.0 ~/.vnc/config, ~/.vnc/passwd, logs in ~/.vnc/ /lib/systemd/system/tigervncserver@.service
24.04 (Noble) 1.13.1 ~/.vnc/config, ~/.vnc/passwd, logs in ~/.vnc/ /lib/systemd/system/tigervncserver@.service
26.04 (Resolute) 1.15.0 ~/.config/tigervnc/config, ~/.config/tigervnc/passwd, logs in ~/.local/state/tigervnc/ /usr/lib/systemd/system/tigervncserver@.service

On 26.04, write the session= line to ~/.config/tigervnc/config and read logs from ~/.local/state/tigervnc/; the commands, the vncserver.users mapping and the unit name stay the same. The password prompt changes too: 26.04's tigervncpasswd refuses anything longer than eight characters instead of ignoring the rest. Older guides that build ~/.vnc/xstartup and a hand-written vncserver@.service don't apply to any of the three, since all of them ship the packaged unit.

Stop it and remove it

Kill the manual session, then the service, then remove the packages and files:

stop it and remove it
tigervncserver -kill :1
sudo systemctl disable --now tigervncserver@:1.service
sudo sed -i '/^:1=/d' /etc/tigervnc/vncserver.users
sudo apt purge tigervnc-standalone-server tigervnc-tools
rm -f ~/.vnc/passwd ~/.vnc/config

disable --now stops the unit and keeps it off at boot. If you opened 5901 for a direct connection, delete the rule with sudo ufw delete allow proto tcp from <subnet> to any port 5901, and sudo ufw status stops listing it. The same apt purge pattern removes the Xfce packages.

If this box is only ever reached over SSH, you're done: leave localhost=yes in ~/.vnc/config and the unit enabled, and nothing new listens beyond loopback.

FAQs

Does running the VNC server as root cause problems on Ubuntu?

Yes. Running the server as root isn't safe and can break parts of the desktop. Map a regular account in /etc/tigervnc/vncserver.users and run tigervncpasswd as that account.

Can tigervncserver choose the display number automatically?

Yes. Run tigervncserver with no display and it takes the first free one, usually :1. Ask for one, such as tigervncserver :13, and it uses that number or exits if it's taken. tigervncserver -list shows which display you got.

Will one Ubuntu server host more than one VNC desktop at a time?

Yes, one display per session. Display :2 listens on port 5902, the service gets one mapping line per display, such as :2=<other-user>, and each display runs as its own unit, such as tigervncserver@:2.service.