A Virtual Private Network (VPN) allows you to securely and privately connect to a remote private network, for example, your office network, or the Internet in such a way as if you are directly connected to a private network.

VPN works in a server-client architecture. A VPN server is deployed on a machine and is publicly accessible over the Internet. The VPN server can be configured to allow connecting to a private LAN, such as an office network, or allow connections to the Internet. The user connects to the VPN server using a VPN client on his local machine. Communication between VPN server and client takes place using a secure tunnelling protocol. To the Internet, it seems as if the destination of the traffic is the VPN server; however, the traffic passes to the client via the server.

VPN has many uses in daily life, like securely connecting to a public Wifi network, which is often compromised or bypassing geo-restrictions on certain websites by connecting to a VPN based in a country which is allowed by the website.

OpenVPN is a widely used VPN implementation that allows a wide range of configurations and options. It uses Secure Sockets Layer (SSL) protocol for the encryption of the data and pre-shared keys, username/password or certificates for authentication of the VPN client. In this article, we will see how to set up a VPN server and VPN client on Ubuntu 20.04.

Installation

OpenVPN is available in the official Ubuntu repositories in the package openvpn. This package installs both OpenVPN server as well as the client.

sudo apt install openvpn

As mentioned earlier, OpenVPN uses SSL certificates to encrypt data between the server and the client. We need to set up our own certificate authority (CA) to issue certificates for the VPN. Note that this should be set up on a different machine than the one where OpenVPN is set up; the reason is that if it is on the same server and if it gets compromised, an attacker can access the private key and thus attack the VPN connection.

We will use a tool called ‘Easy-RSA’ to set up the certificate authority. To install it, run the following on the CA machine, the OpenVPN server machine and the client machine, as the configuration is required on all three of these to setup the CA.

sudo apt install easy-rsa

We will now first configure the certificate authority on the CA machine and perform some required configuration steps for the same on the Open VPN server machine.


Certificate Authority Setup

Initial setup on CA machine

Now, this package installs a command called make-cadir which is used to create a folder for certificate authority configuration. Let’s create a folder using this and enter the folder.

make-cadir cert_authority && cd cert_authority

Open the file called vars created in this directory. This file contains some configuration variables which we need to modify. The values which need to be modified are on lines 91-96, after the comment about Organizational Fields which describes these fields. Uncomment the lines and fill the appropriate values in place of the sample values.

Save and exit the file. If you are using vim editor, press Esc, type :wq and press Enter to save and exit.

Next, we run the easyrsa program in the directory to set up the public key infrastructure (PKI), which will be used to generate public key and certificates.

./easyrsa init-pki

The next step will generate the CA key and certificate. When the command prompts for a password, enter a password for the CA key. Also, enter a common name when prompted. If you leave this blank, the default name Easy-RSA CA name will be used.

./easyrsa build-ca

As we can see from the output the certificate and key have been generated. This key will be used to sign the client and server certificates, hence it should never be touched/modified.

Now, we have the PKI setup. Next step is to create a server key and certificate on the machine which we will use as an OpenVPN server. This certificate will later be signed by the CA machine.

Generating Server Key and Certificate on the Server machine

We have already installed Easy RSA on the server machine. Now perform the three steps on the server machine, which we previously performed on the CA machine, viz. creating a CA directory using make-cadir and going inside it, modifying the variables in the vars file and generating PKI using ./easyrsa init-pki command.

Next, we need to run the command to generate a server certificate request and key.

./easyrsa gen-req server nopass

Note that we passed the option nopass so that the command will not prompt us to enter a password for the server key. It will still prompt for a common name for the server, which you can enter anything, or leave it empty for the default name (server) to be used.

Move the generated key file inside the /etc/openvpn directory.

sudo mv pki/private/server.key /etc/openvpn

Send the certificate request to the CA machine. We will use command scp for this purpose.

scp pki/reqs/server.req user@CA_MACHINE_HOSTNAME:/directory

In the screenshot above, the host 45.79.125.41 is the CA machine. We have copied the certificate in the /root directory.

