VPN setup

Installation

OpenVPN

Ubuntu tutorial | html

sudo apt-get install openvpn easy-rsa

Alternative for site-to-site (requires public addresses): StrongSwan

Key generation

Generate all server and client(s) keys on a dedicated host, using easy-rsa script

Preparation

sudo su
make-cadir /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa

vi vars
# Edit KEY specific info

# easy-rsa v2
# fix cnf file check with latest open-ssl versions
# ln -s openssl-1.0.0.cnf openssl.cnf

# . ./vars
# ./clean-all

Certificate Authority key

CA uses the follwing files:

CA key is used by neither server nor clients, it is only used to sign/revoque each device keys.

# generate the self-signed CA key pair
./easyrsa init-pki
./easyrsa build-ca nopass
Common Name:tognoli.fr

# v2: ./build-ca

Server keys

Server uses the follwing files:

.csr (Certificate Signing Request) are not used/needed after key generation.

# generate and sign server key pair
./easyrsa build-server-full server nopass
# v2: ./build-key-server server

# generate the Diffie Hellman parameters file
./easyrsa gen-dh
# v2: ./build-dh

# generate client authentication key
openvpn --genkey secret ta.key

# pack server keys
tar cvzf ../server-keys.tgz ta.key -C pki ca.crt dh.pem -C issued server.crt -C ../private server.key

Client key

Generates the following files:

We generate one Client key set per client host.

# generate and sign client key (one for each client)
./easyrsa build-client-full client-x nopass
# v2: ./build-key client-x

# pack client keys
tar cvzf ../client-x-keys.tgz ta.key -C pki ca.crt -C issued client-x.crt -C ../private client-x.key

To check key status:

sudo openssl x509 -in client_dart.crt -text -noout

Server configuration

OpenVPN sample server conf file is a good starting point.

# use the sample server file
cd /etc/openvpn/
cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz .
gunzip server.conf.gz
vi server.conf
local 192.168.0.234

# dh dh2048.pem
dh dh.pem

Install Keys

# get the keys
ssh user@keyhost cat private/server-keys.tgz | tar xvzf -

# start the server
systemctl start openvpn@server

# check current server status
systemctl status openvpn@server

Client configuration

Some adjustment are needed on the client side

# use the sample client file
cd /etc/openvpn/
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf .

# get the keys
ssh user@keyhost cat private/client-x-keys.tgz | tar xvzf -
vi client.conf
remote my-server-1 1194
remote server.com 1194

cert client.crt
key client.key
cert client-x.crt
key client-x.key

;tls-auth ta.key 1
tls-auth ta.key 1

;cipher x
cipher AES-256-CBC

comp-lzo
# comp-lzo

Start the client

# start the client
systemctl start openvpn@client

# check current client status
systemctl status openvpn@client.service

Testing

From client

Server is 10.8.0.1 (as per config file), interface is tun0

ip addr show tun0
13: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.8.0.6 peer 10.8.0.5/32 scope global tun0
       valid_lft forever preferred_lft forever

ip -s link show tun0
13: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 100
    link/none
    RX: bytes  packets  errors  dropped overrun mcast
    8774       88       0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    9421       68       0       0       0       0

ping 10.8.0.1 -c 4
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=95.8 ms
64 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=91.1 ms
64 bytes from 10.8.0.1: icmp_seq=3 ttl=64 time=90.7 ms
64 bytes from 10.8.0.1: icmp_seq=4 ttl=64 time=90.6 ms

--- 10.8.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 90.637/92.112/95.897/2.214 ms

From server

ip addr show tun0
4: tun0:  mtu 1500 qdisc pfifo_fast 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
    inet6 fe80::8b05:3440:a279:508d/64 scope link flags 800
       valid_lft forever preferred_lft forever

ip -s link show tun0
4: tun0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 100
    link/none
    RX: bytes  packets  errors  dropped overrun mcast
    9925       74       0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    11034      123      0       0       0       0

