A practical guide to VNC over SSH, Tailscale, or WireGuard

This guide compares the SSH-tunnel route with two overlay options, Tailscale and WireGuard.

A 2025 CISA advisory says internet-exposed devices are scanned for open VNC ports and targeted by brute-force or password-spray attacks (CISA AA25-343A, published 18 Dec 2025). With an SSH local port forward, a VNC viewer communicates with a server as if both programs were on one machine. Inside that session, SSH provides encryption and host authentication (RFC 4253 sections 1, 6.3, and 8). RFB is specified independently of any particular product (RFC 6143 section 1).

Pick a route by reachability

  • If SSH is reachable. The local-forward procedure below carries VNC through SSH.
  • If SSH is not reachable. Compare the separate Tailscale and WireGuard procedures below.
  • For an organization VPN. Use an organization-managed private network.
Option What is exposed How it authenticates Where it sits on the network Audit trail
Tailscale Xvnc listens on the chosen Tailscale address. Tailscale uses an external identity provider through its coordination server, followed by VNC authentication (Tailscale control and data planes). Use a 100.x address or MagicDNS name (Tailscale IP addresses; MagicDNS documentation). Audit coverage is outside this guide.
WireGuard Xvnc listens on the chosen WireGuard address; the configured UDP ListenPort of an inbound peer must be reachable. WireGuard uses peer public keys and AllowedIPs, followed by VNC authentication. Use an address assigned in wg0.conf. Audit coverage is outside this guide.
SSH tunnel The SSH service is exposed while VNC listens on loopback. SSH host keys and unique user keys come first, followed by the Ubuntu package’s default VncAuth password challenge-response. The viewer opens a local forward to the server’s loopback interface. The available records are SSH authentication logs, host logs, and VNC logs.
VPN The VPN gateway is exposed. VPN identity or certificates come first, followed by VNC authentication. Traffic uses the organization’s routed private network. The available records are gateway connection logs, identity logs, and VNC logs.

Traffic in an SSH-forwarded session is encrypted by SSH (RFC 4253 sections 1 and 6.3). Between peers, WireGuard uses ChaCha20Poly1305 authenticated encryption and Curve25519 key exchange to encrypt traffic (WireGuard whitepaper, dated 1 Jun 2020; corroborated by Linux kernel v6.8 WireGuard source). Tailscale encrypts connections between devices with WireGuard, even when a DERP server relays them (Tailscale encryption documentation). For TigerVNC 1.13.1 on Ubuntu 24.04, the Ubuntu wrapper uses VncAuth by default on the SSH/localhost path (Ubuntu noble TigerVNC source package, build 1.13.1+dfsg-2build2). VncAuth encrypts the challenge only; it does not encrypt the session. (RFC 6143 section 7.2.2).

If SSH is unreachable: set up Tailscale or WireGuard

Tailscale

On Ubuntu 24.04, use the noble apt repository to install Tailscale. The Tailscale client GitHub release at check was v1.102.4 (10 Sep 2026):

  1. sudo mkdir -p --mode=0755 /usr/share/keyrings
  2. curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/noble.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
  3. curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/noble.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list
  4. sudo apt-get update && sudo apt-get install tailscale
  5. sudo tailscale up

Each command uses sudo to run as root.

The Ubuntu 24.04 package page for Tailscale publishes no fingerprint for this keyring, so no fingerprint check appears here. According to the dated Tailscale CLI reference, tailscale up connects the device and authenticates it when needed.

Each Tailscale device receives a unique address in 100.64.0.0/10, and MagicDNS can register a device name (Tailscale IP addresses; MagicDNS documentation). Point TigerVNC vncviewer at <Tailscale-address>::5901.

Tailscale’s coordination server provides device discovery, authentication, key distribution, and policy enforcement; an external identity provider handles user authentication (Tailscale control and data planes). It normally requires no inbound firewall rule, and its default listener for direct peer traffic is UDP 41641. Tailscale firewall ports.

WireGuard

Ubuntu package note

On Ubuntu, the wireguard-tools package provides the wg and wg-quick tools.

On Ubuntu 24.04, install wireguard-tools version 1.0.20210914-1ubuntu4 from Ubuntu’s main component (Ubuntu noble package index). Use these commands to generate a key pair:

umask 077
wg genkey | tee private.key | wg pubkey > public.key

For this device and one peer, create /etc/wireguard/wg0.conf and replace each angle-bracketed value:

[Interface]
Address = <THIS-PEER-ADDRESS/CIDR>
PrivateKey = <THIS-PEER-PRIVATE-KEY>
ListenPort = 51820

[Peer]
PublicKey = <OTHER-PEER-PUBLIC-KEY>
AllowedIPs = <OTHER-PEER-ADDRESS/CIDR>
Endpoint = <OTHER-PEER-HOST>:51820

The wg-quick(8) example at release tag v1.0.20210914 uses this one-interface, one-peer form. Bring up the interface with sudo wg-quick up wg0.

WireGuard assigns no address automatically. Set Address and each peer’s AllowedIPs in the configuration, then point TigerVNC vncviewer at <WireGuard-address>::5901. Peers are identified by public keys, and AllowedIPs supplies the trust and routing table; WireGuard has no separate user identity or central authentication server.

For a WireGuard peer that accepts inbound connections, its configured UDP ListenPort must be reachable.

Bind TigerVNC for the chosen route

With TigerVNC 1.13.1, -interface <overlay-address> limits Xvnc to the chosen Tailscale or WireGuard address. On the SSH-tunnel route, -localhost permits connections only from the same machine. For Tailscale or WireGuard, give Xvnc -interface <overlay-address>, set the VNC password with vncpasswd on Ubuntu 24.04, and point vncviewer at <overlay-address>::5901 (TigerVNC Xvnc(1), release tag v1.13.1).

