OpenVPN

Ben's 5 Minute VPN Setup

I was recently wanting to setup a VPN server using a spare computer which runs Ubuntu Server. As I often do I did a quick Google search along the lines of "ubuntu server vpn setup". Well I didn't find much along the lines of tutorials or guides I could follow. I did find that it was relatively easy to setup a PPTP VPN server using only a text based username and password for authentication. I also saw that OpenVPN was very popular, but couldn't find a straightforward way to configure it.

Well I first went with the PPTP setup, but it was flawed for two reasons: Most importantly was that the only thing standing between my server and the internet was a username and password, which are inherently insecure (or not as secure as they should be). Secondly and less important to me was that PTPP is flawed in that the encryption is broken. My primary goal was to access my network shares from afar, but most people use VPNs to encrpyt their traffic from third parties.

I decided to go back to the drawing board and discovered that in my quest for an easy setup I had overlooked the actual OpenVPN documentation. Originally the guides I had referenced had been written in the days of an older OpenVPN version, a version that included Easy RSA and / or involved more complicated routing schemes. Easy RSA must now be installed separately from OpenVPN, but that didn't help as the tutorials still referenced the old version which was only slightly different, but still left me out of luck.

I knew it couldn't be that hard, as it turns out it really wasn't, the documentation provided by OpenVPN themselves outlines a simple setup that fit just my purposes.

Certificate and Key Setup

First you need to install both OpenVPN and Easy RSA, both of these were in the standard repositories.

Then you need to setup a master Certificate Authority (CA) certificate and key. Using our CA certificate the server will authenticate the client certificate and the client will authenticate the server certificate. In this way both the client and server can be assured that the other is legitimate. Both the clients and server will have a private key. This type of setup is a lot more difficult to compromise than my PTPP username and password setup from before.

To generate this on Ubuntu it was still a little tricky as I installed Easy RSA from the package manager so I did not have it in my OpenVPN folders and it was somewhere else, but where? To find this out I executed the command: dpkg -L easy-rsa
This told me that what I wanted could be found in /usr/share/easy-rsa
I copied that entire directory to my OpenVPN setup directory: cp /usr/share/eas-rsa/ /etc/openvpn/
This is important so we can generate keys and mess around without worrying about corrupting the initially installed version.

Then I went into the newly created easy-rsa directory which should be: /etc/openvpn/easy-rsa and executed the command init-config
This created a file called "vars". Edit this file and set the KEY_COUNTRY, KEY_PROVINCE, KEY_CITY, KEY_ORG, and KEY_EMAIL parameters.

Now run these commands exactly like so (yes the " . ./ " is important!!)":
. ./vars
./clean-all
./build-ca

This is what allows us to build the Certificate Authority CA certificate, follow all the prompts in the interactive interface.

Next we need to build the keys for our server do so with the command: ./build-key-server server
Finally we will generate the client certificates: ./build-key client1
./build-key client2
etc

Then we will need to generate Diffie Hellman parameters for our server. Execute the following: ./build-dh
This generates a .pem file.

Now you have a number of key and certificate files generated, just remember this if it ends in .key keep it secret! Although if a key does become compromised you can always revoke it.

VPN Configuration

We've already done a lot, but we're only halfway there. To get the server running we need to modify the configuration files. For me the sample files were found in /usr/share/doc/openvpn/examples/sample-config-files/
Copy the server.conf file and place it into your /etc/openvpn directory.

At the very least you will need to modify the ca, cert, key, and dh parameters to match those that you just created. Remember that since this is the server configuration we will point to the server keys, also know that these are relative pathnames. For example this is the relevant section from my configuration file:
# Any X509 key management system can be used.
# OpenVPN can also use a PKCS #12 formatted key file
# (see "pkcs12" directive in man page).
ca easy-rsa/keys/ca.crt
cert easy-rsa/keys/server.crt
key easy-rsa/keys/server.key
# This file should be kept secret
# Diffie hellman parameters.
# Generate your own with:
# openssl dhparam -out dh2024.pem 1024
# Substitute 2048 for 1024 if you are using
# 2048 bit keys.
dh easy-rsa/keys/dh2048.pem