ping 10.8.0.6 -c 4
PING 10.8.0.6 (10.8.0.6) 56(84) bytes of data.
64 bytes from 10.8.0.6: icmp_seq=1 ttl=64 time=91.0 ms
64 bytes from 10.8.0.6: icmp_seq=2 ttl=64 time=93.3 ms
64 bytes from 10.8.0.6: icmp_seq=3 ttl=64 time=99.6 ms
64 bytes from 10.8.0.6: icmp_seq=4 ttl=64 time=94.2 ms

--- 10.8.0.6 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 91.040/94.575/99.673/3.173 ms

Expanding VPN scope to client/server subnets

Scenario

Next step is to use the VPN tunnel to allow hosts from server LAN to communicate with hosts from client LAN and vice versa.

Internet Server HostA RouterA LanA 192.168.0.xxx .99 .254 .2 Client RouterB HostB LanB 192.168.10.xxx .230 .200 .100 Vpn 10.8.0.1 10.8.0.2

As depicted, HostA (192.168.0.2) from LanA will use tunnel from VPN Server (192.168.0.99) to VPN Client (192.168.10.200) to reach HostB (192.168.10.230).

Server configuration:

Add to the server configuration:

sudo vi /etc/openvpn/server.conf
# Create the routed IP tunnel
proto udp
dev tun
mode server
tls-server
;topology subnet
topology subnet
server 10.8.0.0 255.255.255.0
ifconfig 10.8.0.1 255.255.255.0

# Configure client
;client-config-dir ccd
;route 10.9.0.0 255.255.255.252
client-config-dir ccd
route 192.168.10.0 255.255.255.0 10.8.0.2

Also create client configuration file (for each client, named after client certificate Common Name):

sudo mkdir /etc/openvpn/ccd
sudo vi /etc/openvpn/ccd/client-x
ifconfig-push 10.8.0.2 255.255.255.0
push "route 192.168.0.0 255.255.255.0 10.8.0.1"
iroute 192.168.10.0 255.255.255.0

Restart the server:

sudo systemctl restart openvpn@server

Client configuration

sudo vi /etc/openvpn/client.conf
client
dev tun
proto udp
topology subnet

Restart the server:

sudo systemctl restart openvpn@client

Additional config

Server and all clients need to have IP forwarding enabled:

# echo 1 > /proc/sys/net/ipv4/ip_forward
sudo sysctl -w net.ipv4.ip_forward=1
# sudo sysctl -w net.ipv6.conf.all.forwarding=1

To make the change permanent:

sudo vi /etc/sysctl.conf
# Uncomment the next line to enable packet forwarding for IPv4
#net.ipv4.ip_forward=1
net.ipv4.ip_forward=1

Local hosts need to have a route to openvpn added (either on the default gateway or on all accessible hosts)
Note: This is not required when OpenVPN is installed on the default gateway

sudo ip route add 192.168.10.0/24 via 192.168.0.99

When OpenVPN server is installed behind a NAT gateway, gateway port 1194 must be forwarded to OpenVPN host

Others

Port forwarding

To forward all traffic coming to a port to another host/port:

local=192.168.0.99
lport=8080
dest=10.8.0.6
dport=80

iptables -t nat -A PREROUTING  -p tcp --dst $local --dport $lport -j DNAT --to-destination $dest:$dport
iptables -t nat -A POSTROUTING -p tcp --dst $dest  --dport $dport -j SNAT --to-source $local
iptables -t nat -A OUTPUT      -p tcp --dst $local --dport $lport -j DNAT --to-destination $dest:$dport

Idle ping/keep alive

Keep alive may use significant bandwidth on limited plans. to limit:

By default, openvpn sends ping every 10s idle, means 64*26*60*24*31 = 35MB/month (significant is on a 50MB plan)

Switching to 1 ping per minute will reduce to .5M / month

iftop -p -N -n
# The keepalive directive causes ping-like
# messages to be sent back and forth over
# the link so that each side knows when
# the other side has gone down.
# Ping every 10 seconds, assume that remote
# peer is down if no ping received during
# a 120 second time period.
keepalive 10 120
keepalive 60 360
18-Dec-2023