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).
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 theca.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, yourca.key
file, they will be able to sign certificate requests and gain access to your VPN, impeding its security. This is why yourca.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
- https://techoverflow.net/2020/09/20/how-to-fix-openvpn-tls-error-cannot-locate-hmac-in-incoming-packet-from/
- https://www.digitalocean.com/community/questions/help-with-the-following-error-tls-error-cannot-locate-hmac-in-incoming-packet-from-af_inet
Solved by adding the following in client.ovpn
cipher AES-256-CBC
auth SHA256
Reference
- https://github.com/OpenVPN/easy-rsa
- https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-18-04
- https://ubuntu.com/server/docs/service-openvpn
- https://www.youtube.com/watch?v=0zE6BBrszcw