Sep 19, 2018

How To Set Up an OpenVPN Server on Ubuntu

Install OpenVPN

sudo apt -y update

sudo apt -y install openvpn easy-rsa

Set Up the CA Directory 

OpenVPN is an TLS/SSL VPN. This means that it utilizes certificates in order to encrypt traffic between the server and clients. In order to issue trusted certificates, we will need to set up our own simple certificate authority (CA).

To begin, we can copy the easy-rsa template directory into our home directory with the make-cadir command:

make-cadir ~/openvpn-ca && cd ~/openvpn-ca

Configure the CA Variables

To configure the values our CA will use, we need to edit the vars file within the directory. Open that file now in your text editor:

vim vars

Towards the bottom of the file, find the settings that set field defaults for new certificates. It should look something like this:

. . .

export KEY_CITY="SanFrancisco"
export KEY_ORG="Fort-Funston"
export KEY_EMAIL="[email protected]"
export KEY_OU="MyOrganizationalUnit"

. . .

Edit the values to whatever you'd prefer, but do not leave them blank.

Find the line:
export KEY_NAME="EasyRSA"

Change the name if you want. But remember it for follow steps.

Build the Certificate Authority

Ensure you are in your CA directory, and then source the vars file you just edited:

cd ~/openvpn-ca
source vars

You should see the following if it was sourced correctly:

NOTE: If you run ./clean-all, I will be doing a rm -rf on /home/hdgem/openvpn-ca/keys

Make sure we're operating in a clean environment by typing:


Now, we can build our root CA by typing:


We now have a CA that can be used to create the rest of the files we need.

Create the Server Certificate, Key, and Encryption Files

Note: If you choose a name other than EasyRSA here, you will have to adjust some of the instructions below. For instance, when copying the generated files to the /etc/openvpn directroy, you will have to substitute the correct names. You will also have to modify the /etc/openvpn/EasyRSA.conf file later to point to the correct .crt and .key files.

$ ./build-key-server EasyRSA

Feel free to accept the default values by pressing ENTER. Do not enter a challenge password for this setup. Towards the end, you will have to enter y to two questions to sign and commit the certificate:

You should see the following:

Write out database with 1 new entries
Data Base Updated

Next, we'll generate a few other items. We can generate a strong Diffie-Hellman keys to use during key exchange by typing:


This might take a few minutes to complete.

Afterwards, we can generate an HMAC signature to strengthen the server's TLS integrity verification capabilities:

openvpn --genkey --secret keys/ta.key

Generate a Client Certificate and Key Pair

This can be done on the client machine and then signed by the server/CA for security purposes, we will generate the signed key on the server for the sake of simplicity. You can repeat this process as many times as you'd like. Pass in a unique value to the script for each client.

We will use client1 as the value for our first certificate/key pair for this guide.

cd ~/openvpn-ca
source vars
./build-key client1

If instead, you wish to create a password-protected set of credentials, use the build-key-pass command:

cd ~/openvpn-ca

source vars

./build-key-pass client1

The defaults should be populated, so you can just hit ENTER to continue. Leave the challenge password blank and make sure to enter y for the prompts that ask whether to sign and commit the certificate.

Configure the OpenVPN Service

Copy the files we need to the /etc/openvpn configuration directory.

cd ~/openvpn-ca/keys  &&
sudo cp ca.crt ca.key EasyRSA.crt EasyRSA.key ta.key dh2048.pem /etc/openvpn

Next, we need to copy and unzip a sample OpenVPN configuration file into configuration directory so that we can use it as a basis for our setup:

gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | sudo tee /etc/openvpn/EasyRSA.conf

Now that our files are in place, we can modify the server configuration file:

sudo vim /etc/openvpn/EasyRSA.conf

Basic Configuration
First, find the HMAC section by looking for the tls-auth directive. Remove the ";" to uncomment the tls-auth line. Below this, add the key-direction parameter set to "0":

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

Remove the ";" to uncomment the cipher AES-128-CBC line:

cipher AES-128-CBC

Below this, add an auth line to select the HMAC message digest algorithm. For this, SHA256 is a good choice:

auth SHA256
Finally, find the user and group settings and remove the ";" at the beginning of to uncomment those lines:

user nobody
group nogroup

Push DNS Changes to Redirect All Traffic Through the VPN

The settings above will create the VPN connection between the two machines, but will not force any connections to use the tunnel. If you wish to use the VPN to route all of your traffic, you will likely want to push the DNS settings to the client computers.

Find the redirect-gateway section and remove the semicolon ";" from the beginning of the redirect-gateway line to uncomment it:

push "redirect-gateway def1 bypass-dhcp"

