←back to Articles

HOWTO: Set up OpenVPN in a VPS

This content is 14 years old and may not reflect reality today nor the author’s current opinion. Please keep its age in mind as you read it.

If, like me, you want to do any or all of the following things, you’ll want to tunnel your traffic over a VPN to a remote location:

  • Access media services restricted by geography (Hulu, FOX, BBX, etc.)
  • Bypass draconian censorship
  • Conceal your identity/location/etc.
  • Protect your machine from attackers
  • etc.

You could of course use a commercial service like AlwaysVPN in which case you typically pay ($5-10) per month or (~$1) per gigabyte, but many will prefer to run their own service. FWIW AlywaysVPN has worked very well for me but it’s time to move on.

First thing’s first you’ll want to find yourself a remote Linux server, and the easiest way to do so is to rent a virtual private server (VPS) from one of a myriad providers. No point spending more than 10 bucks a month on it as you don’t need much in the way of resources (only bandwidth). Check out lowendbox.com for VPS deals under $7/month or just run with a BurstNET VPS starting at $5.95/month for a very reasonable resource allocation (including a terabyte of bandwidth!).

Once you’ve placed your order and passed their fraud detection systems (which includes an automated callback on the number you supply) you’ll have to wait 12-24 hours for activation, upon which you’ll receive an email with details for accessing your vePortal control panel as well as the VPS itself (via SSH). You’ll get 2 IP addresses and I dedicated the second to both inbound and outbound traffic for VPS clients (which live on a 10.x RFC1918 subnet and access the Internet via SNAT).

