Server installation

Install the packages:

sudo apt install openvpn easy-rsa

Copy an example config file:

gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | \
sudo tee /etc/openvpn/server.conf

Some example values are used. The WAN IP addresses 111.222.333.444/24 and 2001:1:2:3:4:5:6::/64 are made up. Also, ethernet interface enp0s25 will very likely be different on your system.

Main server configuration

/etc/openvpn/server.conf
# Listen on UDP port 1194
port 1194
proto udp
 
# Use a tun device and push an IPv6 tunnel to clients
dev tun
push tun-ipv6
 
# Certificate settings
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
 
# Create subnets for the clients
topology subnet
server 10.8.0.0 255.255.255.0
server-ipv6 2001:1:2:3:80::/112
 
# Push routes, gateways and DNS to the clients
push "route-ipv6 2001:1:2:3::/64"
push "redirect-gateway def1 bypass-dhcp"
push "redirect-gateway ipv6"
 
## OpenDNS is used in this example, but anything reachable by the VPN server will work
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
 
# Allow direct client-to-client connections
client-to-client
 
# Ping every 10 seconds, assume disconnect after 120 seconds
keepalive 10 120
 
# TLS parameters
## This is the server
tls-auth ta.key 0
key-direction 0
## Use strong ciphers
cipher AES-256-CBC
auth SHA512
 
# Run the daemon with minimal privileges
user nobody
group nogroup
persist-key
persist-tun
 
# Logging settings
status openvpn-status.log
verb 3
explicit-exit-notify 1


Networking configuration

Allow packet forwarding and enable the IPv6 neighbour detection proxy:

/etc/sysctl.conf
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.proxy_ndp=1

Load the kernel parameters:

sudo sysctl -p


SLAAC

If your server gets its IPv6 configuration through SLAAC, also do this:

/etc/sysctl.conf
net.ipv6.conf.all.accept_ra=2
net.ipv6.conf.default.accept_ra=2

Load the kernel parameters:

sudo sysctl -p

Force acceptance of router advertisements for the WAN ethernet interface:

# This setting is not inherited from 'all' or 'default' when the interface is already up.
# It will be inherited after the next reboot, so this only has to be done once.
sudo su -c 'echo 2 > /proc/sys/net/ipv6/conf/enp0s25/accept_ra'


Firewall rules

Allow masquerading for the OpenVPN subnet:

/etc/ufw/before.rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/8 -o enp0s25 -j MASQUERADE
COMMIT
/etc/ufw/before6.rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 2001:1:2:3:80::/112 -o enp0s25 -j MASQUERADE
COMMIT

Don't drop forwarded packets:

/etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"

Allow incoming connections on UDP port 1194 and restart the firewall:

sudo ufw allow 1194/udp
sudo ufw disable && sudo ufw enable


Setting up your own certificate authority

Create a working directory:

make-cadir openvpn-ca
cd openvpn-ca/
ln -s openssl-1.0.0.cnf openssl.cnf

Fill in these variables as desired (saves time):

openvpn-ca/vars
export KEY_COUNTRY="..."
export KEY_PROVINCE="..."
export KEY_CITY="..."
export KEY_ORG="..."
export KEY_EMAIL="..."
export KEY_OU="..."

Source the vars file:

source ./vars

Clean the directory:

./clean-all

Build a certificate authority:

./build-ca

Build a server key called server:

./build-key-server server

Build a Diffie-Hellman key:

./build-dh

Generate a pre-shared key:

/usr/sbin/openvpn --genkey --secret keys/ta.key

Copy the generated keys to the server configuration directory:

cd keys/
sudo cp ca.crt ca.key server.crt server.key ta.key dh2048.pem /etc/openvpn/

Restart the server:

sudo systemctl restart openvpn@server


Creating configuration files automatically

Create a working directory next to openvpn-ca:

cd ../../
mkdir -p client-configs/files/
cd client-configs/


Client configuration

Add a base configuration file for your clients:

base.conf
# Specify that we are a client
client
 
# Use the same setting as you are using on the server
dev tun
 
# Connect to the server on UDP port 1194
proto udp
remote 111.222.333.444 1194
 
# Run the daemon with minimal privileges
user nobody
group nogroup
 
# Unset these defaults (certificates will be provided by the .ovpn file)
#ca ca.crt
#cert client.crt
#key client.key
 
# Use strong ciphers
cipher AES-256-CBC
auth SHA512
 
# This is the client
key-direction 1
 
# Run these scripts after connecting (sets up DNS)
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf


Build script

Add a configuration build script:

make_config.sh
#!/bin/bash
 
KEY_DIR=../openvpn-ca/keys
OUTPUT_DIR=./files
BASE_CONFIG=./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

Make it executable:

chmod 770 ./make_config.sh


Generating client certificates and configurations

Source the vars file:

cd openvpn-ca/
source ./vars

Build a client certificate with password:

./build-key-pass $name

Create a client configuration file:

cd ../client-configs/
./make_config.sh $name

The resulting configuration will be in client-configs/files/$name.ovpn

Copy this to your client with SFTP. Repeat as many times as desired.

Revoking a client certificate

Source the vars file:

cd openvpn-ca/
source ./vars

Revoke the certificate:

./revoke-full $name

Copy the revocation list to the server configuration directory:

sudo cp ./keys/crl.pem /etc/openvpn/

Make sure that the OpenVPN server configuration file contains this line:

/etc/openvpn/server.conf
crl-verify crl.pem

Then restart the server:

sudo systemctl restart openvpn@server


Client installation

sudo apt install network-manager-openvpn-gnome

Then simply import the .ovpn file with NetworkManager.