Set up OpenVPN on Ubuntu 16.04 — For Safety’s Sake!

By: Steven J. Vaughan-Nichols

It’s a dangerous world out there on the public internet. Here’s how to make it safer for you and your users.

Want to know a really scary IT statistic? Xirrus, a leading Wi-Fi company, recently polled more than 2,000 executives and IT professionals. They found that while 91 percent of respondents know public Wi-Fi is insecure… 89 percent go ahead and use it anyway.

Whoops!

One thing you can do to help clean up this security mess is to provide a virtual private network (VPN) so that your users’ traffic gets protected before hackers can get their digital mitts on it. There are many VPN servers, but OpenVPN is my VPN server of choice because it’s very popular, easy to use, and widely supported. When integrated with OpenSSL, OpenVPN can encrypt all VPN traffic to provide a secure connection between machines.

Better still, it’s easy to set up your OpenVPN server to forward internet traffic. Finally, but not least, OpenVPN works well on almost all devices.

You can run OpenVPN on pretty much any Linux server, but in this post I’m going to be talking about the latest long-term support (LTS) of Ubuntu Linux: Ubuntu 16.04.

Before you begin

To get OpenVPN up and running, the first thing you need to do is, of course, have a running Ubuntu 16.04 server:

Familiarize yourself with Linode’s Getting Started guide and complete the steps for setting your time zone. This guide will use sudo wherever possible. Complete the sections of Linode’s Securing Your Server guide to create a standard user account, harden SSH access and remove unnecessary network services. Do not follow the Creating a Firewall section–this guide has instructions specifically for firewall rules for an OpenVPN server. Update your system:

sudo apt-get update

sudo apt-get upgrade

Manage the OpenVPN Environment

Next, we’re going to install the OpenVPN Community Edition. In this, server and client configuration files are manually edited and client credentials are copied to their target devices.

Another way of doing this is with the commercial uses OpenVPN Access Server. This is a server-side application which lets you configure OpenVPN through your web browser.

Client machines use a private URL to download their security credential packages. If you are interested in running OpenVPN Access Server, see the Linode guide: Secure Communications with OpenVPN Access Server.

Networking Rules

For your network, like it or not, you’re going to be using IPv4 for your VPN. OpenVPN 2.4 will support both IPv4 and IPv6 at the same time, but it’s not ready yet. We’re running out of IPv4 addresses, but it’s still the most common network protocol, so you’ll be running with it.

Firewall

Next, flush any pre-existing firewall rules and non-standard chains which may be in the system as below:

sudo iptables -F && sudo iptables -X

Now, use the Securing Your Server guide and complete the section on iptables for Ubuntu using the ruleset below:

*filter

# Allow all loopback (lo) traffic and reject anything

# to localhost that does not originate from lo.

-A INPUT -i lo -j ACCEPT

-A INPUT ! -i lo -s 127.0.0.0/8 -j REJECT

-A OUTPUT -o lo -j ACCEPT

# Allow ping and ICMP error returns.

-A INPUT -p icmp -m state — state NEW — icmp-type 8 -j ACCEPT

-A INPUT -p icmp -m state — state ESTABLISHED,RELATED -j ACCEPT

-A OUTPUT -p icmp -j ACCEPT

# Allow SSH.

-A INPUT -i eth0 -p tcp -m state — state NEW,ESTABLISHED — dport 22 -j ACCEPT

-A OUTPUT -o eth0 -p tcp -m state — state ESTABLISHED — sport 22 -j ACCEPT

# Allow UDP traffic on port 1194.

-A INPUT -i eth0 -p udp -m state — state NEW,ESTABLISHED — dport 1194 -j ACCEPT

-A OUTPUT -o eth0 -p udp -m state — state ESTABLISHED — sport 1194 -j ACCEPT

# Allow DNS resolution and limited HTTP/S on eth0.

# Necessary for updating the server and keeping time.

-A INPUT -i eth0 -p udp -m state — state ESTABLISHED — sport 53 -j ACCEPT

-A OUTPUT -o eth0 -p udp -m state — state NEW,ESTABLISHED — dport 53 -j ACCEPT

-A INPUT -i eth0 -p tcp -m state — state ESTABLISHED — sport 80 -j ACCEPT

-A INPUT -i eth0 -p tcp -m state — state ESTABLISHED — sport 443 -j ACCEPT

-A OUTPUT -o eth0 -p tcp -m state — state NEW,ESTABLISHED — dport 80 -j ACCEPT

-A OUTPUT -o eth0 -p tcp -m state — state NEW,ESTABLISHED — dport 443 -j ACCEPT

# Allow traffic on the TUN interface

-A INPUT -i tun0 -j ACCEPT

-A OUTPUT -o tun0 -j ACCEPT

# Log any packets which don’t fit the rules above…

# (optional but useful)

-A INPUT -m limit — limit 3/min -j LOG — log-prefix “iptables_INPUT_denied: “ — log-level 4

