Surfing the web through an open or public network like a hotel Wi-Fi for example, might potentially be unsafe. Doing online banking or logging into a website with your password can become a huge security risk. To come along this security issues, you can use a virtual private network to tunnel all your internet traffic through a secure and encrypted connection.

There are several ways set up your own VPN. I will show you how to quickly set up a basic working VPN tunnel with OpenVPN on Ubuntu 14.04 server. Most steps in this guide are based one the Ubuntu Server Guide, so don’t wonder if some parts look identical. Anyways, sometimes I’ll do things slightly different or leave out unnecessary stuff. My goal is to get a working OpenVPN tunnel as easy as possible without any bells or whistles.

Please also note that I am not a system administrator nor a network expert. So please write comments and correct me if something is wrong or could be improved.

OpenVPN Server

On Ubuntu 14.04 the OpenVPN sever can be installed with the APT package manager:

sudo apt-get install openvpn easy-rsa

Since we’ll use the certificate-based authentication, we first need to set up our own certification authority (CA) to create and sign the server and client certificates later. The easy-rsa package brings everything we need to do this.

To prevent the easy-rsa scripts to get lost when doing server upgrades, switch to your root user and copy them to the /etc/openvpn/ directoy:

mkdir /etc/openvpn/easy-rsa/
cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/

Now open the /etc/openvpn/easy-rsa/vars file and adopt the following values according to your needs:

export KEY_COUNTRY="DE"
export KEY_PROVINCE="BER"
export KEY_CITY="Berlin"
export KEY_ORG="Example Company"
export KEY_EMAIL="[email protected]"
export KEY_CN=MyVPN
export KEY_NAME=MyVPN
export KEY_OU=MyVPN

Run the following command to build the certification authority (CA):

cd /etc/openvpn/easy-rsa/
source vars
./clean-all
./build-ca

If you discover an error while trying to building the CA, please see below in the trouble shooting section for help.

The next step is to generate the Diffie Hellman parameters for the OpenVPN server:

./build-dh

Server certificates

Now we are ready to generate and sign the server certificates. easy-rsa also offers a script which does all the work for you. You’ll have to enter some parameters for the server certificate. Most of the default values from /etc/openvpn/easy-rsa/vars should be correct.

./build-key-server server

You’ll be asked whether to “Sign the certificate? [y/n]” and “1 out of 1 certificate requests certified, commit? [y/n]”, answer both questions with yes.

The server certificates and keys have been generated into the subdirectory /etc/openvpn/easy-rsa/keys/. Common practice is to copy them to /etc/openvpn/:

cd keys/
cp server.crt server.key ca.crt dh2048.pem /etc/openvpn/

Client certificates

Each VPN client will also need a certificate to authenticate itself to the server. Usually you create a different certificate for each client. To create the certificate, enter the following in a terminal while being user root:

cd /etc/openvpn/easy-rsa/
source vars
./build-key client1

Copy the following files to the client using a secure method:

  • /etc/openvpn/ca.crt
  • /etc/openvpn/easy-rsa/keys/client1.crt
  • /etc/openvpn/easy-rsa/keys/client1.key

As the client certificates and keys are only required on the client machine, ensure to remove them from the server afterwards.

Server configuration

Along with your OpenVPN installation you got a basic sample config file:

[email protected] ~ # ls -l /usr/share/doc/openvpn/examples/sample-config-files/
total 68
-rw-r--r-- 1 root root 4141 Feb  4 15:34 server.conf.gz

Start with copying and unpacking server.conf.gz to /etc/openvpn/server.conf.

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

Edit /etc/openvpn/server.conf to make sure the following lines are pointing to the certificates and keys you created in the section above.

ca ca.crt
cert server.crt
key server.key
dh dh2048.pem

That is the minimum you have to configure to get a working OpenVPN server. You can use all the default settings in the sample server.conf file. Now start the server. You will find logging and error messages in your syslog.

[email protected] ~ # service openvpn start
 * Starting virtual private network daemon(s)...     *   Autostarting VPN 'server'

Now check if OpenVPN created a tun0 interface:

[email protected] ~ # ifconfig tun0
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          inet addr:10.8.0.1  P-t-P:10.8.0.2  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
...

Routed VPN configuration on server

We still have working OpenVPN server, but in order to get our internet traffic routed from the client through the server we need to change some configurations.

To keeps things simple you’ll find my server.conf here. Edit the config so it looks like the following:

port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1"
push "dhcp-option DNS 84.200.69.80"
push "dhcp-option DNS 84.200.70.40"
keepalive 10 120
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status openvpn-status.log
verb 3

To make the new configuration take effect we need to restart the OpenVPN server:

sudo service openvpn restart

If you are using a firewall, you may need to open port 1194 to allow connections to your OpenVPN server. Since I am using ufw this can be done by entering the following command in the terminal:

sudo ufw allow 1194

We’re almost done. You should still be able to connect with the client to the OpenVPN server and get an IP address from our local 10.8.0.0/24 subnet. The only problem is that client is limited to his subnet and unable to get an internet connection. Therefore, we need to set up NAT to route all traffic coming from the local OpenVPN subnet on device tun0 to eth0 (and vice versa).

In order to get NAT working we have to activate packet forwarding in sysctl.

sudo vim /etc/sysctl.conf

Uncomment the following line:

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

Now we are able add a new POSTROUTING route to iptables to route all the traffic coming from our local 10.8.0.0/24 subnet to the physical network device eth0.

sudo /sbin/iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

To add a bit more extra security we also add some FORWARD rules to iptables. The first one will only allow incoming connections to the OpenVPN subnet if they have been initial establish by the server. The second rule is to allow all outgoing connections from your server.

sudo /sbin/iptables -A FORWARD -i eth0 -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo /sbin/iptables -A FORWARD -i tun0 -o eth0 -j ACCEPT

You should now be able to establish a secure VPN tunnel between your client and the OpenVPN server. I won’t cover the client configuration here. If you need help on how to configure the VPN client there should be plenty of tutorials out there. Also, the client configuration may vary depending on which client you are using.

Trouble shooting

You may discover the following error message when trying to build running the ./build-ca command:

error on line 198 of /etc/openvpn/easy-rsa/openssl-1.0.0.cnf
140224783447712:error:0E065068:configuration file routines:STR_COPY:variable has no value:conf_def.c:618:line 198

To fix this error open /etc/openvpn/easy-rsa/vars and add the following line at the end of the file:

export KEY_ALTNAMES="something"

This should do the trick.