VNC

Chapter 6 — VNC: The Protocol, the Server, and the Tunnel

VNC (Virtual Network Computing) predates RDP and works on a simpler principle: it captures the screen as raw pixel data and sends it to the viewer. There is no server-side rendering intelligence — whatever appears on the display is streamed directly. This means VNC works with virtually any desktop environment and on any operating system, but it also means it uses more bandwidth than RDP for the same session quality.

VNC vs RDP — The Key Differences

RDP
VNC
Sends rendering commands — "draw this text at this position in this font"
Sends pixel data — a compressed copy of what's on screen
Creates a new virtual session — the physical display is unaffected
Can share the actual physical display — someone at the machine sees what you see
Encrypted by default (TLS)
Unencrypted by default — must tunnel over SSH
Better bandwidth efficiency — less data for same quality
Higher bandwidth use — more data, especially during motion
Native clipboard, drive, audio redirection
Clipboard sharing only (via extensions); no drive/audio natively
Windows-native; needs xRDP on Linux
Works on Linux, macOS, Windows — true cross-platform
When to prefer VNC over xRDP: when you want to share or observe the actual physical desktop (great for remote support — you see exactly what the user sees), or when setting up xRDP is more trouble than it's worth on an unusual desktop environment. For headless server access, xRDP or SSH is almost always better.

VNC Display Numbers and Ports

VNC uses display numbers starting at :1 (display :0 is the physical screen). Each display maps to a TCP port: display number + 5900.

DisplayPortTypical use
:05900Physical console — sharing the real screen
:15901First virtual VNC display (default when you run vncserver)
:25902Second virtual display (second user or second session)
:35903Third virtual display, and so on

When connecting, you specify the host and display: 192.168.0.24:1 — or the full port: 192.168.0.24:5901. Both mean the same thing.

Installing TigerVNC Server on Debian / Ubuntu

debian — install TigerVNC
philip@debian:~$ sudo apt update philip@debian:~$ sudo apt install -y tigervnc-standalone-server tigervnc-common # set a VNC password (stored separately from your login password) philip@debian:~$ vncpasswd Password: Verify: Would you like to enter a view-only password (y/n)? n # start a VNC server on display :1 with XFCE philip@debian:~$ vncserver :1 -geometry 1920x1080 -depth 24 New Xtigervnc server 'debian:1 (philip)' on port 5901 for display :1. # stop the server philip@debian:~$ vncserver -kill :1 Killing Xtigervnc process ID 3421... success

Configure the desktop environment for VNC

TigerVNC reads ~/.vnc/xstartup to know which desktop to launch:

#!/bin/bash # ~/.vnc/xstartup — launched by vncserver on startup unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS # launch XFCE exec startxfce4 # --- alternatives --- # exec mate-session # exec gnome-session # exec openbox-session
debian — make xstartup executable
philip@debian:~$ chmod +x ~/.vnc/xstartup # restart the server to pick up the new config philip@debian:~$ vncserver -kill :1 && vncserver :1 -geometry 1920x1080 -depth 24

Running VNC as a systemd Service

Starting the VNC server manually works for testing, but for a persistent setup you want it to start automatically on boot:

# /etc/systemd/system/vncserver@.service # the @ allows multiple instances: vncserver@1.service, vncserver@2.service [Unit] Description=TigerVNC server — display %i After=network.target [Service] Type=forking User=philip Group=philip WorkingDirectory=/home/philip PIDFile=/home/philip/.vnc/%H:%i.pid ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill :%i > /dev/null 2>&1 || :' ExecStart=/usr/bin/vncserver :%i -geometry 1920x1080 -depth 24 -localhost no ExecStop=/usr/bin/vncserver -kill :%i [Install] WantedBy=multi-user.target
debian — enable the service
philip@debian:~$ sudo systemctl daemon-reload philip@debian:~$ sudo systemctl enable --now vncserver@1.service philip@debian:~$ sudo systemctl status vncserver@1.service

VNC is Unencrypted — Always Use an SSH Tunnel

VNC transmits everything in plain text by default — including your password (only weakly hashed) and every pixel of your screen. On a local trusted network this may be acceptable. Over the internet, or on any shared network, you must wrap VNC in an SSH tunnel. Never open VNC port 5901 to the internet directly.

The SSH tunnel approach

Forward the remote VNC port to a local port over SSH, then connect your VNC viewer to localhost rather than the remote IP. The traffic travels inside the encrypted SSH connection:

your machine localhost:5901
SSH tunnel encrypted SSH connection :22
remote server 127.0.0.1:5901 (VNC — only accessible locally)
# Step 1 — open the SSH tunnel (background, no shell) ssh -fNL 5901:localhost:5901 philip@192.168.0.24 # Step 2 — connect your VNC viewer to the local end of the tunnel # (address is localhost:5901, NOT the remote IP) vncviewer localhost:5901
# One-liner — tunnel + viewer in the same command (Linux/macOS) ssh -fNL 5901:localhost:5901 philip@192.168.0.24 && vncviewer localhost:5901 # Keep VNC server locked to localhost only (prevents direct connections) # In your vncserver@.service, remove -localhost no and use: vncserver :1 -geometry 1920x1080 -depth 24 -localhost yes # Server will only accept connections from 127.0.0.1 — forces SSH tunnel
-localhost yes is the right production setting. If VNC only listens on 127.0.0.1, a direct connection from outside is impossible — the only way in is through the SSH tunnel. This means you never need to open port 5901 in your firewall at all.

VNC Viewer Clients

TigerVNC Viewer
Windows · Linux · macOS
The matching client for the TigerVNC server. Fast, lightweight, supports all TigerVNC extensions. Free and open-source. Best choice if your server is TigerVNC.
RealVNC Viewer
Windows · Linux · macOS · iOS · Android
Polished cross-platform client with optional cloud-relay (RealVNC Connect). Free tier available. The cloud relay avoids needing an SSH tunnel — useful but sends traffic through RealVNC's servers.
Remmina
Linux (GTK)
Supports both RDP and VNC in one app. Has a built-in SSH Tunnel tab so you can configure the tunnel inside the connection profile rather than running a separate ssh command.
KRDC / Vinagre
Linux (KDE / GNOME)
Desktop-environment native clients. KRDC for KDE, Vinagre for GNOME. Both support VNC and RDP. Good for occasional use; Remmina is more feature-rich for regular work.

Connecting from Windows with PuTTY + TigerVNC

If you're on Windows and prefer a GUI for the SSH tunnel, PuTTY can do it:

  1. Open PuTTY → enter the server IP in Host Name
  2. Go to Connection → SSH → Tunnels
  3. Source port: 5901 · Destination: localhost:5901 · click Add
  4. Go back to Session, save the profile, then click Open
  5. Once the SSH session is open, connect TigerVNC Viewer to localhost:5901

Common VNC Problems

Grey screen / no desktop
xstartup is missing, not executable, or contains the wrong command for the installed desktop.
Check ~/.vnc/xstartup exists, is chmod +x, and references an installed desktop (e.g. startxfce4). Check ~/.vnc/debian:1.log.
Authentication failed
Wrong VNC password — note this is different from your Linux login password.
Reset with vncpasswd then restart the server. The password file lives at ~/.vnc/passwd.
Connection refused
VNC server not running, wrong port, or server started with -localhost yes but you're not going through the SSH tunnel.
Check ss -tlnp | grep 590. If tunnel is required, open the SSH tunnel first then connect to localhost:5901.
Slow / choppy display
VNC's pixel-data transport is bandwidth-hungry. Compositing effects multiply the data sent per frame.
Disable compositing in the desktop settings (XFCE: Window Manager Tweaks → Compositor → off). Use -depth 16 or TigerVNC's -ZlibLevel 9 compression flag.

Quick Reference — vncserver Flags

# start display :1, 1080p, 24-bit colour, locked to localhost vncserver :1 -geometry 1920x1080 -depth 24 -localhost yes # allow external connections (LAN only — still use SSH tunnel from internet) vncserver :1 -geometry 1920x1080 -depth 24 -localhost no # maximum zlib compression (slow CPU, saves bandwidth) vncserver :1 -ZlibLevel 9 # list running VNC sessions vncserver -list # kill display :1 vncserver -kill :1 # kill all sessions for this user vncserver -kill :* # view the server log for display :1 cat ~/.vnc/$(hostname):1.log
Next — Chapter 7: NoMachine and Alternatives. RDP and VNC are the two foundational remote desktop protocols. Beyond them, a tier of modern alternatives offers better performance, easier setup, and built-in encryption. Chapter 7 covers NoMachine (NX protocol — often the fastest option on a LAN), AnyDesk, and TeamViewer: when each makes sense, and when you should stick with the open standards you already know.