Now, the certificate of the server has been copied to the CA machine. Next step is to go back to the CA machine and sign this certificate.

Signing the server certificate in the CA

First, let’s verify if the certificate request file from the server has been copied on the CA machine. Go to the directory where we copied the file (/root in my example) and run ls.

:~# cd /root && ls
cert_authority  server.req

As we can see, the file server.req is present. Next, go to the CA directory and import this request.

cd cert_authority
./easyrsa import-req /root/server.req server

To sign this request, run the following command.

./easyrsa sign-req server server

Here the first argument is the type of request, i.e., server, and the second argument is the common name of the server machine, for which we previously used the default value, i.e., server.

Enter the phrase yes, and the password for the CA key when prompted.

Now we can remove the certificate request file and copy the generated certificate for the server, as well as CA public certificate back to the server machine.

rm /root/server.req
scp pki/issued/server.crt root@172.105.61.175:/root
scp pki/ca.crt root@172.105.61.175:/root

Next, we have to perform few more steps to ensure secure connection of the VPN.

DH Parameters Generation

DH (Diffie-Hellman) key exchange is an algorithm to ensure a secure exchange of crypto keys over an insecure channel. First, let’s move the received certificate and CA public certificate to /etc/openvpn.

mv /root/ca.crt /root/server.crt /etc/openvpn

Go to the CA folder on the server machine and run the following command to generate the DH parameters. It might take a long time to generate.

./easyrsa gen-dh

Now, move the generated file to /etc/openvpn.

mv /root/cert_authority/pki/dh.pem /etc/openvpn

Generating TA keys

OpenVPN uses another additional security measure using TLS auth key. To generate the TLS auth key, run:

openvpn --genkey --secret tls_auth.key

And move the key to /etc/openvpn.

mv tls_auth.key /etc/openvpn

The server key configuration and certificate authority setup is now done. Let us move to the actual configuration of the VPN server now.


OpenVPN Server Configuration

Configuration file for OpenVPN server is not automatically created, however we can use a template configuration file from the openvpn package.

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

Open the file using vim or any editor of your choice.

cd /etc/openvpn
vim server.conf

We have to enter the common names of keys and certificates that we generated previously. Go to line no. 78. Since we used all the default names, we keep them unchanged. Then check the name for DH parameter file on line 85. We have used the name dh.pem, so let’s change it.

Next, let’s modify the privileges for OpenVPN server. Go to line 274 and 275 and remove the leading ; to uncomment it.

Similarly go to line 192 and remove the semicolon. This directive enables traffic of all the clients to pass through the VPN.

Save and exit the file.

Change the ownership of the folder /etc/openvpn to root.

sudo chown -R root:root /etc/openvpn

Networking and Firewall setup

We need to allow IP forwarding on the server in order to allow packets to be forwarded from and to the VPN client. Uncomment line 28 on /etc/sysctl.conf:

Save and exit the file.

Restart systemctl for these changes to take place.

sudo sysctl -p

We need to set up Network Address Translation (NAT) on the server using a UFW firewall so as to allow the VPN Client access the Internet using the VPN server’s IP Address. First, let’s enable packet forwarding in the firewall configuration. Open /etc/default/ufw and change the variable on line 19 to ACCEPT.

Save and exit the file.

Now add the following rules to the file /etc/ufw/before.rules before the filter line in the file.

*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/8 -o <interface> -j MASQUERADE
COMMIT

Enter your network interface in place of <interface>. You can see your network interface with the command ifconfig.

Allow traffic for OpenVPN service on the Firewall and allow port 1194.

sudo ufw allow openvpn && sudo ufw allow 1194

Reload the firewall service.

sudo ufw reload

We can now restart the Open VPN server daemon by running:

sudo service openvpn restart

Enable it to start at boot time by running:

sudo systemctl enable openvpn

The OpenVPN server has now been configured and has started. Let’s now proceed to client certificate request and key generation and other configuration.


OpenVPN Client Configuration

We need to generate a key and a certificate request for the client. The procedure to do this is the same as that for the server.

