running a desktop with vnc over openvpn

Posted by pj on Wed 9 Jan 2013 at 21:50

I'm going to describe how you can display and control your primary desktop remotely from a secondary so that it everything works really well. To do that, we are going to bolt together several commonly used linux components. Along the way I'll pass on some personal drivel about my own experience in doing this. The idea behind this being that you get a feel of how things hang together.

Now, I said display and control your primary desktop remotely from a secondary. By primary desktop, I want you to think of, for example, your desktop at work. Normally, you run a GUI under X on it, so that it shows applications like x-terminals, menus, screensavers, wallpapers, and so on. You've usually set these up just the way you like it on your primary desktop, so that you can work super efficiently. Every other desktop you configure elsewhere is normally a way to approximate the same stuff that you do on the primary.

By display and control your primary desktop remotely I mean something like this example: One day, you want to work from home, from your home machine, in your bunny slippers. The display and control bit means that you can not only see stuff that is on display on the work machine, but also control stuff on that work machine like you would if you were actually at the desktop at work. So, ideally you want to be able to do it from the home desktop so that it feels just like you are at the work desktop.

Note that I don't mean replicating the desktop. Replicating would mean something like copying the underlying disk drive from the work machine to the machine at home and constantly keeping stuff in sync. That requires too much thinking and maintenance. The display and control bit actually says it quite precisely. What I mean is viewing what is at work (display multiplexing), but being able to work on the desktop running at work too (remote control), all without replication of the underlying filesystem data from the remote to the local.

The tools I use for this are:

Getting Xrandr (and its ancestor, xinerama) to do X with Dual Monitors

What is xrandr?

xrandr: X Resize, Rotate and Reflect Extension (RandR). Version 1.3+ (released in 2009) works with dual head setups that use one big virtual screen across both heads.

Actually it works with more than just dual heads, but I just work with dual heads, so that's what I'll consider.

What's my hardware then?

At work the machine I have is a reasonably powerful dual core box, with a single video card ("lspci | grep VGA" shows the chipset as ATI Technologies Inc RS880 [Radeon HD 4200]). With this card is one output for DVI and one for VGA. One output is plugged into one 22" Samsung monitor each, giving me a dual head. Having two outputs from a single video card like this is quite common for current (2012) video cards. The VGA analogue output is not distinguishable in quality from the DVI output on the hardware I use, at least for these 22" monitors running at a resolution of 1920x1200.

Back at home, my desktop set up is rather more humble. Actually, forget humble, it's downright obsolete --- the home box is a P-4 single core machine, with a single built-in VGA out, to which an oldish 1280x1024 LCD monitor is plugged in. To this I added some additional junk --- and I mean junk quite literally. As in, I added a ridiculously old 8MB PCI voodoo 3dfx card from internet prehistory, together with an equally ancient 19" Ilyama CRT monitor. Both of these were junked freebies. However, in the end, I had a home box with a gigantic CRT monitor stood beside an oldish LCD monitor that the box was already using.

Aha!, you may exclaim, the power consumption of the CRT will eat up any savings from the freebieness! Aha yourself! --- I use the CRT about once a week. So it works out to about 6 years before I spend in power the amount I would on a new LCD monitor the same size, without the power consumption. With energy saving modes enabled on the CRT it'd be a few years more. So I'm okay there on green credentials. Not so okay on the exasperation-from-the-significant-other front, but like she says, I'm thick-skinned. Plus I quite like the display on the Ilyama, since it was a fantastically overengineered monitor in its heyday.

BIOS tweaks for PCI video cards

So, there I am with two monitors and two video cards. The kernel detects both cards just fine, and Debian's xserver-xorg installs a suite of drivers for X11 for the xserver. The PCI card needs to made to boot first in the BIOS, or it refuses to do X. It seems to be a common quirk for those kind of vintage machines. The voodoo and built-in video are detected just fine after the BIOS tweak.

From the gentoo wiki, the BIOS options can be tweaked like this:

Getting X on the cards


