Take care of your privacy and create your own virtual private network
By: Zaid Alissa Almaliki
Tags: Data Science, Security

Do you like to access the Internet safely and securely from your smartphone or laptop when connected to an untrusted network such as the WiFi of a hotel, coffee shop or a Library? A Virtual Private Network (VPN) allows you to traverse untrusted networks privately and securely as if you were on a private network. The traffic emerges from the VPN server and continues its journey to the destination.

OpenVPN is a full-featured, open-source Secure Socket Layer (SSL) VPN solution that accommodates a wide range of configurations. In this tutorial of two parts, we will set up an OpenVPN server on an Ubuntu server using digital ocean then configure access to it from Android. This tutorial will keep the installation and configuration steps as simple as possible for each of these setups.Let’s start with the first part which includes the first five steps of installation and configuration.

Step One: Installing OpenVPN and EasyRSA

This step for both machines the VPN server and the CA machine. We start off, updating our package index and install OpenVPN. OpenVPN is available in Ubuntu’s default repositories, so we can use apt for the installation

$ sudo apt update

$ sudo apt install openvpn

OpenVPN is a TLS/SSL VPN. This means that it uses certificates in order to encrypt traffic between the server and clients. To issue trusted certificates, we will set up our simple certificate authority (CA). To do this, we will download the latest version of EasyRSA, which we will deploy to build our CA public key infrastructure (PKI), from the project’s official GitHub repository.

We will build the CA on a standalone server. The reason for this approach is that, if an attacker were able to infiltrate our server, they would be able to access our CA private key and use it to sign new certificates, giving them access to our VPN. Accordingly, managing the CA from a standalone machine helps to prevent unauthorized users from accessing our VPN. Note, as well, that it’s recommended that we keep the CA server turned off when not being used to sign keys as a further precautionary measure.

To begin building the CA and PKI infrastructure, we use wget to download the latest version of EasyRSA on both our CA machine and our OpenVPN server. To get the latest version, go to the Releases page on the official EasyRSA GitHub project, copy the download link for the file ending in .tgz , and then paste it into the following command:

Then extract the tarball:

$ cd ~

$ tar xvf EasyRSA-3.0.4.tgz

We have successfully installed all the required software on our server and CA machine. Continue on to configure the variables used by EasyRSA and to set up a CA directory, from which we will generate the keys and certificates needed for our server and clients to access the VPN.

Step Two: Configuring the EasyRSA variables and building the CA certificates

We will follow these instructions only on the CA machine. EasyRSA comes installed with a configuration file which we can edit to define a number of variables for our CA. On our CA machine, navigate to the EasyRSA directory:

$ cd ~/Documents/EasyRSA-3.0.4/

Inside this directory is a file named vars.example . We make a copy of this file, and name the copy vars without a file extension:

$ cp vars.example vars

We open this new file using our preferred text editor which vim we can use another one for example nano editor:

$ vim vars

Find the settings that set field defaults for new certificates. It will look something like this:~/Documents/EasyRSA-3.0.4/vars

. . . #set_var EASYRSA_REQ_COUNTRY "US"

#set_var EASYRSA_REQ_PROVINCE "California"

#set_var EASYRSA_REQ_CITY "San Francisco"

#set_var EASYRSA_REQ_ORG "Copyleft Certificate Co"

#set_var EASYRSA_REQ_EMAIL "me@example.net"

#set_var EASYRSA_REQ_OU "My Organizational Unit" . . .

Uncomment these lines and update the highlighted values to whatever we’d prefer, but we do not leave them blank:~/Documents/EasyRSA-3.0.4/vars

. . . set_var EASYRSA_REQ_COUNTRY "US"

set_var EASYRSA_REQ_PROVINCE "NewYork"

set_var EASYRSA_REQ_CITY "New York City"

set_var EASYRSA_REQ_ORG "DigitalOcean"

set_var EASYRSA_REQ_EMAIL "admin@example.com"

set_var EASYRSA_REQ_OU "Community" . . .

When we are finished, save and close the file. Within the EasyRSA directory is a script called easyrsa which is called to perform a variety of tasks involved with building and managing the CA. We run this script with the init-pki option to initiate the public key infrastructure on the CA server:

$ ./easyrsa init-pki

After this point, we call the easyrsa script again, following it with the build-ca option. This will build the CA and create two important files ca.crt and ca.key which make up the public and private sides of an SSL certificate.

ca.crt is the CA’s public certificate file which, in the context of OpenVPN, the server and the client use to inform one another that they are part of the same web of trust and not someone performing a man-in-the-middle attack. For this reason, our server and all of our clients will need a copy of the ca.crt file.