Although a client key and certificate request can be created on the client machine and then transferred to the CA machine, it is recommended to create it on the server machine. The advantage of doing this on the server is that you can create a script for performing all the required steps on the server which makes it easier for a new client to join the VPN.

Go to the CA folder on the server and run the following:

cd ~/cert_authority
./easyrsa gen-req client nopass

In a similar way as done previously, enter a common name when prompted, or leave it empty to use the default common name, i.e., client.

Let’s now copy the generated client certificate request to the CA machine.

scp pki/reqs/client.req root@45.79.125.41:/root

Let’s import this request in the CA machine:

./easyrsa import-req /root/client.req client

And let’s now sign it:

./easyrsa sign-req client client

Enter yes when prompted to continue. Enter the password for CA key when asked.

We can now remove the requested file for client and copy the request back to the VPN server machine.

rm /root/client.req
scp pki/issued/client.crt  root@172.105.61.175:/root

Let’s create a folder called client to keep all files related to the client on the VPN server. We will move the client key and the certificate to this folder.

mkdir ~/client
sudo mv ~/client.crt ~/cert_authority/pki/private/client.key ~/client

Now, let’s create a configuration file from an available template, similar to how we created the server configuration file.

cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client

Open the file client.conf. On line 42, enter hostname or IP Address of your server machine in place of my-server-1.

Uncomment lines 61 and 62 by removing the leading semicolon, to downgrade privileges for the file.

Next, comment out lines 88-90 and line 108. The reason is that we want to add the contents of the mentioned files manually instead of using the file locations. The purpose of doing this is that the client configuration file will later be transferred to the client, where we actually won’t have the client key and certificate files; hence we copy contents of those in the configuration file itself.

Append the following to the client configuration file. Enter the file contents of the respective files inside the given tags.

<ca>
# Paste content of ca.crt file here
</ca>

<cert>
# Paste content of client.crt file here
</cert>

<key>
# Paste content of client.key file here
</key>

key-direction 1
<tls-auth>
# Paste content of tls_auth.key file here
</tls-auth>

Save and exit the file. Rename this file from client.conf to client.ovpn, as the latter one is the extension required for configuration files which can be imported as network configurations.

Now, transfer the file client.ovpn to the client, i.e., local machine.

Run scp on your client machine to transfer file from server machine to your local machine.

scp user@server_ip:/path_to_file local_destination_path

Finally, we need to use this configuration file to connect to the VPN server. This can be done both via command line as well as GUI.

To start the VPN client from command line, run:

sudo openvpn --config client.ovpn

And that is the only command you need to run to start the VPN Client.

To start the VPN client via GUI, perform the following steps.

Go to Settings » Network on your client machine.

Click on the + button in the VPN section and choose ‘Import from file…’ from the options.

Click on ‘Add’ to start using the VPN.

Note that under ‘Gateway’, it is the IP Address of the server.

Finally, toggle the ‘client VPN’ button to enable VPN on the machine.

It might take a few seconds to establish a VPN connection. A new progress logo for VPN will appear at the top left corner of your screen while it is being set up, and it will change to a VPN logo once it is set up.

To verify if the VPN is working correctly, run the following:

curl https://ipinfo.io/ip

It should return the IP address of your server machine. Or else you can also check your IP address by simply searching ‘My IP’ on Google. It should show your VPN server’s IP address if our VPN setup is working properly.


Conclusion

In this article, we saw how to configure an OpenVPN server, a Certificate Authority and an OpenVPN Client. To add more clients to the VPN, we now need to follow the procedure to generate and sign a certificate for the client and use the same configuration file created here, with only the client key and certificate values changed.

In the case of slower internet connections, it is possible that if UDP is being used for communication, there is considerable packet loss. User can switch to TCP by uncommenting the line proto tcp and commenting on the line proto udp in the server configuration file.

Also, in case there are other errors, you can set logging level with the verb directive in both server and client configuration files. You can enter values between 0 and 9. Higher the value of this directive, more verbose will be the log.