vncserver :1 -localhost no -interface <overlay-address>

In Ubuntu noble’s TigerVNC 1.13.1 package, explicit -localhost no is the documented way to force listening beyond localhost, while -interface confines the listener to the chosen address (Ubuntu noble TigerVNC source package, build 1.13.1+dfsg-2build2). To configure the same settings in a file, put $localhost = "no"; and $interface = "<overlay-address>"; in ~/.vnc/tigervnc.conf.

Risks of exposing a raw VNC port

A 2025 CISA advisory says internet-exposed devices are scanned for open VNC ports and targeted by brute-force or password-spray attacks (CISA AA25-343A, published 18 Dec 2025). Use a tunnel when the network is untrusted.

How the tunnel works

The SSH client opens a local listening port. Connections to that local port travel inside the encrypted SSH session (RFC 4253 sections 1 and 6.3). At the far end, the SSH server connects to the VNC listener from its own network context. If VNC listens only on the remote loopback interface, it remains unavailable to other machines while still reachable through the tunnel.

The viewer connects to localhost, not the remote hostname. SSH then chooses the remote destination written in the forwarding rule. This distinction matters: closing the terminal that owns SSH also closes the path, even though the VNC server remains running.

Start VNC and open the tunnel

Start the VNC server (Ubuntu 24.04)

These commands apply to TigerVNC 1.13.1 (Ubuntu 24.04 package). The installation command uses sudo and runs as root.

sudo apt install tigervnc-standalone-server
vncpasswd
vncserver :1 -localhost yes

SSH-tunnel route: On Ubuntu 24.04, vncpasswd writes ~/.vnc/passwd; the password must be at least six characters, only the first eight are significant, and the file is not encrypted at rest. In this configuration, the Ubuntu wrapper uses localhost-only by default (Ubuntu noble TigerVNC source package, build 1.13.1+dfsg-2build2). The -localhost yes flag states that restriction explicitly.

Before the first connection (OpenSSH 9.6p1 on Ubuntu 24.04), run ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub on the server. Compare its output with the fingerprint ssh displays when it asks you to confirm the new host key.

Open the SSH tunnel

local machine ยท open the tunnel
$ ssh -N -L 5901:localhost:5901 user@host
# keep this process running, then point TigerVNC vncviewer at localhost::5901

SSH must be reachable: From your location, you must be able to reach the host’s SSH port to use this command. Otherwise, compare the separate Tailscale and WireGuard procedures.

Part Meaning
ssh Starts the encrypted SSH connection.
-N Runs no remote command, useful for a forwarding-only session.
-L Requests a local port forward.
5901 Local port where the viewer connects.
localhost:5901 Destination as seen by the remote SSH server.
user@host SSH account and reachable SSH hostname.

The ssh, -N, and -L entries above follow ssh(1).

By convention, display :1 uses port 5901 (TigerVNC vncserver source, release tag v1.13.1). If your server uses another port, change the remote destination port. When local 5901 is occupied, run ssh -N -L 15901:localhost:5901 user@host and point TigerVNC vncviewer at localhost::15901.

Add -v while diagnosing. It causes SSH to print debugging messages about its progress, which is helpful for debugging connection, authentication, and configuration problems (ssh(1), verbose mode).

Use that output to check whether SSH requested local forwarding and where authentication ended. Test the remote listener separately from the SSH host with sudo ss -tlnp. The tunnel can authenticate even when its destination refuses the connection because the VNC server is stopped or listening on a different display port.

Add -g only when you intend to let other machines reach the local forward. OpenSSH binds a local forward to loopback by default (ssh_config(5), GatewayPorts); confirm that binding on your system. On Linux, use sudo ss -tlnp | grep 5901. On macOS, use lsof -iTCP -sTCP:LISTEN -n -P | grep 5901.

Need to discuss a variation or edge case? Use the community group for this topic.

Windows specifics

The availability of the Windows OpenSSH client depends on the edition. Check for it in PowerShell with Get-Command ssh. If it is missing, install the optional OpenSSH Client capability from optional features in Windows Settings, subject to your organization’s software policy. Next, run ssh.exe -N -L 5901:localhost:5901 user@host, leave that window open, and point TigerVNC vncviewer at localhost::5901.

PowerShell does not need special quoting for this simple forward. A corporate endpoint agent or local firewall can still block the loopback listener. Get-NetTCPConnection -LocalPort 5901 should show the listening process after authentication succeeds.

Keys, not passwords

On the client, create a modern key with ssh-keygen -t ed25519. Protect the private key with a passphrase and, when appropriate, load it into an agent. Put only the public key in the remote account’s ~/.ssh/authorized_keys. Confirm key-based login in a second terminal.

Checklist

  1. With TigerVNC 1.13.1, choose -localhost for the SSH route or -interface <overlay-address> for Tailscale or WireGuard (TigerVNC Xvnc(1), release tag v1.13.1). Use sudo ss -tlnp to inspect listening TCP sockets.
  2. Where practical, limit SSH access to the networks you expect.
  3. For SSH, point TigerVNC vncviewer at localhost::5901; for Tailscale or WireGuard, use <overlay-address>::5901.
  4. Give SSH users unique keys and keep their private keys protected.
  5. Keep SSH and VNC patched, and inspect authentication logs.
VNC.com editorial
community

Discuss this in the community

Security and Remote Access group

last active 13 Aug 2026, 09:05

Join the community

Sources accurate as of 30 September 2026.

Open-source VNC suits personal projects and home labs. When your business depends on remote access, RealVNC Connect adds end-to-end encryption, centralised management and commercial support from the team that created VNC.