After this open the file /etc/sysctl.conf and make sure the following line is uncommented:
net.ipv4.ip_forward=1
This is important in order to have traffic forwarded to the outside web, I believe it's enabled by default in Ubuntu, but double check for yourself.

In order to have our traffic to the outside web routed through the VPN you need to add/uncomment this line in the server.conf file:
(This step may be uneccessary see explanation below)
push "redirect-gateway def1"
And because the server will be interacting with the web it will need to NAT the traffic. So run this command to set that up:
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

I did not initially do this, when I would check my WAN IP address on google or any other service it appeared to already be doing this. My guess is that what was happening was that the OpenVPN box was not functioning as my main router, so when requests to outside urls where made the VPN would ask the router like it would normal internal traffic and the router would then handle the requests.

The only reason I ran the two commands above was because I was trying to get my mobile's IPv6 web requests to go through the VPN. In hindsight of course it didn't work (as the iptables rule isn't even for IPv6).

TL;DR So, if your VPN server is behind a router the above two commands won't do anything, otherwise you will need them to route requests for the outside web through your VPN.

IPv6

I did get IPv6 traffic to work properly on my IPv4 network. The basic gist is that rather than the 10.8.0.0/24 default subnet you have to specify an additional IPv6 subnet for clients connecting from IPv6 addresses. Internally the VPN will route it as normal IPv6. When connecting to the open web the traffic will now be successfully routed through the VPN, meaning the public address will be the public address of the server (which in my case is IPv4).

First you'll probably want to enable IPv6 packet forwarding in /etc/sysctl.conf:
net.ipv6.conf.all.forwarding=1

Edit the server.conf file and add the following lines:
server-ipv6 2001:db8:0:123::/64
tun-ipv6
push tun-ipv6
ifconfig-ipv6 2001:db8:0:123::1 2001:db8:0:123::2
push "route-ipv6 2000::/3"

Again because my VPN box is not the main router I don't really need to worry about traffic NATing, but if it was I would likely need to set up a similar iptable rule for NAT, like above, for IPv6 traffic. This isn't tested and I have no idea if iptables demands different syntax for IPv6, but something like:
iptables -t nat -A POSTROUTING -s 2001:db8:0:123::/64 -o eth0 -j MASQUERADE

Of course check that everything is working as expected with different IP checkers. Do note that not every website is IPv6 enabled. For example ifconfig.me was showing my mobile's address as v4 while Google and whatismyip.com where both showing v6 addresses.

Because I'm going to use GUI interfaces for my clients I didn't worry about the client configuration file.

Firewall Configuration

If you plan to use ufw on the server you'll have to configure that to allow the OpenVPN port (eg. 1194)

In order to actually browse websites we further have to edit /etc/default/ufw
Modify:
DEFAULT_FORWARD_POLICY="DROP"
to be
DEFAULT_FORWARD_POLICY="ACCEPT"

I had set a number of server hardening setting post VPN setup, not surpisingly things weren't working perfectly afterwards. The above firewall settings got me 90% of the way there, but I was encountering a strange issue where I could access sites by their domain names, but could not ping them. Although it did resolve in the browser it was very slow. I modified the DNS settins in the server config and everything was smooth again.
Add or modify this line in your server.conf file. Use the IP of your router or preffered DNS server.
# use router dns
push "dhcp-option DNS 192.168.1.1"

Starting the Server

To start the server we need to run the command: openvpn your_configuration_file
You also need to forward the port 1194 (default, or whichever you specified) from your router settings and point it towards your server.

Wait a second, you want the VPN server to run at boot don't you? This is already taken care of in Ubuntu. Any VPN configuration file contained in /etc/openvpn/your_file.conf will be automatically run!

Connect the Clients

The server will have the IP address 10.8.0.1 (connected devices will take subsequent addresses eg. 10.8.0.2 and so on) You can ping this to verify connectivity. I will still access network shares using my normal IP and not the 10.8.0.1 address despite the shares being on the VPN server computer.

Also keep in mind that there are other ways than .key and .crt depending on your scenario you may want to do that. For example on android I ran into problems connecting this way and found it easier to use my .key and .crt files to generate a single .p12 file.