LCD Monitors can run at lots of resolutions, but the optimal ones are the ones matching the hardware pixel layout (resolution figures like 1920x1200, or 1280x1024). CRT monitors that are 17" or greater can generally handle 1280x1024, while the Ilyama 19" beast I have can cope with 1600x1200, for example. A resolution of 1280x1024 with a depth of 24 is fine for work, and is something even the Voodoo card copes with.

Monitor Juggling

Running X


VNC is awesome! I'll only be going through a part of its capabilities though, because if I go on about it in depth, you will be blinded by its extreme awesomeness. And then you won't be able to read this article properly.

What is VNC?

VNC was covered earlier on this website. Basically, if you have been living under a rock for the last 15 years, VNC can display the GUI on the remote (work desktop) to your local (home) display. Not only that, but mouse and keyboard stuff you do locally (at home) gets converted to remote equivalents at the work machine. The result is that it's like you are at the work desktop, except from home. Which is obviously getting us on the right track if we want to work from home.

Set this VNC visual display up right, and you don't have to replicate the file structure on your work machine that makes the remote desktop. This is because, well, you have the remote desktop display itself on display in front of you. So, that means, no copying of .bashrc, /home/, your customized menu, whatever. Your work desktop is just there, in front of your naked, steaming eyes! And "there" then becomes wherever you can get a connection to the work box. If you follow the current IT fashion for cloud-speak, then your workbox is your truly personal cloud!

Most VNC implementations run as a client/server setup. That is, a VNC server runs on the remote, and you use a VNC client for viewing locally. The VNC protocol has a common core standard, so that you can mix different clients and servers. The x11vnc server is designed to send the X11 display to clients, while vino/vinagre is good for gnome. I find x11vnc server works well for me with the xtightvncviewer client. The "tight" in xtightvncviewer refers to clever compression extensions to the original VNC protocol. These extensions make the exchange between client and server take fewer round trips and generally make things snappier. All modern VNC implementations have something similar --- everyone likes responsiveness after all!