-A FORWARD -m limit — limit 3/min -j LOG — log-prefix “iptables_FORWARD_denied: “ — log-level 4

-A OUTPUT -m limit — limit 3/min -j LOG — log-prefix “iptables_OUTPUT_denied: “ — log-level 4

# then reject them.

-A INPUT -j REJECT

-A FORWARD -j REJECT

-A OUTPUT -j REJECT

COMMIT

“Tun,” you ask? That’s the virtual interface between the OpenVPN daemon and your Linode’s eth0 network interface..

Install and Configure OpenVPN

These next few sections require that we temporarily switch to a root user:

sudo su -

Note that you shouldn’t leave this user logged in when you’re not actively working. If you need to log out of root before completing this section, enter the command, exit.

Rather than just install OpenVPN, I like to install easy-rsa as well. This is a simple, private RSA certificate authority (CA) program. It makes installing security certificates, which are essential for OpenVPN to work, much simpler. So, I run:

apt-get install openvpn easy-rsa

Next, you must extract from the archive of config templates OpenVPN’s server-side configuration file, /etc/openvpn/server.conf, with the following command:

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

Now, run the make-cadir script to copy over the necessary files from /usr/share/doc/openvpn/examples/ and create your working directory. Then, change location into it:

make-cadir /etc/openvpn/easy-rsa

cd /etc/openvpn/easy-rsa/

Next, create a symbolic link from openssl-1.0.0.cnf to openssl.cnf:

ln -s openssl-1.0.0.cnf openssl.cnf

The permissions of /etc/openvpn/easy-rsa/keys are 0700, which do not allow for group or world access to the key and certificate files. For this reason, keep keys as the storage location for server credentials by specifying the absolute paths in OpenVPN’s server.conf. 4096 will be created in the next section, so expect your default server.conf to look a little different.

Here’s a sample of the server.conf:

/etc/openvpn/server.conf

# 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 /etc/openvpn/easy-rsa/keys/ca.crt

cert /etc/openvpn/easy-rsa/keys/server.crt

key /etc/openvpn/easy-rsa/keys/server.key # This file should be kept secret

# Diffie hellman parameters.

# Generate your own with:

# openssl dhparam -out dh4096.pem 4096

# Substitute 4096 for 1024 to use 4096 bit keys.

dh /etc/openvpn/dh4096.pem

Harden OpenVPN

Notice how we’re using 4096 instead of the default 1024? As computers get faster, it gets easier and easier to crack encryption codes. The longer your keys, the more sturdy they are against hackers.

While you’re editing this file, let’s go ahead and make it even more secure by giving OpenVPN’s data channel better encryption by adding the line to the end of server.conf:

cipher AES-256-CBC

This is more secure than the default Blowfish-128 cipher.

Then, let’s enhance the data channel’s authentication digest by upgrading it to SHA-512, a SHA-2 hash function by adding this line to the end of server.conf:

auth SHA512

To further harden your OpenVPN from attackers, you should require keyed-hash message authentication code (HMAC) to be identical. This requires that any HMAC packet signature in the TLS handshake between the server and connecting clients be identical. To do this, uncomment the line by removing the “;” (semicolon) at its beginning.

tls-auth ta.key 0 # This file is secret.

Finally, restrict the VPN’s control channel to strong cipher suites. It is recommended to be as restrictive as possible here, but not all cipher suites can be used with all versions of OpenVPN.

Limit the pool to AES in GCM mode over TLS 1.2 using SHA 2, and both AES and Camellia in CBC mode using SHA 1 over TLS 1.0. Do this by adding this line to the end of the file :

tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA

Save and close the server.conf file.

You now need to create the pem file we inserted earlier.

You do this by using OpenSSL’s Diffie-Hellman PEM to create keys. You create a 4,096-bit key with the command:

openssl dhparam 4096 > /etc/openvpn/dh4096.pem

Create the ta.key:

openvpn — genkey — secret /etc/openvpn/easy-rsa/keys/ta.key

Last, but never least, OpenVPN has this nasty habit of running as root. Nothing should run as root unless you have no other choice.

You remedy this problem by creating a new limited user account for the OpenVPN daemon to run as, and then tell it to drop privileges to that account after startup. As an example, the name openvpn_server is used:

adduser — system — shell /usr/sbin/nologin — no-create-home openvpn_server

Uncomment the user and group lines, and edit user with the username above. This tells the daemon to drop root privileges and switch to the openvpn_server user after startup.

To get OpenVPN to grok what’s going on, add these lines to your /etc/openvpn/server.conf file:

user openvpn_server

group nogroup

OK. OpenVPN is now ready. Let’s give it some certificates, so it can start securing your communications.

Certificate and Key Pairs

From here, you must be in the easy-rsa directory, so be sure go there,

cd /etc/openvpn/easy-rsa

Now, it’s time to give your CA some var values to work with. For example, you might edit the vars file to read

