【OpenVPN】Ubuntu Setup OpenVPN Server

Posted by 西维蜀黍 on 2021-07-05, Last Modified on 2022-03-10

Server Installation

To install openvpn in a terminal enter:

$ sudo apt install openvpn easy-rsa

Public Key Infrastructure Setup

The first step in building an OpenVPN configuration is to establish a PKI (public key infrastructure). The PKI consists of:

  • a separate certificate (also known as a public key) and private key for the server and each client.
  • a master Certificate Authority (CA) certificate and key, used to sign the server and client certificates.

OpenVPN supports bidirectional authentication based on certificates, meaning that the client must authenticate the server certificate and the server must authenticate the client certificate before mutual trust is established.

Both server and client will authenticate the other by first verifying that the presented certificate was signed by the master certificate authority (CA), and then by testing information in the now-authenticated certificate header, such as the certificate common name or certificate type (client or server).

To begin building the CA and PKI infrastructure, use wget to download the latest version of EasyRSA on both your CA machine and your OpenVPN server.

easy-rsa is a CLI utility to build and manage a PKI CA. In laymen’s terms, this means to create a root certificate authority, and request and sign certificates, including intermediate CAs and certificate revocation lists (CRL).

https://github.com/OpenVPN/easy-rsa

Certificate Authority (CA) Setup

Copy

$ sudo make-cadir /etc/openvpn/easy-rsa
$ cd /etc/openvpn
$ sudo chmod -R 777 easy-rsa
$ cd easy-rsa

Modify Personal Info/

$ vim vars

Find the settings that set field defaults for new certificates. It will look something like this:

. . .

#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 you’d prefer, but do not leave them blank:

. . .

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"

. . .

When you are finished, save and close the file.

Initiate Public Key

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. Run this script with the init-pki option to initiate the public key infrastructure on the CA server:

$ ./easyrsa init-pki

Note: using Easy-RSA configuration from: ./vars


WARNING!!!

You are about to remove the EASYRSA_PKI at: /etc/openvpn/easy-rsa/pki
and initialize a fresh PKI here.

Type the word 'yes' to continue, or any other input to abort.
  Confirm removal: yes

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /etc/openvpn/easy-rsa/pki

Create the CA’s Public and Private Certificate

After this, 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, your server and all of your clients will need a copy of the ca.crt 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 your CA and, in turn, your ca.key file, they will be able to sign certificate requests and gain access to your VPN, impeding its security. This is why your ca.key file should only be on your CA machine and that, ideally, your CA machine should be kept offline when not signing certificate requests as an extra security measure.
$ ./easyrsa build-ca

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

$ ./easyrsa build-ca nopass

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
Generating RSA private key, 2048 bit long modulus (2 primes)
...........+++++
...........................................................................................................+++++
e is 65537 (0x010001)
Can't load /etc/openvpn/easy-rsa/pki/.rnd into RNG
140470052455744:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:98:Filename=/etc/openvpn/easy-rsa/pki/.rnd
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/etc/openvpn/easy-rsa/pki/ca.crt

In the output, you’ll be asked to confirm the common name for your CA:

Output. . .
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:

The common name is the name used to refer to this machine in the context of the certificate authority. You 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, your CA is in place and it’s ready to start signing certificate requests.

Creating the Server Certificate, Key, and Encryption Files

Now that you have a CA ready to go, you can generate a private key and certificate request from your server and then transfer the request over to your CA to be signed, creating the required certificate. You’re also free to create some additional files used during the encryption process.

$ ./easyrsa gen-req server nopass

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
Generating a RSA private key
.........................+++++
...................................+++++
writing new private key to '/etc/openvpn/easy-rsa/pki/private/server.key.zz4jRGJkAA'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [server]:

Keypair and certificate request completed. Your files are:
req: /etc/openvpn/easy-rsa/pki/reqs/server.req
key: /etc/openvpn/easy-rsa/pki/private/server.key

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:

$ cd /etc/openvpn
$ sudo cp easy-rsa/pki/private/server.key .
$ ./easyrsa sign-req server server

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020


You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a server certificate for 1080 days:

subject=
    commonName                = server


Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: yes
Using configuration from /etc/openvpn/easy-rsa/pki/safessl-easyrsa.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Jun 20 14:55:07 2024 GMT (1080 days)

Write out database with 1 new entries
Data Base Updated