The snappiness caused by the compression extensions is remarkable. Trying the same trick of viewing a desktop with standard ssh -X (as described in in, or is painfully, teeth-clenchingly, laggy --- at least over a connection to anywhere beyond a local LAN. Using a compressed VNC client makes the connection miraculously unlaggy.

Installing VNC

The VNC server

Installing the VNC server is easy:

work:~# apt-get x11vnc

Then, store a password with (as an ordinary user):

peej@work:~$ x11vnc -storepasswd secret12345

Using a password is a fairly weak precaution (let alone the pathetic password used here), considering there is no encryption during a default VNC connection. You can crank up the connection security to any level you like, including using ssl, piggybacking over ssh, or only allowing access from particular IP addresses. Read the man page if you want to know more on this, but I found my eyes glazing over when I tried reading it. So I used openvpn instead. I'm going to discuss using openvpn later on.

Having got the VNC server ready, we can start it up, as an ordinary user, with:

peej@work:~$ x11vnc -display :0 -usepw -forever

Tip: If you like screen or tmux, you may want to start it up under that at boot from, say cron:

@reboot /usr/bin/screen -d -m -S "x11vncserver-d" /usr/bin/x11vnc -display :0 -usepw -forever

The VNC client

Once the server is running, you can run the client from the home machine. I've set up a mindless shortcut that does something like this:

pkill xtightvncviewer;  echo "secret12345" | xtightvncviewer -autopass -fullscreen


Like I said earlier in the VNC section, we need to do VNC in a secure way. One way that works for me is to tunnel between the client and server within OpenVPN on the big bad internet.

I covered tunneling securely over OpenVPN in in detail earlier. If you aren't familiar with OpenVPN, you should find that a pretty good guide.

The way I run OpenVPN between two points is something like:

       # openvpn --script-security 2 --proto tcp-client --remote \
       --tls-client --remote-cert-tls server --ca ca.crt --cert pjworkbox_vpn.crt \
       --key pjworkbox_vpn.key --dev tun1 --ifconfig \
       --verb 4 --port 80 --user nobody --group nogroup --persist-tun --persist-key

The client script repeats indefinitely every 5 seconds or so if it gets no connection, so it is a bit like a service anyway. The IP address specified in it is the internet address of the local machine at home. You can maybe use a dyndns service for that, for convenience. Also, like the x11vnc service, you can run it in a screen session at boot.

      # openvpn --script-security 2 --proto tcp-server --tls-server --ca ca.crt \
      --dh dh2048.pem --cert serverbox_vpn.crt --key serverbox_vpn.key --dev \
      tun1 --ifconfig --verb 4 --port 80 --user nobody \
      --group nogroup --persist-tun --persist-key

I use port 80 for my tunnel to's the least likely outgoing port to be blocked by a firewall at work. As far as VNC is concerned, it will look like a private LAN connection from to

Once the tunnel is connected up from both ends, I just run that vncviewer script from earlier:

      pkill xtightvncviewer
      echo "secret12345" | xtightvncviewer -autopass -fullscreen

If all goes well, my snappy remote X session starts, and no one can snoop on the contents.

The alternatives

This way of working remotely can be done in many other ways, including:

My preference for the xv11vnc/xtightvncviewer way over openVPN was based on the parts being free (as in freedom and open standards), without MITM worries, familiarity, and fast enough on the cheapest broadband connection I could get. Addendum: sample xorg.conf file that handles xinerama over two video cards:

Section "ServerLayout"
        Identifier     " Configured"
        Screen      0  "Screen0" 0 0
        Screen      1  "Screen1" RightOf "Screen0"
        InputDevice    "Mouse0" "CorePointer"
        InputDevice    "Keyboard0" "CoreKeyboard"
Section "ServerFlags"
        Option  "Xinerama"      "True"
Section "Files"
        ModulePath   "/usr/lib/xorg/modules"
        FontPath     "/usr/share/fonts/X11/misc"
        FontPath     "/usr/share/fonts/X11/cyrillic"
        FontPath     "/usr/share/fonts/X11/100dpi/:unscaled"
        FontPath     "/usr/share/fonts/X11/75dpi/:unscaled"
        FontPath     "/usr/share/fonts/X11/Type1"
        FontPath     "/usr/share/fonts/X11/100dpi"
        FontPath     "/usr/share/fonts/X11/75dpi"
        FontPath     "/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType"
        FontPath     "built-ins"
Section "Module"
        Load  "extmod"
        Load  "dri2"
        Load  "dbe"
        Load  "glx"
        Load  "dri"
        Load  "record"
Section "InputDevice"
        Identifier  "Keyboard0"
        Driver      "kbd"
Section "InputDevice"
        Identifier  "Mouse0"
        Driver      "mouse"
        Option      "Protocol" "auto"
        Option      "Device" "/dev/input/mice"
        Option      "ZAxisMapping" "4 5 6 7"
Section "Monitor"
        Identifier   "Monitor0"
        VendorName   "Monitor Vendor"
        ModelName    "Monitor Model"
Section "Monitor"
        Identifier   "Monitor1"
        VendorName   "Monitor Vendor"
        ModelName    "Monitor Model"
Section "Device"
        Identifier  "Card0"
        Driver      "tdfx"
        BusID       "PCI:0:9:0"
Section "Device"
        Identifier  "Card1"
        Driver      "nouveau"
        BusID       "PCI:1:0:0"
Section "Screen"
        Identifier "Screen0"
        Device     "Card0"
        Monitor    "Monitor0"
        SubSection "Display"
                Viewport   0 0
                Depth     24
Section "Screen"
        Identifier "Screen1"
        Device     "Card1"
        Monitor    "Monitor1"
        SubSection "Display"
                Viewport   0 0
                Depth     24

This article can be found online at the Debian Administration website at the following bookmarkable URL (along with associated comments):

This article is copyright 2013 pj - please ask for permission to republish or translate.