Using a Virtual Private Network is a good way to work-around geoIP restrictions but also to protect your network traffic when travelling with your laptop and connecting to untrusted networks.

While you might want to use Tor for the part of your network activity where you prefer to be anonymous, a VPN is a faster way to connect to sites that already know you.

Here are my instructions for setting up OpenVPN on Debian / Ubuntu machines where the VPN server is located on a cheap Linode virtual private server. They are largely based on the instructions found on the Debian wiki.

An easier way to setup an ad-hoc VPN is to use sshuttle but for some reason, it doesn't seem work on Linode or Rackspace virtual servers.

Generating the keys

Make sure you run the following on a machine with good entropy and not a VM! I personally use a machine fitted with a Chaos Key.

The first step is to install the required package:

sudo apt-get install easy-rsa openvpn

Then, copy the following file in your home directory (no need to run any of this as root):

mkdir easy-rsa
cp -ai /usr/share/easy-rsa/* easy-rsa/
cd easy-rsa/

and put something like this in your ~/easy-rsa/vars:

export KEY_SIZE=2048
export KEY_COUNTRY="NZ"
export KEY_PROVINCE="AKL"
export KEY_CITY="Auckland"
export KEY_ORG="fmarier.org"
export KEY_EMAIL="francois@fmarier.org"
export KEY_CN="hafnarfjordur.fmarier.org"
export KEY_NAME="hafnarfjordur.fmarier.org"
export KEY_OU="VPN"
export KEY_ALTNAMES=""

Create this symbolic link:

ln -s openssl-1.0.0.cnf openssl.cnf

and set the following in openssl.cnf:

default_crl_days= 3650

to avoid having the CRL expire after one month and throw this error in the logs:

VERIFY ERROR: depth=0, error=CRL has expired:

Finally, generate the keys:

. ./vars
./clean-all
./build-ca                 # press ENTER at every prompt
./build-key-server server  # press ENTER at every prompt, no password
./build-key akranes        # "akranes" as Name, no password
./build-dh
/usr/sbin/openvpn --genkey --secret keys/ta.key

Configuring the server

On my server, called hafnarfjordur.fmarier.org, I installed the openvpn package:

apt-get install openvpn

and then copied the following files from my high-entropy machine:

cp ca.crt dh2048.pem server.key server.crt ta.key /etc/openvpn/
touch /etc/openvpn/crl.pem
chown root:root /etc/openvpn/*
chmod 600 /etc/openvpn/ta.key /etc/openvpn/server.key

Then I took the official configuration template:

cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/
gunzip /etc/openvpn/server.conf.gz

and set the following in /etc/openvpn/server.conf (which includes recommendations from BetterCrypto.org and Gert van Dijk):

dh dh2048.pem
topology subnet
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 74.207.241.5"
push "dhcp-option DNS 74.207.242.5"
tls-auth ta.key 0
auth SHA512
tls-cert-profile preferred
tls-version-min 1.3
cipher AES-256-GCM
user nobody
group nogroup
crl-verify crl.pem

(These DNS servers are the ones I found in /etc/resolv.conf on my Linode VPS.)

Finally, I added the following to these configuration files:

  • /etc/sysctl.d/openvpn.conf:

    net.ipv4.ip_forward=1
    net.ipv4.conf.all.rp_filter=1
    
  • /etc/rc.local (just before exit 0):

    iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
    
  • /etc/default/openvpn:

    AUTOSTART="all"
    

and ran sysctl -p before starting OpenVPN:

/etc/init.d/openvpn start

If the server has a firewall, you'll need to open up this port:

iptables -A INPUT -p udp --dport 1194 -j ACCEPT

as well as let forwarded packets flow:

iptables -A FORWARD -i eth0 -o tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -s 10.8.0.0/24 -o eth0 -j ACCEPT

Configuring the client

The final piece of this solution is to setup my laptop, akranes, to connect to hafnarfjordur by installing the relevant Network Manager plugin:

apt-get install network-manager-openvpn-gnome openvpn-systemd-resolved

The laptop needs these files from the high-entropy machine:

cp ca.crt akranes.crt akranes.key ta.key /etc/openvpn/
chown root:francois /etc/openvpn/akranes.key /etc/openvpn/ta.key
chmod 640 /etc/openvpn/ta.key /etc/openvpn/akranes.key

and my own user needs to have read access to the secret keys.

To create a new VPN, right-click on Network-Manager and add a new VPN connection of type "OpenVPN":

  • Gateway: hafnarfjordur.fmarier.org
  • Type: Certificates (TLS)
  • User Certificate: /etc/openvpn/akranes.crt
  • CA Certificate: /etc/openvpn/ca.crt
  • Private Key: /etc/openvpn/akranes.key
  • Available to all users: NO

then click the "Avanced" button and set the following:

  • Security
    • Cipher: AES-256-GCM
    • HMAC Authentication: SHA512
  • TLS Authentication
    • Server Certificate Check: Verify name exactly
    • Subject Match: server
    • Verify peer (server) certificate usage signature: YES
      • Remote peer certificate TLS type: Server
    • Verify peer (server) certificate nsCertType designation: YES
      • Remove peer certificate nsCert designation: Server
    • Additional TLS authentication or encryption:
      • Mode: TLS-Auth
      • Key File: /etc/openvpn/ta.key
      • Key Direction: 1

There are also compatible clients on Android, iOS and OSX.

Debugging

If you run into problems, simply take a look at the logs while attempting to connect to the server:

tail -f /var/log/syslog

on both the server and the client.

In my experience, searching for the error messages you find in there is usually enough to solve the problem.

Next steps

With the basics working, you could now add support for IPv6 to your VPN.

The next thing I'm going to add to this VPN setup is a local unbound DNS resolver that will be offered to all clients.

Is there anything else you have in your setup and that I should consider adding to mine?