is the CA’s public certificate file which, in the context of OpenVPN, the server and the client use to inform one another that they are part of the same web of trust and not someone performing a man-in-the-middle attack. For this reason, our server and all of our clients will need a copy of the file. ca.key is the private key which the CA machine uses to sign keys and certificates for servers and clients. If an attacker gains access to our CA and, in turn, our file, they will be able to sign certificate requests and gain access to our VPN, impeding its security. This is why our file should only be on our CA machine and that, ideally, our CA machine should be kept offline when not signing certificate requests as an extra security measure.

If we don’t want to be prompted for a password every time we interact with our CA, we can run the build-ca command with the nopass option, like this:

$ ./easyrsa build-ca nopass

In the output, we’ll be asked to confirm the common name for our CA:

The common name is the name used to refer to this machine in the context of the certificate authority. We can enter any string of characters for the CA’s common name but, for simplicity’s sake, press ENTER to accept the default name. With that, our CA is in place and it’s ready to start signing certificate requests.

Step Three: Creating the server certificate, key, and encryption files

We will follow these instructions only on the server machine. Now that we have a CA ready to go, we can generate a private key and certificate request from our server and then transfer the request over to our CA to be signed, creating the required certificate. we’re also free to create some additional files used during the encryption process. Start by navigating to the EasyRSA directory on our OpenVPN server:

$ cd ~/Documents/EasyRSA-3.0.4/

From there, run the easyrsa script with the init-pki option. Although we already ran this command on the CA machine, it’s necessary to run it here because our server and CA will have separate PKI directories:

$ ./easyrsa init-pki

Then call the easyrsa script again, this time with the gen-req option followed by a common name for the machine. Again, this could be anything we like but it can be helpful to make it something descriptive. Throughout this tutorial, the OpenVPN server’s common name will simply be server. Be sure to include the nopass option as well. Failing to do so will password-protect the request file which could lead to permissions issues later on:

$ ./easyrsa gen-req server nopass

This will create a private key for the server and a certificate request file called server.req . Copy the server key to the /etc/openvpn/ directory:

$ sudo cp ~/Documents/EasyRSA-3.0.4/pki/private/server.key /etc/openvpn/

We will follow these instructions only on the CA machine. Using a secure method (like SCP, in our example below), transfer the server.req file to our CA machine:

$ scp -i ~/.ssh/id_rsa_do zaid@my_server_ip:~/Documents/EasyRSA-3.0.4/pki/reqs/server.req .

Next, on our CA machine, navigate to the EasyRSA directory:

$ cd ~/Documents/EasyRSA-3.0.4/

Using the easyrsa script again, import the server.req file, following the file path with its common name:

$ ./easyrsa import-req /tmp/server.req server

Then we sign the request by running the easyrsa script with the sign-req option, followed by the request type and the common name. The request type can either be client or server , so for the OpenVPN server’s certificate request, be sure to use the server request type:

$ ./easyrsa sign-req server server

In the output, we’ll be asked to verify that the request comes from a trusted source. Type yes then press ENTER to confirm this:

If we encrypted our CA key, we’ll be prompted for our password at this point. Next, transfer the signed certificate back to our VPN server using a secure method:

$ scp -i ~/.ssh/id_rsa_do pki/issued/server.crt zaid@my_server_ip:/tmp

Before logging out of our CA machine, we transfer the ca.crt file to our server as well:

$ scp -i ~/.ssh/id_rsa_do pki/ca.crt zaid@my_server_ip:/tmp

We will follow these instructions only on the server machine. Next, log back into our OpenVPN server and copy the server.crt and ca.crt files into our /etc/openvpn/ directory:

$ sudo cp /tmp/{server.crt,ca.crt} /etc/openvpn/

Then navigate to our EasyRSA directory:

$ cd ~/Documents/EasyRSA-3.0.4/

From there, create a strong Diffie-Hellman key to use during key exchange by typing:

$ ./easyrsa gen-dh

This may take a few minutes to complete, so if you are here my dear reader you can take a cup of tea and enjoy yourself. Once it does, generate an HMAC signature to strengthen the server’s TLS integrity verification capabilities:

$ openvpn --genkey --secret ta.key

When the command finishes, we copy the two new files to our /etc/openvpn/ directory:

$ sudo cp ~/Documents/EasyRSA-3.0.4/ta.key /etc/openvpn/

$ sudo cp ~/Documents/EasyRSA-3.0.4/pki/dh.pem /etc/openvpn/

With that, all the certificate and key files needed by our server have been generated. We are ready to create the corresponding certificates and keys which our client machine will use to access our OpenVPN server.

Step Four: Generating a client certificate and key files

We will follow these instructions only on the server machine. Although we can generate a private key and certificate request on our client machine and then send it to the CA to be signed, this guide outlines a process for generating the certificate request on the server.