Certificate created at: /etc/openvpn/easy-rsa/pki/issued/server.crt
$ cd /etc/openvpn
$ sudo cp easy-rsa/pki/ca.crt .
$ sudo cp easy-rsa/pki/issued/server.crt .

Create a strong Diffie-Hellman key to use during key exchange by typing:

$ /etc/openvpn/easy-rsa
$ ./easyrsa gen-dh

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
..........................+..........................................+...............................................................+....................................................+...............................................................................................................+...................................................................................................................................................................................................................+...................................................................................+............................................................+..........................................................................................................................................+.......+.......................................................................................................................................................................................................+............+.................+................................................................................++*++*++*++*

DH parameters of size 2048 created at /etc/openvpn/easy-rsa/pki/dh.pem

This may take a few minutes to complete. Once it does, generate an HMAC signature to strengthen the server’s TLS integrity verification capabilities:

$ /etc/openvpn/easy-rsa
$ openvpn --genkey --secret ta.key
$ sudo cp ta.key /etc/openvpn
$ sudo cp pki/dh.pem /etc/openvpn

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

Generating a Client Certificate and Key Pair

Throughout this tutorial, the first certificate/key pair is referred to as client1.

$ cd /etc/openvpn/easy-rsa
$ ./easyrsa gen-req client1 nopass

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
Generating a RSA private key
........................+++++
.................................................................................+++++
writing new private key to '/etc/openvpn/easy-rsa/pki/private/client1.key.v93vAcKvH8'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [client1]:

Keypair and certificate request completed. Your files are:
req: /etc/openvpn/easy-rsa/pki/reqs/client1.req
key: /etc/openvpn/easy-rsa/pki/private/client1.key

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

$ ./easyrsa sign-req client client1

Note: using Easy-RSA configuration from: ./vars

Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020


You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a client certificate for 1080 days:

subject=
    commonName                = client1


Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: yes
Using configuration from /etc/openvpn/easy-rsa/pki/safessl-easyrsa.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'client1'
Certificate is to be certified until Jun 20 15:08:29 2024 GMT (1080 days)

Write out database with 1 new entries
Data Base Updated

Certificate created at: /etc/openvpn/easy-rsa/pki/issued/client1.crt

Simple Server Configuration

$ 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 your preferred text editor:

$ sudo vim /etc/openvpn/server.conf

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

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 you 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:

user nobody
group nogroup

The changes you’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.

Adjusting the Server Networking Configuration

here are some aspects of the server’s networking configuration that need to be tweaked so that OpenVPN can correctly route traffic through the VPN. The first of these is IP forwarding, a method for determining where IP traffic should be routed. This is essential to the VPN functionality that your server will provide.

Adjust your server’s default IP forwarding setting by modifying the /etc/sysctl.conf file:

$ sudo vim /etc/sysctl.conf

Inside, look for the commented line that sets net.ipv4.ip_forward. Remove the “#” character from the beginning of the line to uncomment this setting:

net.ipv4.ip_forward=1

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

$ sudo sysctl -p
Outputnet.ipv4.ip_forward = 1

Regardless of whether you use the firewall to block unwanted traffic (which you almost always should do), for this guide you need a firewall to manipulate some of the traffic coming into the server. Some of the firewall rules must be modified to enable masquerading, an iptables concept that provides on-the-fly dynamic network address translation (NAT) to correctly route client connections.

Before opening the firewall configuration file to add the masquerading rules, you must first find the public network interface of your machine. To do this, type:

ip route | grep default

Your public interface is the string found within this command’s output that follows the word “dev”. For example, this result shows the interface named enp0s4, which is highlighted below:

default via 203.0.113.1 dev enp0s4 proto static

When you have the interface associated with your default route, open the /etc/ufw/before.rules file to add the relevant configuration:

$ sudo vim /etc/ufw/before.rules

UFW rules are typically added using the ufw command. Rules listed in the before.rules file, though, are read and 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. Remember to replace enp0s4 in the -A POSTROUTING line below with the interface you found in the above command:

Next, you need to tell UFW to allow forwarded packets by default as well. To do this, open the /etc/default/ufw file:

$ sudo vim /etc/default/ufw

Inside, find the DEFAULT_FORWARD_POLICY directive and change the value from DROP to ACCEPT:

DEFAULT_FORWARD_POLICY="ACCEPT"