If you didn’t already do so when signing up then choose a sensible OS in your control panel (“OS Reload”) like Ubuntu 8.04 – a Long Term Support release which means you’ll be getting security fixes for years to come – or better yet, 10.4 if it’s been released by the time you read this (it’s the next LTS release). Do an “apt-get install unattended-upgrades” and you ought to be fairly safe until 2015. You’re also going to need your TUN/TAP device(s) enabled which involves another trip to the control panel (“Enable Tun/Tap”) and/or a helpdesk ticket (http://support.burst.net/). If /dev/net/tun doesn’t exist then you can create it with “mknod /dev/net/tun c 10 200”.

To install OpenVPN it’s just a case of doing “apt-get install openvpn”… you could also download a free 2-user version of OpenVPN-AS from http://openvpn.net/ but I found it had problems trying to load netfilter modules that were already loaded so YMMV. If you want support or > 2 users you’ll be looking at a very reasonable $5/user – you’re on your own with the free/open source version but there’s no such limitations either.

OpenVPN uses PKI but rather than go to a certificate authority we’ll set one up ourselves. EasyRSA is included to simplify this process so it’s just a case of doing something like this:

cd /usr/share/doc/openvpn/examples/easy-rsa/2.0.
./vars
./clean-all
./build-ca
./build-dh
openvpn --genkey --secret ta.key./build-key-server server
./build-key client1./build-key client2
./build-key client3

It’ll ask you a bunch of superflous information like your country, state, city, organisation, etc. but I just filled these out with ‘.’ (blank rather than the defaults) – mostly so as not to give away information unnecessarily to anyone who asks. The only field that matters is the Common Name which you probably want to leave as ‘server’, ‘client1’ (or some other username like ‘samj’), etc. When you’re done here you’ll want to “cp keys/* /etc/openvpn” so OpenVPN can see it.

Next you’ll want to configure the OpenVPN server and client(s) based on examples in /usr/share/doc/openvpn/examples/sample-config-files. I’m running two – one “Faster” one for the best performance when I’m on a “clean” connection (which uses udp/1194) and another “Compatible” one for when I’m on a restricted/corporate network (which shares tcp/443 with HTTPS). I did a “zcat server.conf.gz > /etc/openvpn/faster.conf” and edited it so it (when filtered with cat faster.conf | grep -v "^#" |grep -v "^;" | grep -v "^$") looks something like this:

local 173.212.x.x
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh1024.pem
server 10.9.0.0 255.255.255.0
ifconfig-pool-persist faster-ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
client-to-client
keepalive 10 120
tls-auth ta.key 0
cipher BF-CBC
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn/faster-status.log
log-append /var/log/openvpn/faster.log
verb 3
mute 20

Noteworthy points:

  • local specifies which IP to bind to – I used the second (of two) that BurstNET had allocated to my VPS so as to keep the first for other servers, but you could just as easily use the first and then put clients behind the second, which would appear to be completely “clean”.
  • We’re using “tun” (tunneling/routing) rather than “tap” (ethernet briding) because BurstNET use venet interfaces which lack MAC addresses rather than veth. Wasn’t able to get bridging up and running, as originally intended.
  • There are various hardening options but to keep it simple I just run as nobody:nogroup and use tls-auth (having generated the optional ta.key with “openvpn –genkey –secret ta.key” above).
  • Pushing Google Public DNS addresses to clients as they won’t be able to use their local resolver addresses once connected. Also telling them to route all traffic over the VPN (which would otherwise only intercept traffic for a remote network).
  • Configured separate log files and subnets (10.8.0.0/24 and 10.9.0.0/24) for the “faster” and “compatible” instances.

The “compatible.conf” file varies only with the following lines:

port 443
proto tcp
server 10.8.0.0 255.255.255.0
status /var/log/openvpn/compatible-status.log
log-append /var/log/openvpn/compatible.log

Next you’ll want to copy over client.conf from /usr/share/doc/openvpn/examples/sample-config-files (but set ‘AUTOSTART=”compatible faster”‘ in /etc/default/openvpn so it’s ignored by the init scripts).

client
dev tun
proto udp
remote 173.212.x.x 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca burstnet-ca.crt
cert burstnet-client.crt
key burstnet-client.key
ns-cert-type server
tls-auth burstnet-ta.key 1
tls-cipher DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA
cipher BF-CBC
comp-lzo
verb 3

As I’ve got a bunch of different connections on my clients I’ve prepended “burstnet-” to all the files and called the main config files “BurstNET-Faster.conf” and “BurstNET-Compatible.conf” (which appear in the Tunnelblick menu on OS X as “BurstNET-Faster” and “BurstNET-Compatible” respectively – thanks to AlwaysVPN for this idea). The only difference for BurstNET-Compatible.conf is:

proto tcp
remote 173.212.x.x 443

You’re now almost ready for the smoke test (and indeed should be able to connect) but you’ll end up on a 10.x subnet and therefore unable to communicate with anyone. The fix is “iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -j SNAT --to-source 173.212.x.x” (where the source IP is one of those allocated to you).

Being paranoid though I want to lock down my server with a firewall, which for Ubuntu typically means ufw (you’ll need to “apt-get install ufw” if you haven’t already). My ufw rules look something like this:

# ufw status
Status: active
To                         Action  From
--                         ------  ----
Anywhere                   ALLOW   1.2.3.4
1194/udp                   ALLOW   Anywhere
443/tcp                    ALLOW   Anywhere

The first rule allows me to access the server from home via SSH and 1194/udp and 443/tcp allow VPN clients in. To allow the clients to access the outside world we’re going to have to rewrite their traffic to come from a public IP (which is called “SNAT”), but first you’ll want to enable forwarding by setting DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw. Then it’s just a case of adding something like this to /etc/ufw/before.rules:

# nat Table rules
*nat
:POSTROUTING ACCEPT [0:0]

# SNAT traffic from VPN subnet.
-A POSTROUTING -s 10.8.0.0/255.255.255.0 -j SNAT --to-source 173.212.x.x
-A POSTROUTING -s 10.9.0.0/255.255.255.0 -j SNAT --to-source 173.212.x.x

# don't delete the 'COMMIT' line or these nat table rules won't be processed
COMMIT

You may need to enable UFW (“ufw enable”) and if you lose access to your server you can always disable UFW (“ufw disable”) using the rudimentary “Console” function of vePortal.

On the client side you’ve got support for (at least) Linux (e.g. “openvpn --config /etc/openvpn/BurstNET-Faster.conf“), Mac and Windows and there’s various GUIs (including OpenVPN GUI for Windows and Tunnelblick for Mac OS X). I’m (only) using Tunnelblick, and after copying Tunnelblick.app to /Applications I just need to create a ~/Library/openvpn directory and drop these files in there:

  • BurstNET-Compatible.conf
  • BurstNET-Faster.conf
  • burstnet-ca.crt
  • burstnet-client.key
  • burstnet-client.crt
  • burstnet-ta.key

When Tunnelblick’s running I have a little black tunnel symbol in the top right corner of my screen from which I can connect & disconnect as necessary.

I think that’s about it – hopefully there’s nothing critical I’ve missed but feel free to follow up in the comments if you’ve anything to add. I’m now happily streaming from Hulu and Fox in the US, downloading Amazon MP3s (using my US credit card), and have a reasonable level of anonymity. If I was in Australia I’d have little to fear from censorship (and there’s virtually nothing they can do to stop me) and as my machine has a private IP I’m effectively firewalled.

Update: It seems that my VPS is occasionally restarted (which is not all that surprising) and forgets about its tun/tap device (which is). The device node itself is still visible in the filesystem, but with no driver to connect to in the kernel it doesn’t work and OpenVPN doesn’t start. You can test if your tun device is working using cat:

WORKING:

cat /dev/net/tun
cat: /dev/net/tun: File descriptor in bad state

NOT WORKING:

cat /dev/net/tun
cat: /dev/net/tun: No such device

I’ve also noticed that ufw may need to be manually started with a ‘ufw enable’. Hope that saves you some time diagnosing problems!