This is the natural followup to the old article I wrote about tunnelling VNC from a thumb drive in Windows. The setup is simple:

For the client you need nothing but ssh and a VNC client, Ubuntu comes with “vinagre” (in the menu it can be found as “Remote Desktop Viewer”) which works out of the box, but there are plenty of alternatives such as gtkvncviewer, gvncviewer and xtightviewer. Check your package manager.

For the server you need the openssh-server package as well as x11vnc.

The connection itself can be done with a one-liner:

$ ssh -L5900:127.0.0.1:5900 user@host.com "DISPLAY=:0.0 x11vnc -listen 127.0.0.1"

The -L switch tells ssh to set up a local forwarding on port 5900. The endpoint of this tunnel will be 127.0.0.1:5900 on the remote side, which is where x11vnc is instructed to listen for connections. This ensures that it will only accept local connections and not connections from the internet.

The DISPLAY=:0.0 statement sets the DISPLAY environment variable for x11vnc, telling it to use the default X session. You can leave this line out, but not with guaranteed success. Furthermore, if x11vnc in its logging output gives you something other than PORT=5900 on Ubuntu you most likely already have the “vino-server” running. To fix this, try the following instead:

$ ssh -L5900:127.0.0.1:5900 user@host.com
...
host.com$ killall -9 vino-server
host.com$ DISPLAY=:0.0 x11vnc -listen 127.0.0.1

If the problem persists, try to determine what process is listening on port 5900:

noccy@noccy-aspire:~$ netstat -lp | grep 5900
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp        0      0 *:5900                  *:*                     LISTEN      10772/x11vnc

And then, if appropriate, kill them off with kill -9 pid, in the above example kill -9 10722.

Once x11vnc is up and running and listening on the appropriate port, open your VNC viewer application and connect to 127.0.0.1:5900. You should now see the remote Linux desktop. The x11vnc server will close when the viewer disconnects, so there is no need to kill it afterwards.

To do this all with a single script:

#!/bin/bash
if [ -z $1 ]; then
echo "Use: `basename $0` [user@]host"
exit 1
fi
ssh -L5900:127.0.0.1:5900 $1 "DISPLAY=:0.0 x11vnc -listen 127.0.0.1" &
sleep 5
vinagre 127.0.0.1:5900

This script will wait 5 seconds for the SSH connection to be established, you might need more depending on the connection and remote host.

Note: The $ and host.com$ in the examples above represent the local and remote prompts and should not be included in your command line.