Introduction
This article covers the installation of OpenVPN on a virtual box machine with the latest Debian distribution – Debian 12.
Another OpenVPN has been installed on MJ1900 server based on the installation script from angristan. However, this script does not support the latest OpenVPN directory structure which has the server config placed under the server directory. The current problem on MJ1900 is that the script cannot add additional clients after the config file is put under the server directory.
This project is to follow the howtofork.com approach to install OpenVPN manually so as to meet the customized requirement – follows the latest directory structure and have a script to add clients.
The howtofork.com recommends to put the CA server and OpenVPN server on two separate machines. However, this project will put them on the same VM machine.
Step 1 – Setting up the CA server
Step 1.1 – Install Easy-RSA
Install the easy-rsa set of scripts. easy-rsa is a Certificate Authority management tool used to generate a private key and public root certificate.
// Exit from root first
$ cd ~
$ sudo apt update
$ sudo apt install easy-rsa
The above has installed easy-rsa in the folder /usr/share/easy-rsa.
Step 1.2 – Create a Public Key Infrastructure (PKI) Directory
Create the PKI under the user home:
$ mkdir ~/easy-rsa
$ ln -s /usr/share/easy-rsa/* ~/easy-rsa
$ chmod 700 /home/tfw/easy-rsa
$ cd ~/easy-rsa
$ ./easyrsa init-pki // Initalize the PKI
The created PKI dir is /home/tfw/easy-rsa/pki. The Easy-RSA “vars” is also moved to the above pki directory.
Step 1.3 – Create a Certificate Authority (CA)
Before you can create your CA’s private key and certificate, you need to configure the organization information for it. The configuration file vars is already created in the pki directory. Open it for editing.
set_var EASYRSA_REQ_COUNTRY "HK"
set_var EASYRSA_REQ_PROVINCE "Kowloon"
set_var EASYRSA_REQ_CITY "TaiKokTsui"
set_var EASYRSA_REQ_ORG "InnovRiver"
set_var EASYRSA_REQ_EMAIL "innovriver@gmail.com"
set_var EASYRSA_REQ_OU "Dev Unit"
set_var EASYRSA_ALGO ec
set_var EASYRSA_DIGEST "sha256"
//Find and modify the EASYRSA_CRL_DAYS
set_var EASYRSA_CRL_DAYS 3650
Run the following command to create the root public and private key pair for your CA. The ‘nopass’ argument allows no password is required for every time you interact with your CA.
$ cd ~/easy-rsa
$ ./easyrsa build-ca nopass
Question prompted: Common Name = innovriver
Output of build-ca:
CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/tfw/easy-rsa/pki/ca.crt
This has created two files:
~/easy-rsa/pki/ca.crt- is the CA’s public certificate file. Every user and the OpenVPN server will need a copy of this file.
~/easy-rsa/pki/private/ca.key- is the private key used by the CA to sign certificates for the OpenVPN server and client.
Step 2 – Install OpenVPN
As the CA and OVPN server are on the same machine, Step 2 and after are slightly different from that described in the referenced HowToFork article.
$ sudo apt install openvpn
Step 3 – Create a PKI for OpenVPN Server
The PKI has already been created in Step 1.2.
Step 4 – Create OpenVPN Server Certificate Signing Request (CSR) and Private Key
Run the easy-rsa command with the gen-req option followed by a Common Name (CN) for the server. Set the CN to ovpn-server and add the nopass option to avoid any permission issues.
$ cd ~/easy-rsa
$ ./easyrsa gen-req ovpn-server nopass
Output:
* Notice:
Using Easy-RSA configuration from: /home/tfw/easy-rsa/pki/vars
* Notice:
Using SSL: openssl OpenSSL 3.0.9 30 May 2023 (Library: OpenSSL 3.0.9 30 May 2023)
-----
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) [ovpn-server]:
* Notice:
Keypair and certificate request completed. Your files are:
req: /home/tfw/easy-rsa/pki/reqs/ovpn-server.req
key: /home/tfw/easy-rsa/pki/private/ovpn-server.key
Copy the server key to the “/etc/openvpn/server” directory
$ sudo cp /home/tfw/easy-rsa/pki/private/ovpn-server.key /etc/openvpn/server/
Step 5 – Sign the OpenVPN Server’s CSR
Step 5.1 – import the CSR
The syntax is “./easyrsa import-req /path/to/received.req UNIQUE_SHORT_FILE_NAME”.
Move the .req file to /tmp directory first, otherwise it will cause an error about file already exists.
$ cd ~/easy-rsa
$ mv easy-rsa/pki/reqs/ovpn-server.req /tmp
$ ./easyrsa import-req /tmp/ovpn-server.req ovpn-server
Output:
* Notice:
Using Easy-RSA configuration from: /home/tfw/easy-rsa/pki/vars
* Notice:
Using SSL: openssl OpenSSL 3.0.9 30 May 2023 (Library: OpenSSL 3.0.9 30 May 2023)
* Notice:
The request has been successfully imported with a short name of: ovpn-server
You may now use this name to perform signing operations on this request.
Step 5.2 – Sign the OpenVPN Server’s CSR
$ cd ~/easy-rsa
$ ./easyrsa sign-req server ovpn-server
Output:
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 825 days:
subject=
commonName = ovpn-server
Type the word 'yes' to continue, or any other input to abort.
Confirm request details:
Using configuration from /home/tfw/easy-rsa/pki/9d2e2fca/temp.5616474e
4097EB01CA7F0000:error:0700006C:configuration file routines:NCONF_get_string:no value:../crypto/conf/conf_lib.c:315:group=<NULL> name=unique_subject
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :ASN.1 12:'ovpn-server'
Certificate is to be certified until Dec 2 17:12:33 2025 GMT (825 days)
Write out database with 1 new entries
Data Base Updated
* Notice:
Certificate created at: /home/tfw/easy-rsa/pki/issued/ovpn-server.crt
The resulting certificate contains the OpenVPN server’s public encryption key as well as the signature from the CA server. Copy the certificates back to the OpenVPN directory.
$ cd ~/easy-rsa
$ sudo cp pki/issued/ovpn-server.crt /etc/openvpn/server
$ sudo cp pki/ca.crt /etc/openvpn/server
Step 6 – Configure OpenVpn Cryptographic Material
We will add an extra shared secret key that the server and all clients will use with OpenVPN’s tls-crypt directive. This ensures that the OpenVPN server can cope with unauthenticated traffic, port scans, and Denial of Service attacks. It also makes it harder to identify OpenVPN network traffic.
$ cd ~/easy-rsa
// Generate a strong Diffie-Hellman key to use during key exchange:
$ ./easyrsa gen-dh
Output:
=======
* Notice:
DH parameters of size 2048 created at /home/tfw/easy-rsa/pki/dh.pem
Generate the tls-crypt pre-shared key. This will create a file called ta.key
$ sudo openvpn --genkey secret ta.key
Copy the dh.pem and ta.key to the OpenVpn server directory:
$ cd ~/easy-rsa
$ sudo cp ta.key /etc/openvpn/server
$ sudo cp pki/dh.pem /etc/openvpn/server
Step 7 – Generate a Client Certificate and Key Pair
Create a directory to store the client certificate and key files:
$ mkdir -p /etc/openvpn/innovr-client-configs/keys
$ chmod -R 700 /etc/openvpn/innovr-client-configs
Generate a client key with client-1 as the Common Name for the client. You can use any CN for the client.
$ cd ~/easy-rsa
$ ./easyrsa gen-req client-1 nopass
// Output
Keypair and certificate request completed. Your files are:
req: /home/tfw/easy-rsa/pki/reqs/client-1.req
key: /home/tfw/easy-rsa/pki/private/client-1.key
Copy the client-1 key file to the /etc/openvpn/innovr-client-configs/keys directory.
Move the client-1.req to /tmp, and then use import-req option to import the same to the reqs directory. Compare this file with that in /temp to check if there are any difference.
$ cd ~/easy-rsa
$ sudo cp pki/private/client-1.key /etc/openvpn/innovr-client-configs/keys
$ mv pki/reqs/client-1.req /tmp
$ cp /tmp/client-1.req /tmp/client-1-copy.req
$ ./easyrsa import-req /tmp/client-1.req client-1
// Output:
* Notice:
The request has been successfully imported with a short name of: client-1
You may now use this name to perform signing operations on this request.
$ diff -y pki/reqs/client-1.req /tmp/client-1.req
// The 2 files have no difference! Can the import be skipped? Try it out for client-2.
Sign the request using the following command. We are using client as the request type.
$ ./easyrsa sign-req client client-1
Output:
Using configuration from /home/tfw/easy-rsa/pki/58ae390d/temp.a29f86ad
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :ASN.1 12:'client-1'
Certificate is to be certified until Dec 3 09:49:06 2025 GMT (825 days)
Write out database with 1 new entries
Data Base Updated
* Notice:
Certificate created at: /home/tfw/easy-rsa/pki/issued/client-1.crt
Transfer the created client certificates to the openvpn directories:
$ cd ~/easy-rsa
$ sudo cp pki/issued/client-1.crt /etc/openvpn/innovr-client-configs/keys
$ sudo cp ta.key /etc/openvpn/innovr-client-configs/keys
$ sudo cp /etc/openvpn/server/ca.crt /etc/openvpn/innovr-client-configs/keys/
Step 8 – Configure OpenVpn
Copy the sample server.conf file as a starting point to configure OpenVPN.
// su to root
# cd /etc/openvpn
# cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf server/ovpn-sever.conf
# nano /etc/openvpn/server/ovpn-server.conf
Edit /etc/openvpn/server/ovpn-server.conf
// Find the HMAC section of the file by looking for the tls-auth directive. Comment out the line by adding a semi-colon (;) at the beginning of the line. Add a new line below it as shown.//
;tls-auth ta.key 0 # This file is secret
tls-crypt ta.key
//Next, change the cryptographic cipher value by looking for the cipher lines. The default value is set to AES-256-CBC. Comment out the default value and add another line with the AES-256-GCM encryption which offers a better level of encryption, and performance as shown.//
;cipher AES-256-CBC
cipher AES-256-GCM
//Right below, add the auth directive to select the HMAC message digest algorithm.//
auth SHA256
//Since we are using Elliptic Curve Cryptography, we need to turn off the Diffie-Hellman encryption. Comment out the dh dh2048.pem line and add dh none below it.//
;dh dh2048.pem
dh none
//OpenVPN should run with no privileges once it has started. To enable this, find and uncomment the ;user openvpn and ;group openvpn lines and change them as shown.//
user nobody
group nogroup
Redirect All Traffic through the VPN
//The settings above create the VPN connection between the client and server, but won't force any connections to use the tunnel. To do so, start by finding the push "redirect-gateway def1 bypass-dhcp" line. This line tells the client to redirect all its traffic through the OpenVPN server. Uncomment the line to enable the functionality.//
push "redirect-gateway def1 bypass-dhcp"
//Find the dhcp-option section below this line. Remove the semi-colon from the beginning of both lines. This tells the client to use the OpenDNS resolvers. Also add the home router as the resolver.//
push "dhcp-option DNS 192.168.88.1"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
Other changes
//OpenVPN uses port 1194 and the UDP protocol by default to accept client connections. You can change the port depending on your needs. If you are not hosting web content on your OpenVPN server, you can use port 443. Find the line port 1194 and change its value.//
port 1194
//Find the proto udp line and comment it out by adding a semi-colon in front of it. And, uncomment the proto tcp line by removing the semi-colon as shown.//
;proto tcp
proto udp
//For TCP protocol, the value is 0. For UDP, set to 1.//
explicit-exit-notify 1
//Modify the cert and key directive to point to the correct names//
cert ovpn-server.crt
key ovpn-server.key
# By default, log messages will go to the syslog (or
# on Windows, if running as a service, they will go to
# the "\Program Files\OpenVPN\log" directory).
# Use log or log-append to override this default.
# "log" will truncate the log file on OpenVPN startup,
# while "log-append" will append to it. Use one
# or the other (but not both).
log /var/log/openvpn/openvpn.log
;log-append /var/log/openvpn/openvpn.log
# Maintain a record of client <-> virtual IP address
# associations in this file. If OpenVPN goes down or
# is restarted, reconnecting clients can be assigned
# the same virtual IP address from the pool that was
# previously assigned.
ifconfig-pool-persist /etc/openvpn/server/ipp.txt
//Check certificate against a Client Revoked List (CRL)
crl-verify /etc/openvpn/server/crl.pem
Generate the CRL
# cd /home/tfw/easy-rsa
# ./easyrsa gen-crl
# cp pki/crl.pem /etc/openvpn/server
# chmod 644 /etc/openvpn/server/crl.pem
Step 9 – Adjust OpenVpn Server Network Configuration
Enable IP Forwarding
// Log in as root//
# nano /etc/sysctl.conf
//Add the following line at the bottom of the file.//
net.ipv4.ip_forward = 1
//To read the file and load the new values for the current session, use the following command.//
$ sysctl -p
//Output://
vm.swappiness = 0
net.ipv4.ip_forward = 1
Step 10 – Configure Firewall
To allow OpenVPN through the firewall, you need 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, first, find the public network interface of your machine using the following command.
$ ip route list default
// Output: //
default via 192.168.88.1 dev enp0s3 proto dhcp src 192.168.88.115 metric 100
This tells us that the interface name is enp0s3.
Edit the ufw before.rules file. These rules are read and put in place before the conventional UFW rules are loaded. Add the following lines at the start of the file as shown.
// SU as root
# nano /etc/ufw/before.rules
----------------------------------------------------
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
# ufw-before-input
# ufw-before-output
# ufw-before-forward
#
# ^^ TFW 2023-08-31
# START OPENVPN RULES
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to enp0s3 (change to the interface you discovered!)
-A POSTROUTING -s 10.8.0.0/8 -o enp0s3 -j MASQUERADE
COMMIT
# ^^ END OPENVPN RULES
# Don't delete these required lines, otherwise there will be errors
*filter
. . .
Next, we need to configure UFW to allow forwarded packets by default. Open the /etc/default/ufw file for editing.
# nano /etc/default/ufw
//Find the DEFAULT_FORWARD_POLICY directive and change its value from DROP to ACCEPT.//
DEFAULT_FORWARD_POLICY="ACCEPT"
And, finally, open port 1194 which you configured earlier for the OpenVPN server.
# ufw allow 1194/udp
//Disable and enable the firewall to apply the new configuration.//
# ufw disable
# ufw enable
Step 11 – Start OpenVPN
# systemctl start openvpn-server@ovpn-server.service
//Check the status of the service.//
# systemctl status openvpn-server@ovpn-server.service
//Enable the OpenVPN service to start at boot.//
# systemctl -f enable openvpn-server@ovpn-server.service
Step 12 – Create Client Configuration
Create client’s base config
//Before testing a client, we need to create configuration files for the client we will use. Create a directory for storing client configuration files.//
# cd /etc/openvpn/innovr-client-configs
# mkdir files
//Copy the example client configuration file to the directory.//
# cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf base.conf
//Open the configuration file for editing.//
$ nano base.conf
Edit the file according to the following:
. . .
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote innovriver.com 1194
. . .
//Set the protocol you chose earlier by uncommenting it and commenting out the proto udp setting.//
proto udp
//Uncomment the user and group directives by removing the semi-colon in front of them. Also, change the values as follows.//
# Downgrade privileges after initialization (non-Windows only)
user nobody
group nogroup
//Find the ca, cert, and key directives and comment them out by putting a semi-colon in front of them. This is because we will add the certs and keys within the client configuration file.//
# 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
//Comment out the tls-auth directive as we will add the 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
//Match the cipher setting that you set in the `/etc/openvpn/server/ovpn-server.conf file. Also, add the auth setting at the bottom of the file.//
cipher AES-256-GCM
....
auth SHA256
//Add the key-direction directive and set it to 1 for the VPN to function correctly.//
key-direction 1
//Next, add a few commented-out lines to handle different methods used by VPN clients for DNS resolution. Add the following set of lines for clients that don't use systemd-resolved but rely on the resolvconf utility to manage DNS.//
; script-security 2
; up /etc/openvpn/update-resolv-conf
; down /etc/openvpn/update-resolv-conf
//Add the following 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 .
Create client ovpn files
Create a script to compile the base configuration with the relevant certificate, key, and encryption files, and then copy the generated configuration file into the /etc/openvpn/innovr-client-configs/files directory.
Create and open the file make-client-config.sh within the innovr-client-configs directory.
# cd /etc/openvpn/innovr-client-configs
# nano make-client-config.sh
Past the folllowing code into the sh file
#!/bin/bash
# First argument: Client identifier
KEY_DIR=/etc/openvpn/innovr-client-configs/keys
OUTPUT_DIR=/etc/openvpn/innovr-client-configs/files
BASE_CONFIG=/etc/openvpn/innovr-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-crypt>') \
${KEY_DIR}/ta.key \
<(echo -e '</tls-crypt>') \
> ${OUTPUT_DIR}/${1}.ovpn
//Make the file executable and restrict permissions to it.//
# chmod 700 make-client-config.sh
This script makes a copy of the base.conf file, collect all the certificate and key files, extract their content, append them to the base configuration file, and export all that to create a new client configuration file. Every time you add a new client, you need to generate new keys and certificates for it and then run this script to create a client configuration file.
We have already created the client certificate and key files in step 7. Let us create the configuration file for the same.
Run the script to make the client configuration file:
# cd /etc/openvpn/innovr-client-configs
# ./make-client-config.sh client-1
//This will create a file named client-1.ovpn in the directory ../innovr-client-configs/files. This file will be transferred to the client device for making the connection.//
Step 13 – Test VPN Connections
The client-1 ovpn file was transfered to Mi 13 device. The VPN connections to Internet and LAN were successful.
// Control of the service:
# systemctl start openvpn-server@ovpn-server
# systemctl status openvpn-server@ovpn-server
and others...
Conclusion
The setting up of OpenVPN based on the procedures in the HowToFork article was successfully completed.
The easy-rsa has been installed in the folder /usr/share/easy-rsa.
The PKI has been installed in /home/tfw/easy-rsa/pki directory
The OpenVpn server has been installed in /etc/openvpn/server directory
The OpenVpn clients setup has been installed in /etc/openvpn/innovr-client-configs directory
The creation of script to automate the addition of new clients will be covered in another coming post.
