How to install and setup OpenVPN on Ubuntu server

This website was born to keep track of my projects, I tend to forget how to setup something if I’m not doing it daily. I have a collection of text file in my computer and this new one is about installing the OpenVPN application on a Ubuntu server. I made the configuration easy, removing the unnecessary. I suggest to read the OpenVPN manual to adapt the configuration for a specific use.

First, obviously, find a suitable Ubuntu server.
In order to have the VPN working, this server must be connected behind a firewall (or directly on the internet if you are using the same server as a firewall) and open the OpenVPN port, but only after the configuration is done.

Update the repository:

apt-get update

And install the OpenVPN server:

apt-get install openvpn easy-rsa

At the end of the installation, extract the server.conf inside openvpn folder:

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

And edit it:

vi /etc/openvpn/server.conf

I tend to remove comments to make the file more readable:

# the port to use
port 1194

# For a VPN it is preferred to use UDP
# faster and not need to correct packet errors
proto udp

# The adapter
dev tun

# The certificates
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.
dh /etc/openvpn/easy-rsa/keys/dh2048.pem

# The OpenVPN's server's address will be 10.8.0.1
server 10.8.0.0 255.255.255.0

# Maintain a record of client <-> virtual IP address
# associations in this file.  If OpenVPN goes down or
# is restarted, reconnecting clients can be assigned
# the same virtual IP address from the pool that was
# previously assigned.
ifconfig-pool-persist ipp.txt

# Push routes to the client to allow it
# to reach other private subnets behind
# the server.
push "route 10.10.0.1 255.255.255.255"

# For the clients to see each other
client-to-client
route 10.10.0.0 255.255.255.0

# Ping every 10 seconds, assume that remote
# peer is down if no ping received during
# a 120 second time period.
keepalive 10 120

# For extra security
tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0 # This file is secret

# Enable compression on the VPN link.
# must be enabled on clients too 
comp-lzo

# The persist options will try to avoid
# accessing certain resources on restart
# that may no longer be accessible because
# of the privilege downgrade.
persist-key
persist-tun

# Output a short status file showing
# current connections, truncated
# and rewritten every minute.
status openvpn-status.log

# From 0 to 9 where 0 is log disabled 
verb 3

# A way to disable users without revoking certificates
script-security 3 system
tls-verify "/etc/openvpn/tls_check.sh /etc/openvpn/userlist.txt"

When the configuration file is ready, we can create the Diffie hellman parameters and the ta.key file that both gives an extra layer of security:

openvpn --genkey --secret ta.key
openssl dhparam -out /etc/openvpn/dh2048.pem 2048

And we can already manage the connections working on these 2 file: ipp.txt and tls_check.sh.
About ipp.txt, this file will contain the internal ipv4 addresses the clients use to connect to the server.
Suppose we have 3 clients:

client1,10.8.0.4
client2,10.8.0.8
client3,10.8.0.12

The addresses are shifted of 4 addresses, because you need to count the network, the broadcast and the address itself. Client1 will be 10.8.0.6, client2,10.8.0.10 and client3,10.8.0.14.

The tls_check.sh instead, is a script that checks every connection and ensures that the CN used in the certificate is allowed to connect to the server. Check out the owner’s POST about his tool.

#!/bin/sh


#    ovpnCNcheck -- an OpenVPN tls-verify script
#    """""""""""""""""""""""""""""""""""""""""""
#
#    This script checks if the peer is in the allowed
#    user list by checking the CN (common name) of the
#    X509 certificate against a provided text file.
#
#    For example in OpenVPN, you could use the directive
#    (as one line):
#
#    tls-verify "/usr/local/sbin/ovpnCNcheck.py
#                /etc/openvpn/userlist.txt"
#
#    This would cause the connection to be dropped unless
#    the client common name is within the userlist.txt.
#
#    Special care has been taken to ensure that this script
#    also works on openwrt systems where only busybox is
#    available 
#
#    Written by Robert Penz <robert@penz.name> under the GPL 2
#    Parts are copied from the verify-cn sample OpenVPN
#    tls-verify script.


[ $# -eq 3 ] || { echo usage: ovpnCNcheck.sh userfile certificate_depth X509_NAME_oneline ; exit 255 ; }

# $2 -> certificate_depth
if [ $2 -eq 0 ] ; then
	# $3 -> X509_NAME_oneline
	# $1 -> cn we are looking for
	grep -q "^`expr match "$3" ".*/CN=\([^/][^/]*\)"`$" "$1" && exit 0
	exit 1
fi

exit 0

I’m using this folder to store the certificates: /etc/openvpn/easy-rsa/keys.

cp -r /usr/share/easy-rsa/ /etc/openvpn
mkdir /etc/openvpn/easy-rsa/keys
cd /etc/openvpn/easy-rsa

At the creation of the certificate, it is important to fill in the correct information. Probably not that important for internal use, but at least the Common Name (CN), which MUST be different for any released certificate and MUST match the names used in the userlist.txt, else the tls_check script won’t work.

For all the rest, edit VARS to match your organization, city, country… if you like:

vi vars

Once done, load and build it all:

source ./vars
./clean-all
./build-ca

And now, create and sign the certificate for the server (where SERVER is the name you want to give to the certificate, but can be later renamed):

./build-key-server SERVER

And for the client:

./build-key CLIENT

I would not use any password, but it is up to you.

Move now the below created certificate and key to the client computer.

/etc/openvpn/easy-rsa/keys/client.crt
/etc/openvpn/easy-rsa/keys/client.key
/etc/openvpn/easy-rsa/keys/ca.crt
/etc/openvpn/easy-rsa/keys/ta.key

And after you install the OpenVPN client on you machine, create the client.ovpn file, this one:

client
dev tun
dev-node VPN
proto udp
port 1194
remote 12.34.56.78
resolv-retry infinite
persist-key
persist-tun
ca certs/ca.crt
cert certs/client.crt
key certs/client.key
ns-cert-type server
tls-auth certs/ta.key 1
comp-lzo
verb 5

The dev-node is the name given to the OpenVPN adapter on Windows, remove when the connection comes from a Linux system.
The remote is the address of your server.
And the certificates are those copied from the server to this client, watch out in keeping the ta.key and ca.crt as safest as possible.

If all is done well, the connection should work instantly. Remember to open the 1194 from the server to accept any UDP packets from your client and in case of problems, enable the full log (9).