/etc/openvpn/easy-rsa/vars

# These are the default values for fields

# which will be placed in the certificate.

# Don’t leave any of these fields blank.

export KEY_COUNTRY=”US”

export KEY_PROVINCE=”NC”

export KEY_CITY=”Asheville”

export KEY_ORG=”TheShire”

export KEY_EMAIL=”me@myself.mydomain”

export KEY_OU=”MyCompany”

You don’t need to use all of those keys, but what you can’t do is use one and leave it blank. Bad things will happen.

Source the .vars file to refresh the settings and use clean-all to give it a fresh start:

source ./vars

./clean-all

Server Credentials

A root certificate is the certificate used to generate client keypairs. At each prompt, add or edit the information to be used in your certificate (or leave them blank).

Use your server’s hostname or some other ID as the common name, and leave the challenge password blank:

./build-ca

Then, create the server’s private key. Again, add or edit at the information prompts as needed:

./build-key-server server

When you’ve completed the question section for the private key, confirm the signing of the certificate and the certificate requests certified by answering “yes” to those two questions.

Client Credentials

Each client device connecting to the VPN should have its own unique key. Furthermore, each key should have its own name. All other certificate information can remain the same. If you need to add users at any time later, just repeat these commands:

cd /etc/openvpn/easy-rsa

source ./vars && ./build-key client1

Anyone with access to client1.key will be able to access your VPN. To better protect against this scenario, you can issue ./build-key-pass client1 instead to build a client key which is encrypted with a passphrase.

Client Configuration File

Each client needs a configuration file defining the OpenVPN server’s settings for it. It’s a good idea to keep a copy of your client config file on the server as a template in case more clients are added in the future. It cannot be located in /etc/openvpn, because then the OpenVPN daemon won’t know whether to load client.conf or server.conf. For this reason, you should store it in the keys folder with the other client files, even though the file does not need to be kept secret.

Copy the client.conf template file and open it for editing. Most clients require a .ovpn file format instead of .conf, and the file extension can be changed during extraction:

cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/easy-rsa/keys/client.ovpn

Update the remote line in the client.ovpn with the OpenVPN server’s IP address:

/etc/openvpn/easy-rsa/keys/client.ovpn

# The hostname/IP and port of the server.

# You can have multiple remote entries

# to load balance between the servers.

remote 192.0.2.0 1194

You could use a hostname, but since all Linodes have static public IP addresses, it’s a bit more secure to to connect by IP and bypass the DNS lookup.

On all but Windows systems tell the client-side OpenVPN service to drop root privileges. You do this by editing the file /etc/openvpn/easy-rsa/keys/client.ovpn with the following lines:

user nobody

group nogroup

Further down in the /etc/openvpn/easy-rsa/keys/client.ovpn file, edit the crt and key lines to reflect the names and locations on the client device. Specify the path to the files so they, and client.ovpn, will not be stored in the same folder.

# SSL/TLS parms.

# See the server config file for more

# description. It’s best to use

# a separate .crt/.key file pair

# for each client. A single ca

# file can be used for all clients.

ca /path/to/ca.crt

cert /path/to/client1.crt

key /path/to/client1.key

Tell the client to use the HMAC key generated earlier. Again specify the path, if necessary, in file, /etc/openvpn/easy-rsa/keys/client.ovpn:

# If a tls-auth key is used on the server

# then every client must also have the key.

tls-auth /path/to/ta.key 1

Since the VPN server was told to force certain cryptographic settings in its config file, the clients must have the same settings. Add these lines to the end of client.ovpn:

cipher AES-256-CBC

auth SHA512

If you added any lines for Control Channel cipher suites to the server above, add those lines to client.ovpn too:

tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA

Pack all the necessary client files into a tarball ready for transferring. The specific files are:

/etc/openvpn/easy-rsa/keys/ca.crt

/etc/openvpn/easy-rsa/keys/client1.crt

/etc/openvpn/easy-rsa/keys/client1.key

/etc/openvpn/easy-rsa/keys/client.ovpn

/etc/openvpn/easy-rsa/keys/ta.key

tar -C /etc/openvpn/easy-rsa/keys -cvzf /etc/openvpn/client1.tar.gz {ca.crt,client1.crt,client1.key,client.ovpn,ta.key}

These are then ready to ship to your users. Windows will need 7zip to extract .tar files. You can also use the package zip to create a .zip archive, which can easily be opened on almost any operating system.

At this point, you no longer need to be root, so exit back to your standard user:

exit

Finally, start the OpenVPN daemon and enable it on reboot:

sudo systemctl enable openvpn.service

sudo systemctl start openvpn.service

These commands will scan the /etc/openvpn directory on the server for files with a .conf extension. For every file that it finds, it will spawn a VPN daemon (server instance), so make sure you don’t have a client.conf or client.ovpn file in there.

You’re now ready to start securing your users — whether they’re working down the hall or down at Joe’s Barbecue.