The benefit of this is that we can create a script which will automatically generate client configuration files that contain all of the required keys and certificates. This let us avoid having to transfer keys, certificates, and configuration files to clients and streamlines the process of joining the VPN. best practices

We will generate a single client key and certificate pair for this guide. If we have more than one client, we can repeat this process for each one. Please note, though, that we will need to pass a unique name value to the script for every client. Throughout this tutorial, the first certificate/key pair is referred to as client1 .

Get started by creating a directory structure within our home directory to store the client certificate and key files:

$ mkdir -p ~/client-configs/keys

Since we will store our clients’ certificate/key pairs and configuration files in this directory, we should lock down its permissions now as a security measure:

$ chmod -R 700 ~/client-configs

Next, navigate back to our EasyRSA directory and run the easyrsa script with the gen-req and nopass options, along with the common name for the client:

$ cd ~/Documents/EasyRSA-3.0.4/

$ ./easyrsa gen-req client1 nopass

Press ENTER to confirm the common name. Then, copy the client1.key file to the /client-configs/keys/ directory we created earlier:

$ cp pki/private/client1.key ~/client-configs/keys/

Next, transfer the client1.req file to our CA machine using a secure method. We will follow these instructions only on the CA machine.

$ sudo scp -i ~/.ssh/id_rsa_do zaid@my_server_ip:~/Documents/EasyRSA-3.0.4/pki/reqs/client1.req .

We navigate to the EasyRSA directory, and import the certificate request:

$ cd ~/Documents/EasyRSA-3.0.4/

$ sudo ./easyrsa import-req /tmp/client1.req client1

Then sign the request as we did for the server in the previous step. This time, though, be sure to specify the client request type:

$ cd pki/reqs

$ sudo chown zeyd:zeyd client1.req

$ ./easyrsa sign-req client client1

At the prompt, enter yes to confirm that we intend to sign the certificate request and that it came from a trusted source. Again, if we encrypted our CA key, we’ll be prompted for our password here. This will create a client certificate file named client1.crt . Transfer this file back to the server:

$ scp -i ~/.ssh/id_rsa_do pki/issued/client1.crt zaid@my_server_ip:~/client-configs/keys/

We will follow these instructions only on the server machine. Next, we copy the ca.crt and ta.key files to the /client-configs/keys/ directory as well:

$ cp ~/Documents/EasyRSA-3.0.4/ta.key ~/client-configs/keys/

$ sudo cp /etc/openvpn/ca.crt ~/client-configs/keys/

With that, our server and client’s certificates and keys have all been generated and are stored in the appropriate directories on our server. There are still a few actions that need to be performed with these files, but those will come in a later step. For now, we can move on to configuring OpenVPN on our server.

Step Five: Configuring the OpenVPN service

We will follow these instructions only on the server machine. Now that both our client and server’s certificates and keys have been generated, we can begin configuring the OpenVPN service to use these credentials. Start by copying a sample OpenVPN configuration file into the configuration directory and then extract it in order to use it as a basis for our setup:

$ 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 server configuration file in our preferred text editor:

$ sudo vim /etc/openvpn/server.conf

Find the HMAC section by looking for the tls-auth directive. This line should already be uncommented, but if isn’t then remove the ";" to uncomment it. Below this line, add the key-direction parameter, set to "0":/etc/openvpn/server.conf

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

key-direction 0

Next, find the section on cryptographic ciphers by looking for the commented out cipher lines. The AES-256-CBC cipher offers a good level of encryption and is well supported. Again, this line should already be uncommented, but if it isn’t then just remove the ";" preceding it:/etc/openvpn/server.conf

cipher AES-256-CBC

Below this, add an auth directive to select the HMAC message digest algorithm. For this, SHA256 is a good choice:/etc/openvpn/server.conf

auth SHA256

Next, find the line containing a dh directive which defines the Diffie-Hellman parameters. Because of some recent changes made to EasyRSA, the filename for the Diffie-Hellman key may be different than what is listed in the example server configuration file. If necessary, change the file name listed here by removing the 2048 so it aligns with the key we generated in the previous step:/etc/openvpn/server.conf

dh dh.pem

Finally, find the user and group settings and remove the ";" at the beginning of each to uncomment these lines:/etc/openvpn/server.conf

user nobody

group nogroup

The changes we’ve made to the sample server.conf file up to this point are necessary in order for OpenVPN to function. The changes outlined below are optional, though they too are needed for many common use cases.

Check our free course on Udemy.

Thanks for reading. If you loved this article, feel free to hit that follow button so we can stay in touch.

Note from Towards Data Science’s editors: While we allow independent authors to publish articles in accordance with our rules and guidelines, we do not endorse each author’s contribution. You should not rely on an author’s works without seeking professional advice. See our Reader Terms for details.