StrongSwan VPN setup

This is a guide for setting up strongSwan, a VPN solution that allows you to securely connect to your home network from a remote location. The guide is based on this excellent blog post by Atomstar.

While strongSwan can work with a wide range of scenarios, the setup presented here is a typical home network where the VPN server acts as a gateway allowing you to connect to your home devices from outside the network.

I used a Raspberry Pi in my setup, but the instructions can be easily applied to any Debian-based Linux distribution.

Why strongSwan

I personally chose strongSwan because it uses IKEv2/IPSec under the hood, a protocol stack natively supported by macOS and iOS without the need of a separate app. After struggling to configure an OpenVPN client on macOS (via the Tunnelblick app) I decided to look for an alternative solution, and was surprised to see how smooth strongSwan's configuration went.

Another reason would be that StrongSwan is already present in the official Debian apt repository, making installation easier and more secure.

There are other IPSec solutions for Linux, such as Openswan or Libreswan. The differences between all the "Swans" are highlighted in this serverfault question, but ultimately StrongSwan seems to be the more mature project and better suited for Debian/Ubuntu/RaspberryPi.

The setup

Installing required packages

strongSwan is part of the official apt repository for RaspberryPi OS, Debian and Ubuntu, so installation involves just running an apt install:

sudo apt install strongswan strongswan-pki libcharon-extra-plugins libstrongswan-extra-plugins

Certificates and keys

Let's generate the required certificate and keys.
We will do this within a directory that nobody else can access:

mkdir ~/vpn-certs/
cd ~/vpn-certs/
chmod 700 .

Let's set some environment variables to help us with the commands. Adjust these to match your setup:

export SERVER_FQDN="mihai.fm"
export SERVER_COUNTRY="RO"

An IKEv2 server requires a certificate to identify itself to clients. This needs to be signed by a certificate authority root certificate and key.

We first need to generate the key for our certificate authority.

ipsec pki --gen --type rsa --size 4096 --outform pem > server-root-key.pem
chmod 600 server-root-key.pem

Then we generate the root certificate for our certificate authority.

ipsec pki --self --ca --lifetime 3650 \
    --in server-root-key.pem \
    --type rsa --dn "C=${SERVER_COUNTRY}, O=VPN Server, CN=VPN Server Root CA" \
    --outform pem > server-root-ca.pem

Next, let's generate a key for our VPN server:

ipsec pki --gen --type rsa --size 4096 --outform pem > vpn-server-key.pem

Finally, generate the certificate for our VPN server and sign it with the certificate authority key/certificate.

ipsec pki --pub --in vpn-server-key.pem \
    --type rsa | ipsec pki --issue --lifetime 1825 \
    --cacert server-root-ca.pem \
    --cakey server-root-key.pem \
    --dn "C=${SERVER_COUNTRY}, O=VPN Server, CN=${SERVER_FQDN}" \
    --san ${SERVER_FQDN} \
    --flag serverAuth --flag ikeIntermediate \
    --outform pem > vpn-server-cert.pem

Copy the output files to the necessary locations and set permissions:

sudo cp ./vpn-server-cert.pem /etc/ipsec.d/certs/vpn-server-cert.pem
sudo cp ./vpn-server-key.pem /etc/ipsec.d/private/vpn-server-key.pem

sudo chown root /etc/ipsec.d/private/vpn-server-key.pem
sudo chgrp root /etc/ipsec.d/private/vpn-server-key.pem
sudo chmod 600 /etc/ipsec.d/private/vpn-server-key.pem

All these commands are better explained in this digitalocean guide.

Configuration file

The main configuration file for strongSwan is /etc/ipsec.conf. All the configuration options for this file are well documented in the strongSwan wiki.

Let's make a backup of the original file first:

sudo cp /etc/ipsec.conf /etc/ipsec.conf.original

Below is the actual /etc/ipsec.conf I used in my setup:

conn ikev2-vpn
    auto=add
    forceencaps=yes

    mobike=yes
    ikelifetime=22h
    lifetime=23h

    # manually choosing the ciphers
    ike=aes192gcm16-aes128gcm16-prfsha256-ecp256-ecp521,aes192-sha256-modp3072
    esp=aes192gcm16-aes128gcm16-ecp256-modp3072,aes192-sha256-ecp256-modp3072

    dpdaction=clear
    dpddelay=300s
    left=%any
    leftid=@mihai.fm
    leftcert=/etc/ipsec.d/certs/vpn-server-cert.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0
    right=%any
    rightid=%any
    rightauth=eap-mschapv2
    rightdns=10.10.10.10
    rightsourceip=%dhcp
    rightsendcert=never
    eap_identity=%identity

The only things that need to be changed are:

I'm also running Pi-hole on my Raspberry-Pi, so I've set this value to the local IP address of the Pi.

Regarding the ciphers, there is more information on Atomstar's blog post, including some performance results for the various ciphers.

Adding login info

Login credentials for connecting clients can be created by editing /etc/ipsec.secrets:

mihai.fm : RSA "/etc/ipsec.d/private/vpn-server-key.pem"
YOUR_USERNAME %any% : EAP "YOUR_PASSWORD"

The file format is documented on the strongSwan wiki.

Starting ipsec

After editing /etc/ipsec.conf and /etc/ipsec.secrets, we need to start the IKE daemon used by strongSwan:

sudo ipsec start

If we make any changes to the configuration, we can reload the files with:

sudo ipsec reload

IP packet forwarding

One critical configuration item without which this setup wouldn't work, is to enable IPv4 packet forwarding in Linux. This is done by uncommenting a line in /etc/sysctl.conf

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

Enable and start the service

Finally we can enable and start strongSwan:

sudo systemctl enable strongswan
sudo systemctl start strongswan

Port forwarding

Going into our router settings, we need to make sure the following ports are open and forwarded to our VPN server:

Connecting clients

In order to connect our clients to the VPN server, we need to install server-root-ca.pem on any of the clients.

In macOS, we can simply copy the file to our device and double click on it. This will add the certificate to the keychain, after which we need to explicitly Trust it. To create the VPN connection, we can go to System Preferences -> Network -> click the + button -> set Interface to VPN.

For iOS, we can email the certificate to our self and click on the attachment in the Mail app. This will install the certificate on the phone. We can then go to Settings -> VPN -> Add VPN Configuration... and enter the credentials we configured in /etc/ipsec.secrets.

More detailed instructions on how to connect clients (including a Windows client) can be found on the digitalocean guide.

Troubleshooting

strongSwan adds log entries to the system log, which is /var/log/syslog on the Raspberry Pi, so basic troubleshooting can be done by checking this file.

There was only one weird problem that I encountered during my setup, that might be worth mentioning. I detailed the problem in this serverfault question, but basically I could not connect to the VPN if my router happened to have the same private IP address (or same network) as the Wi-Fi gateway I was connecting from (typically 192.168.0.1).

The easiest way to fix this was to configure my router with a different private IP, less likely to be encountered in the wild.

2020-06-11