Find the dhcp-option section. Again, remove the ";" from in front of both of the lines to uncomment them (add Google DNS too):

push "dhcp-option DNS"
push "dhcp-option DNS"
push "dhcp-option DNS"
push "dhcp-option DNS"

Adjust the Port and Protocol

port 443
proto tcp

If you selected a different name during the ./build-key-server command earlier, modify the cert and key lines that you see to point to the appropriate .crt and .key files. 

cert EasyRSA.crt
key EasyRSA.key 

Server Networking Configuration

Allow IP Forwarding

First, we need to allow the server to forward traffic. This is fairly essential to the functionality we want our VPN server to provide.

We can adjust this setting by modifying the /etc/sysctl.conf file:

sudo vim /etc/sysctl.conf


To read the file and adjust the values for the current session, type:

sudo sysctl -p

Adjust the UFW Rules to Masquerade Client Connections

Before we open the firewall configuration file to add masquerading, we need to find the public network interface of our machine. To do this, type:

ip route | grep default

Your public interface should follow the word "dev". 
open the /etc/ufw/before.rules file to add the relevant configuration:
sudo vim /etc/ufw/before.rules

This file handles configuration that should be put into place before the conventional UFW rules are loaded. Towards the top of the file, add the highlighted lines below. This will set the default policy for the POSTROUTING chain in the nat table and masquerade any traffic coming from the VPN:

Note: Remember to replace em1 ( and em2 ) in the -A POSTROUTING line below with the interface you found in the above command.
  1 #
  2 # rules.before
  3 #
  4 # Rules that should be run before the ufw command line added rules. Custom
  5 # rules should be added to one of these chains:
  6 #   ufw-before-input
  7 #   ufw-before-output
  8 #   ufw-before-forward
  9 #

# NAT table rules
# Allow traffic from OpenVPN client to em1

 22 # Don't delete these required lines, otherwise there will be errors
 23 *filter

We need to tell UFW to allow forwarded packages by default as well. To do this, we will open the /etc/default/ufw file:

sudo vim /etc/default/ufw

find the DEFAULT_FORWARD_POLICY directive. We will change the value from DROP to ACCEPT:


sudo ufw allow OpenSSH && sudo ufw disable && sudo ufw enable

Start and Enable the OpenVPN Service

Our configuration file for our server is called /etc/openvpn/EasyRSA.conf, so we will add @EasyRSA to end of our unit file when calling it:

sudo systemctl start openvpn@EasyRSA

Double-check that the service has started successfully by typing:

sudo systemctl status openvpn@EasyRSA

You can also check that the OpenVPN tun0 interface is available by typing:

ip addr show tun0

Enable the service so that it starts automatically at boot:

sudo systemctl enable [email protected]

Create Client Configuration Infrastructure

mkdir -p ~/client-configs/files && chmod 700 ~/client-configs/files
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf

vim ~/client-configs/base.conf

. . .
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote server_IP_address 443

Be sure that the protocol matches the value you are using in the server configuration:

proto tcp

uncomment the user and group directives by removing the ";":

 60 # Downgrade privileges after initialization (non-Windows only)
 61 user nobody
 62 group nogroup

Find the directives that set the ca, cert, and key. Comment out these directives since we will be adding the certs and keys within the file itself:
# 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 ca.crt
#cert client.crt
#key client.key

Mirror the cipher and auth settings that we set in the /etc/openvpn/EasyRSA.conf file:
cipher AES-128-CBC
auth SHA256

add the key-direction directive somewhere in the file. This must be set to "1" to work with the server:
key-direction 1

Finally, the following should only enable them for Linux clients that ship with a /etc/openvpn/update-resolv-conf file. This script uses the resolvconf utility to update DNS information for Linux clients.

script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

Configuration Generation Script

Create and open a file called within the ~/client-configs directory:

vim ~/client-configs/

# First argument: Client identifier


cat ${BASE_CONFIG} \
    <(echo -e '<ca>') \
    ${KEY_DIR}/ca.crt \
    <(echo -e '</ca>\n<cert>') \
    ${KEY_DIR}/${1}.crt \
    <(echo -e '</cert>\n<key>') \
    ${KEY_DIR}/${1}.key \
    <(echo -e '</key>\n<tls-auth>') \
    ${KEY_DIR}/ta.key \
    <(echo -e '</tls-auth>') \
    > ${OUTPUT_DIR}/${1}.ovpn

chmod 700 ~/client-configs/

Generate Client Configurations

cd ~/client-configs
./ client1

You should have a client1.ovpn file in our ~/client-configs/files directory:

ls ~/client-configs/files