Objective

Learn how to install and configure Openvpn server on Ubuntu 18.04 Bionic Beaver

Requirements

  • Root permissions

Difficulty

MEDIUM

Conventions

  • # - requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
  • $ - requires given linux commands to be executed as a regular non-privileged user

Introduction

Description here Virtual private network technology makes possible to access safe, private networks by using less secure networks like the internet. VPNs are typically used to connect physically remote branches of an organization, making them appear as if they were part of the same LAN (for example two offices in different cities). The traffic between the sides of the connection is encrypted using tunnels, which protects the transmitted data and the connection information themselves. For the same characteristics, VPNs are often used to circumvent government restrictions and anonymize internet traffic.

In this tutorial we will see how to create a virtual private network server using OpenVPN, the open source VPN software on Ubuntu 18.04 Bionic Beaver.

Step 1 - Installation

Installing OpenVPN on Ubuntu 18.04 is really easy: the software is available in the default repositories. We also need to install the easy-rsa package, which will assist us in the creation of the needed certificates and keys:
$ sudo apt-get update && sudo apt-get install openvpn easy-rsa
Few seconds and the software will be installed in our machine, ready to be configured.

Step 2 - Server infrastructure setup

In this section we will generate the needed certificates and keys: first we will create our custom CA (certificate authority), then we will generate the server certificate/key pair, the Diffie-Hellman parameters and the tls-auth key.

Let's start by generating the directory which will contain the scripts that will do the heavy job for us. We run the make-cadir command, that is part of the easy-rsa package, providing the name of the directory we want to create. We also want to enter the directory as soon as it is created:
$ make-cadir certificates && cd certificates
In this case I called the directory certificates. This will be our working directory for the rest of the tutorial, therefore all mentioned commands must be considered as launched inside it.


Step 2.1 - Variables setup

