Introduction
The first attemp to install openvpn on MJ1900 was 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 problem on MJ1900 was that the script cannot add additional clients after the server config file was moved to the server directory. The VPN connections were also unreliable. The clients could connect to it on one day but there was a high probability that the connection failed on the next day, after the server was restarted.
This post describes the steps to re-install OpenVPN based on the post here.
Uninstall the current OpenVpn
// Run as root //
# systemctl stop openvpn-server@mj1900-ovpn-server
# systemctl disable openvpn-server@mj1900-ovpn-server
//remove customised service//
# rm /etc/systemd/system/openvpn\@.service
// Remove the iptables rules related to the script//
# systemctl stop iptables-openvpn
# systemctl disable iptables-openvpn
# rm /etc/systemd/system/iptables-openvpn.service
# systemctl daemon-reload
// Cleanup //
# rm /etc/iptables/add-openvpn-rules.sh
# rm /etc/iptables/rm-openvpn-rules.sh
// Uninstall //
# apt-get remove --purge -y openvpn
# apt-get update
// Cleanup //
# find /home/ -maxdepth 2 -name "*.ovpn" -delete
# find /root/ -maxdepth 1 -name "*.ovpn" -delete
# rm -rf /etc/openvpn
# rm -rf /usr/share/doc/openvpn*
# rm -f /etc/sysctl.d/99-openvpn.conf
# rm -rf /var/log/openvpn
Re-install OpenVpn
The steps will be base on here with modifications to suit the MJ1900 server setup.
Step 1.1 – Install Easy-RSA
This step can be skipped as Easy-Rsa has been install already.
Step 1.2 – Create a Public Key Infrastructure (PKI) Directory
Create the PKI under the /home/tfw:
// Run as tfw //
$ 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.
$ nano ~/easy-rsa/pki/vars
Lines to change or add:
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 "Research 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.crtis the CA’s public certificate file. Every user and the OpenVPN server will need a copy of this file.~/easy-rsa/pki/private/ca.keyis the private key used by the CA to sign certificates for the OpenVPN server and client.
Step 2 – Install OpenVPN
$ 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 mj1900-server and add the nopass option to avoid any permission issues.
$ cd ~/easy-rsa
$ ./easyrsa gen-req mj1900-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) [mj1900-server]:
* Notice:
Keypair and certificate request completed. Your files are:
req: /home/tfw/easy-rsa/pki/reqs/mj1900-server.req
key: /home/tfw/easy-rsa/pki/private/mj1900-server.key
Copy the server key to the “/etc/openvpn/server” directory
$ sudo cp /home/tfw/easy-rsa/pki/private/mj1900-server.key /etc/openvpn/server/
Step 5.1 – import the OpenVpn server CSR
As the CA and OpenVpn server are on the same machine, no import is necessary.
Step 5.2 – Sign the OpenVPN server CSR
$ cd ~/easy-rsa
$ ./easyrsa sign-req server mj1900-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)
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 = mj1900-server
Type the word 'yes' to continue, or any other input to abort.
Confirm request details: yes
Using configuration from /home/tfw/easy-rsa/pki/696a9e86/temp.e38d3e07
40574E42D37F0000: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:'mj1900-server'
Certificate is to be certified until Dec 8 03:45:46 2025 GMT (825 days)
Write out database with 1 new entries
Data Base Updated
* Notice:
Certificate created at: /home/tfw/easy-rsa/pki/issued/mj1900-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/mj1900-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:
// Run as root //
# mkdir -p /etc/openvpn/innovr-client-configs/keys
# chmod -R 700 /etc/openvpn/innovr-client-configs
# cd /home/tfw/easy-rsa
# cp ta.key /etc/openvpn/innovr-client-configs/keys
# cp /etc/openvpn/server/ca.crt /etc/openvpn/innovr-client-configs/keys
Other actions in this step are skipped as the generation of client certificate and key pair will be handled by linux script which will be covered later.
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/mj1900-server.conf
# nano /etc/openvpn/server/mj1900-server.conf
Edit /etc/openvpn/server/mj1900-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
# Network topology
# Should be subnet (addressing via IP)
# unless Windows clients v2.0.9 and lower have to
# be supported (then net30, i.e. a /30 per client)
# Defaults to net30 (not recommended)
topology subnet
# Configure server mode and supply a VPN subnet
# for OpenVPN to draw client addresses from.
# The server will take 10.8.0.1 for itself,
# the rest will be made available to clients.
# Each client will be able to reach the server
# on 10.8.0.1. Comment this line out if you are
# ethernet bridging. See the man page for more info.
server 10.8.0.0 255.255.255.0
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 mj1900-server.crt
key mj1900-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
# Push routes to the client to allow it
# to reach other private subnets behind
# the server. Remember that these
# private subnets will also need
# to know to route the OpenVPN client
# address pool (10.8.0.0/255.255.255.0)
# back to the OpenVPN server.
push "route 192.168.88.0 255.255.255.0"
//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 enp2s0 onlink
//This tells us that the interface name is enp2s0. //
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.
// Run 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-09-05
# START OPENVPN RULES
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to enp2s0 (change to the interface you discovered!)
-A POSTROUTING -s 10.8.0.0/8 -o enp2s0 -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@mj1900-server
//Check the status of the service.//
# systemctl status openvpn-server@mj1900-server
//Enable the OpenVPN service to start at boot.//
# systemctl -f enable openvpn-server@mj1900-server
Step 12 – Create Client Configuration
Create client’s base config file
//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 script to generate client configuration file
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
Create scripts to manage the clients’ cert and key generation and vpn configuration
This is based on the post article here. Copy the following files from the virtual box vm-Debian-12 guest to mj1900 at /etc/openvpn directory. Some modifications are required as outlined below.
- Add a client
- command: /etc/openvpn/ivr-add-client.sh client_cn
- added the function for checking the client CN is provided as an the argument
- command: /etc/openvpn/ivr-add-client.sh client_cn
- Remove a client
- command: /etc/openvpn/ivr-remove-client.sh client_cn
- added the function for checking the client CN is provided as an the argument
- replaced the server to ‘mj1900-server’
- command: /etc/openvpn/ivr-remove-client.sh client_cn
- Show all, active or revoked clients
- /etc/openvpn/ivr-show-clients.sh [ active(default) | all | revoked ]
- the script is rewritten using the ‘tail’ command instead of ‘cat’
- /etc/openvpn/ivr-show-clients.sh [ active(default) | all | revoked ]
Step 13 – Test VPN Connections
Create a temporary account test00 and transfer it to a mobile phone for testing on LAN and internet connections. Remove the this account after the test.
Remove all sensitive files in these directories:
- /root
- /doc/temp
- download directories of concerned phone and notebook devices.
Conclusion
The reinstallation of OpenVpn on MJ1900 was successfully implemented on 06-Sep-2023.
Updates
2023-09-11
There were occassions that the VPN clients, even though they could connect to the VPN Server and Internet, but were not able to connect to other servers / resources on the LAN.
The following actions were taken and appeared to have solved the problem:
- Edited /etc/ufw/sysctl.conf
- Uncommented the line net/ipv4/ip_forward = 1
- noted that during openvpn installation, another file, /etc/sysctl.conf, was also added this line.
- It was observed that if only 1 interface had the masq. rule and when the LAN connection was failed, there were no packets going through the interface. Therefore, the /etc/ufw/before.rules was edited to let both network interfaces have the masquerade rule.
- -A POSTROUTING -s 10.8.0.0/24 -o enp2s0 -j MASQUERADE
- -A POSTROUTING -s 10.8.0.0/24 -o enp1s0 -j MASQUERADE
- enp1s0 has no packets passed through.
- enp2s0 has packets passed through.
2023-09-12
Working nornally. Both interfaces have packets passed through.