Next, adjust the firewall itself to allow traffic to OpenVPN. If you did not change the port and protocol in the /etc/openvpn/server.conf file, you will need to open up UDP traffic to port 1194. If you modified the port and/or protocol, substitute the values you selected here.

In case you forgot to add the SSH port when following the prerequisite tutorial, add it here as well:

sudo ufw allow 1194/udp
sudo ufw allow OpenSSH

After adding those rules, disable and re-enable UFW to restart it and load the changes from all of the files you’ve modified:

sudo ufw disable
sudo ufw enable

Your server is now configured to correctly handle OpenVPN traffic.

Starting and Enabling the OpenVPN Service

You’re finally ready to start the OpenVPN service on your server. This is done using the systemd utility systemctl.

Start the OpenVPN server by specifying your configuration file name as an instance variable after the systemd unit file name. The configuration file for your server is called /etc/openvpn/server.conf, so add @server to end of your unit file when calling it:

$ sudo systemctl start openvpn@server

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

$ sudo systemctl status openvpn@server

If everything went well, your output will look something like this:

Output● openvpn@server.service - OpenVPN connection to server
   Loaded: loaded (/lib/systemd/system/openvpn@.service; disabled; vendor preset: enabled)
   Active: active (running) since Tue 2016-05-03 15:30:05 EDT; 47s ago
     Docs: man:openvpn(8)
           https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage
           https://community.openvpn.net/openvpn/wiki/HOWTO
  Process: 5852 ExecStart=/usr/sbin/openvpn --daemon ovpn-%i --status /run/openvpn/%i.status 10 --cd /etc/openvpn --script-security 2 --config /etc/openvpn/%i.conf --writepid /run/openvpn/%i.pid (code=exited, sta
 Main PID: 5856 (openvpn)
    Tasks: 1 (limit: 512)
   CGroup: /system.slice/system-openvpn.slice/openvpn@server.service
           └─5856 /usr/sbin/openvpn --daemon ovpn-server --status /run/openvpn/server.status 10 --cd /etc/openvpn --script-security 2 --config /etc/openvpn/server.conf --writepid /run/openvpn/server.pid

If fail, like

● openvpn@server.service - OpenVPN connection to server
     Loaded: loaded (/lib/systemd/system/openvpn@.service; disabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Tue 2021-07-06 15:28:14 UTC; 1s ago
       Docs: man:openvpn(8)
             https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
             https://community.openvpn.net/openvpn/wiki/HOWTO
    Process: 15675 ExecStart=/usr/sbin/openvpn --daemon ovpn-server --status /run/openvpn/server.sta>
   Main PID: 15675 (code=exited, status=1/FAILURE)

check /var/log/syslog.


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

$ ip addr show tun0

This will output a configured interface:

Output4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 100
    link/none 
    inet 10.8.0.1 peer 10.8.0.2/32 scope global tun0
       valid_lft forever preferred_lft forever

After starting the service, enable it so that it starts automatically at boot:

$ sudo systemctl enable openvpn@server

Your OpenVPN service is now up and running. Before you can start using it, though, you must first create a configuration file for the client machine. This tutorial already went over how to create certificate/key pairs for clients, and in the next step we will demonstrate how to create an infrastructure that will generate client configuration files easily.

Creating the Client Configuration Infrastructure

Creating configuration files for OpenVPN clients can be somewhat involved, as every client must have its own config and each must align with the settings outlined in the server’s configuration file. Rather than writing a single configuration file that can only be used on one client, this step outlines a process for building a client configuration infrastructure which you can use to generate config files on-the-fly. You will first create a “base” configuration file then build a script which will allow you to generate unique client config files, certificates, and keys as needed.

Get started by creating a new directory where you will store client configuration files within the client-configs directory you created earlier:

$ mkdir -p ~/client-configs/files

Next, copy an example client configuration file into the client-configs directory to use as your base configuration:

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

Open this new file in your text editor:

$ vim ~/client-configs/base.conf

Inside, locate the remote directive. This points the client to your OpenVPN server address — the public IP address of your OpenVPN server. If you decided to change the port that the OpenVPN server is listening on, you will also need to change 1194 to the port you selected:

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

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

proto udp

Next, uncomment the user and group directives by removing the “;” at the beginning of each line:

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

Find the directives that set the ca, cert, and key. Comment out these directives since you will add the certs and keys within the file itself shortly:

# 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

Similarly, comment out the tls-auth directive, as you will add ta.key directly into the client configuration file:

# If a tls-auth key is used on the server
# then every client must also have the key.
#tls-auth ta.key 1

Mirror the cipher and auth settings that you set in the /etc/openvpn/server.conf file:

cipher AES-256-CBC
auth SHA256

Next, add the key-direction directive somewhere in the file. You must set this to “1” for the VPN to function correctly on the client machine:

key-direction 1

Finally, add a few commented out lines to handle various methods that Linux based VPN clients will use for DNS resolution. You’ll add two similar, but separate sets of commented out lines. The first set is for clients that do not use systemd-resolved to manage DNS. These clients rely on 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

Now add another set of lines for clients that use systemd-resolved for DNS resolution:

; script-security 2
; up /etc/openvpn/update-systemd-resolved
; down /etc/openvpn/update-systemd-resolved
; down-pre
; dhcp-option DOMAIN-ROUTE .

Save and close the file when you are finished.

Later in Step 10 - Installing the Client Configuration step of this tutorial you will learn how to determine how DNS resolution works on Linux clients and which section to uncomment.

Next, create a simple script that will compile your base configuration with the relevant certificate, key, and encryption files and then place the generated configuration in the ~/client-configs/files directory. Open a new file called make_config.sh within the ~/client-configs directory:

vim ~/client-configs/make_config.sh

Inside, add the following content:

#!/bin/bash

# First argument: Client identifier

KEY_DIR=~/client-configs/keys
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf

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

Save and close the file when you are finished.

Before moving on, be sure to mark this file as executable by typing:

chmod 700 ~/client-configs/make_config.sh

This script will make a copy of the base.conf file you made, collect all the certificate and key files you’ve created for your client, extract their contents, append them to the copy of the base configuration file, and export all of this content into a new client configuration file. This means that, rather than having to manage the client’s configuration, certificate, and key files separately, all the required information is stored in one place. The benefit of this is that if you ever need to add a client in the future, you can just run this script to quickly create the config file and ensure that all the important information is stored in a single, easy-to-access location.

Please note that any time you add a new client, you will need to generate new keys and certificates for it before you can run this script and generate its configuration file. You will get some practice using this script in the next step.

Generating Client Configurations

$ cd /etc/openvpn
$ sudo cp ca.crt ~/client-configs/keys
$ sudo cp ta.key ~/client-configs/keys
$ sudo cp easy-rsa/pki/issued/client1.crt ~/client-configs/keys
$ sudo cp easy-rsa/pki/private/client1.key ~/client-configs/keys

If you followed along with the guide, you created a client certificate and key named client1.crt and client1.key, respectively, in Step 4. You can generate a config file for these credentials by moving into your ~/client-configs directory and running the script you made at the end of the previous step:

$ cd ~/client-configs
$ sudo ./make_config.sh client1

This will create a file named client1.ovpn in your ~/client-configs/files directory:

ls ~/client-configs/files

Copy

Outputclient1.ovpn

You need to transfer this file to the device you plan to use as the client. For instance, this could be your local computer or a mobile device.

While the exact applications used to accomplish this transfer will depend on your device’s operating system and your personal preferences, a dependable and secure method is to use SFTP (SSH file transfer protocol) or SCP (Secure Copy) on the backend. This will transport your client’s VPN authentication files over an encrypted connection.

Here is an example SFTP command using the client1.ovpn example which you can run from your local computer (macOS or Linux). It places the .ovpn file in your home directory:

sftp sammy@your_server_ip:client-configs/files/client1.ovpn ~/

macOS Connect

$ brew install openvpn
$ find the path
$ brew info openvpn
$ /usr/local/Cellar/openvpn/2.5.3/sbin/openvpn /Users/wei.shi/Desktop/client1.ovpn

Troubleshooting

cannot locate HMAC

Jul  6 16:48:14 Truenasubuntusw ovpn-server[16787]: TLS Error: cannot locate HMAC in incoming packet from [AF_INET]111.65.44.3:53945
Jul  6 16:48:28 Truenasubuntusw kernel: [177191.753583] [UFW BLOCK] IN=enp0s4 OUT= MAC=... SRC=192.168.18.1 DST=224.0.0.1 LEN=36 TOS=0x1C PREC=0xE0 TTL=1 ID=42214 DF PROTO=2

Solved by adding the following in client.ovpn

cipher AES-256-CBC
auth SHA256

Reference