As a first thing we need to adjust the variables which will be used to set the values used during the generation of the certificate authority and the certificate/key. The variables are defined inside the vars file:
export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA`
export KEY_COUNTRY="US"
export KEY_PROVINCE="CA"
export KEY_CITY="SanFrancisco"
export KEY_ORG="Fort-Funston"
export KEY_EMAIL="me@myhost.mydomain"
export KEY_OU="MyOrganizationalUnit"
A very important variable is KEY_CONFIG, which, by default is set by calling a little wrapper script which should retrieve the right ssl configuration. However, if used this way it generates an error, because the script doesn't retrieve the configuration. To avoid this, we specify the configuration file directly:
export KEY_CONFIG="$EASY_RSA/openssl-1.0.0.cnf"
The values for the other variables must be changed and adapted to your specific needs. After we finished editing the file, we must "source" it, to let the variables become part of our runtime environment:
$ source vars

Step 2.2 - Generation of the CA

We can proceed and generate our CA (certificate authority). Running the clean-all and build-ca scripts in order. The CA generation will begin, using the values of the variables we defined in the vars file as defaults for the corresponding fields:
$ ./clean-all && ./build-ca

Step 2.3 - Certificate and key generation

The next step is the generation of the certificate and key for the server. It's just a matter of running the build-key-server script giving the name we want to use for the certificate and the key as parameter. In this case we use "server" because it is the default name used in the vpn configuration file, as we will see further in the tutorial:
$ ./build-key-server server
Follow the onscreen instructions. The challenge password and company name fields are optional.

Step 2.4 - Diffie-Hellman parameters generation

Next step is to create the Diffie-Hellman parameters. Those parameters are used to exchange cryptographic keys using a public and insecure channel. We use the build-dh script:
$ ./build-dh
The script will take some time to generate the parameters, depending on the machine we are running on, be patient!

Step 2.5 - Generate a random key to be used as a shared secret

To strengthen our security, in addition to use a certificate, we will generate and use a key to use a shared secret. The server and each client will need a copy of this key:
$ openvpn --genkey --secret keys/ta.key

Step 2.6 - Copying the generated files

The certificate authority (ca.crt), certificate (server.crt), key (server.key), Diffie-Hellman parameters (dh2048.pem) and tls-auth key (ta.key) files, should have been generated inside the keys directory. Now it's time to copy them to /etc/openvpn:
$ sudo cp keys/{server.crt,server.key,ca.crt,dh2048.pem,ta.key} /etc/openvpn

Step 3 - OpenVPN configuration

We can proceed in configuring the OpenVPN service. A (compressed) sample configuration can be found at /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz: we just need to extract it into the /etc/openvpn directory:
$ gzip -d -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | sudo tee /etc/openvpn/server.conf > /dev/null
With the above command we decompressed the original file, sending its output to stdout and redirecting it through the /etc/openvpn/server.conf file. Verify that the default values in the configuration file correspond to the ones we generated:
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh2048.pem


Step 4 - Setup the firewall and allow ip forwarding

We almost finished setting up our vpn server: now we must setup the firewall, in order to allow incoming traffic from port 1194/udp (default port and protocol):
$ sudo ufw allow openvpn
Very important: by default only the traffic between the client and the server passes over the VPN tunnel, this excludes internet traffic. To change this behavior, we first have to uncomment the option on line 192 of the server configuration file (/etc/openvpn/server.conf):
push "redirect-gateway def1 bypass-dhcp"
Next, we need to use an iptable rule to NAT the VPN client through the internet. Notice that I specified the eth0 interface but you need to adapt the rule to the interface in use on your machine:
$ sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
Set this way, however, the rule will not persist a reboot. To make it persistent, we must add it to the /etc/ufw/before.rules file. This file contains rules that are applied by ufw before the ones defined from command line. Add the rule as the first one in the file:
*nat
:POSTROUTING ACCEPT [0:0] 
-A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE
COMMIT
Now we must enable packet forwarding. First we need to edit the /etc/sysctl.conf file and uncomment the line 28:
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
At this point we should reload the configuration:
$ sudo sysctl -p /etc/sysctl.conf
We still need to allow packet forwarding through the ufw firewall. Open /etc/default/ufw and change DEFAULT_FORWARD_POLICY from DROP to ACCEPT:
# Set the default forward policy to ACCEPT, DROP or REJECT.  Please note that
# if you change this you will most likely want to adjust your rules
DEFAULT_FORWARD_POLICY="ACCEPT"
Finally, reload the firewall:
$ sudo ufw reload

Step 5 - Start the service

We now will use systemctl to start the server, passing the variable containing the name of our configuration file to the service unit. By using systemd we can do this by prefixing the value with the @ symbol. For example:
$ sudo systemctl start openvpn@server
At this point the server should be up and running. Verify it by running
$ sudo systemctl is-active openvpn@server
The command should return "active".


Step 6 - Client setup

For each client we want to use, we must generate a certificate/key pair, just like we did above for the server:
$ source vars && ./build-key client
Now we have two options: we can either copy the necessary files to our client, or we can generate an .ovpn file, in which the content of those files are embed. We will concentrate on the second option.

Just like we did server-side, we will take a sample configuration as our starting point. Let's create a dedicated directory and copy the template:
$ mkdir clients && cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf clients/client.ovpn
Follow the very well commented sections of the file, and adapt the options to the ones defined in the server configuration (in our case it's already done). Set the server ip and port by modifying the setting (line 42):
remote my-server-1 1194
Where "my-server" must be replaced by the server ip and the port must be changed if not using the default one. Next, uncomment the following lines (61,62):
# Downgrade privileges after initialization (non-Windows only)
;user nobody
;group nogroup
Now, we will substitute references to CA, certificate, key, dh parameters and tls-auth key with the actual content of the files: this way we will create an embed, easily exportable configuration. First comment references (lines 88-90 and 108)
#ca ca.crt
#cert client.crt
#key client.key
#tls-auth ta.key 1
Next, copy the content of the mentioned files, between the appropriate tags. The certificate authority content must be included between <ca></ca> tags, the content of the certificate file inside <cert></cert> and the key between <key></key>. Just as an example, consider the CA:
<ca>
# Here goes the content of the ca.crt file
</ca>
For the tls-auth key, instead we would do:
key-direction 1
<tls-auth>
# The content of the ta.key file
</tls-auth>
Finally, just import the file in your client application and you should be ready to go.

Android connection example

To connect to our openvpn server from android, we will use the official openvpn application: OpenVpn Connect. Once installed and launched the following menu will appear:
Android Openvpn App Menu
Android Openvpn App Menu


Tap on, the last item, OVPN Profile From the file picker, navigate to the place where you stored the .ovpn file, and select it, than tap on "import" in the upper right corner. The profile should have been imported correctly:
Android Openvpn App Import
Android Openvpn App Import
Now, same as before, tap on add, and on the following screen activate the connection:
Android Openvpn App Connected
Android Openvpn App Connected
Success!
Please refer all article related questions to:

You may also be interested in: