IKEv2 VPN server with strongSwan and Let’s Encrypt
VPN helps to secure your Internet connection. There are many cases when you want your network traffic to be encrypted to prevent stealing your sensitive data, e.g., public Wi-FI networks. Numerous of VPN protocols exist. Most popular are PPTP, L2TP/IPsec, OpenVPN and IKEv2. In this guide I will explain setting up IKEv2 VPN server with strongSwan and Let’s Encrypt certificate with automatic renewal configuration.
IKEv2 stands for Internet Key Exchange protocol version 2. The protocol works natively on macOS, iOS, Windows. Several IKEv2 implementations exist for Android, Blackberry and Linux. The key strength of this protocol is resistance to network change, so VPN connection will remain established after you change the network, e.g., from cellular to Wi-FI.
Prerequisites
For this tutorial you need VPS with Linux (DigitalOcean provides machines starting at $5/month) and domain. This guide covers the following software versions:
- Ubuntu 16.04 LTS
- strongSwan 5.3.5
- Certbot 0.26.1
Installing strongSwan
strongSwan is an open source IPsec implementation with full support of IKEv2 protocol. Let’s install it:
sudo apt-get update
sudo apt-get install strongswan strongswan-plugin-eap-mschapv2
Installing Certbot and obtaining Let’s Encrypt certificate
You can generate your own certificate if you don’t have a domain. The only drawback is that you will need to install your root certificate on any client, which will use your VPN server. This case is not covered in this guide.
If you have a domain, you can buy or use a free certificate provided by Let’s Encrypt certificate authority (CA). Let’s Encrypt issues a certificate which is valid for 90 days. After the certificate expires, you will have to renew it. Fortunately the process of certificate obtaining and renewal can be automated with Certbot utility.
Certbot packages in Ubuntu are old, so we will add PPA and install newer verision of utility:
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot
Next we will obtain the certificate. Replace yourdomain with your domain name:
sudo certbot certonly --standalone -d yourdomain
Your certificate and private key will be stored in /etc/letsencrypt/live/yourdomain.
Certbot will handle automatic certificate renewal process for you. Let’s create symbolic links to the files so you will not have to manually copy them to make available to strongSwan after every renewal:
sudo ln -s /etc/letsencrypt/live/yourdomain/chain.pem /etc/ipsec.d/cacerts/ca.pem
sudo ln -s /etc/letsencrypt/live/yourdomain/cert.pem /etc/ipsec.d/certs/certificate.pem
sudo ln -s /etc/letsencrypt/live/yourdomain/privkey.pem /etc/ipsec.d/private/key.pem
To restart strongSwan after successful certificate renewal edit file /lib/systemd/system/certbot.service and change this line to:
ExecStart=/usr/bin/certbot renew --deploy-hook "systemctl restart strongswan.service"
Reload systemctl daemon for the changes to take effect:
sudo systemctl daemon-reload
Configuring strongSwan
Next thing we need to do is to edit /etc/ipsec.conf:
config setup
charondebug="ike 1, knl 1, cfg 1"
conn ikev2-vpn
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
ike=aes256-sha1-modp1024
esp=aes256-sha1
dpdaction=clear
dpddelay=30s
rekey=no
left=%any
leftid=@yourdomain
leftcert=certificate.pem
leftsendcert=always
leftsubnet=0.0.0.0/0
right=%any
rightid=%any
rightauth=eap-mschapv2
rightsourceip=10.10.10.0/24
rightdns=8.8.8.8,8.8.4.4
rightsendcert=never
eap_identity=%identity
For the configuration parameters explanation refer to General Connection Parameters.
Configuring authentication
Now we have to add users to be able to connect to our VPN server. Edit /etc/ipsec.secrets file and replace username and password with client user name and password:
yourdomain : RSA key.pem
username %any% : EAP "password"
You can add more users by inserting additional lines. In order for changes to take effect you don’t have to reload the daemon. Just run:
sudo ipsec rereadsecrets
Disabling AppArmor profile
AppArmor strongSwan profiles cause problems with permissions. As a result, when daemon tries to read certificate or private key you will get Permission denied error. You can check if AppArmor is running:
sudo apparmor_status
If you see profiles /etc/apparmor.d/usr.lib.ipsec.charon or /etc/apparmor.d/usr.lib.ipsec.stroke, you should remove them:
sudo ln -s /etc/apparmor.d/usr.lib.ipsec.charon /etc/apparmor.d/disable/
sudo ln -s /etc/apparmor.d/usr.lib.ipsec.stroke /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/usr.lib.ipsec.charon
sudo apparmor_parser -R /etc/apparmor.d/usr.lib.ipsec.stroke
Restarting and checking strongSwan status
After we successfully configured strongSwan, we can restart the service and check if it’s up and running:
sudo ipsec statusall
Status of IKE charon daemon (strongSwan 5.3.5, Linux 4.4.0-128-generic, x86_64):
uptime: 31 minutes, since Oct 12 14:09:04 2018
malloc: sbrk 1761280, mmap 0, used 568912, free 1192368
worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 0
loaded plugins: charon test-vectors aes rc2 sha1 sha2 md4 md5 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl fips-prf gmp agent xcbc hmac gcm attr kernel-netlink resolve socket-default connmark farp stroke updown eap-identity eap-sim eap-sim-pcsc eap-aka eap-aka-3gpp2 eap-simaka-pseudonym eap-simaka-reauth eap-md5 eap-gtc eap-mschapv2 eap-dynamic eap-radius eap-tls eap-ttls eap-peap eap-tnc xauth-generic xauth-eap xauth-pam xauth-noauth tnc-tnccs tnccs-20 tnccs-11 tnccs-dynamic dhcp lookip error-notify certexpire led addrblock unity
Virtual IP pools (size/online/offline):
10.10.10.0/24: 254/0/2
Listening IP addresses:
youripaddress
Connections:
ikev2-vpn: %any...%any IKEv2, dpddelay=30s
ikev2-vpn: local: [yourdomain] uses public key authentication
ikev2-vpn: cert: "CN=yourdomain"
ikev2-vpn: remote: uses EAP_MSCHAPV2 authentication with EAP identity '%any'
ikev2-vpn: child: 0.0.0.0/0 === dynamic TUNNEL, dpdaction=clear
Security Associations (0 up, 0 connecting):
none
sudo ipsec listcerts
List of X.509 End Entity Certificates:
altNames: yourdomain
subject: "CN=yourdomain"
issuer: "C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3"
serial: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
validity: not before Sep 19 23:58:54 2018, ok
not after Dec 18 23:58:54 2018, ok
pubkey: RSA 2048 bits, has private key
keyid: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
subjkey: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
authkey: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
If something went wrong you can check the logs with:
sudo journalctl -u strongswan.service
Configuring iptables
Next thing we need to do is to configure iptables properly to close all ports which we don’t need and to set up masquerading to redirect all client traffic through VPN server.
First we clear all iptables rules:
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables -Z
We need to open ports TCP 22 (SSH), TCP 80, 443 (Certbot), UDP 500, 4500 (IPsec):
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 500 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT
Enable Encapsulating Security Payload (ESP) forwarding and traffic masquerading:
sudo iptables -A FORWARD --match policy --pol ipsec --dir in --proto esp -s 10.10.10.10/24 -j ACCEPT
sudo iptables -A FORWARD --match policy --pol ipsec --dir out --proto esp -d 10.10.10.10/24 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 10.10.10.10/24 -o eth0 -m policy --pol ipsec --dir out -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 10.10.10.10/24 -o eth0 -j MASQUERADE
Also we should adjust packet maximum segment size to prevent problems with some VPN clients:
sudo iptables -t mangle -A FORWARD --match policy --pol ipsec --dir in -s 10.10.10.10/24 -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
Finally we will drop other packets:
sudo iptables -A INPUT -j DROP
sudo iptables -A FORWARD -j DROP
These iptables rules will be lost after restart. So in order to make them persistent:
sudo apt-get install iptables-persistent
sudo netfilter-persistent save
sudo netfilter-persistent reload
Configuring IPv4 forwarding
Add or change the following parameters in /etc/sysctl.conf to enable IPv4 forwaring, disable ICMP redirects sending/receiving and disable Path MTU discovery to prevent the man-in-the-middle attacks:
net.ipv4.ip_forward=1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.ip_no_pmtu_disc = 1
Finally reboot the system:
sudo reboot
Configuring VPN client connection
macOS 10.12 and iOS 11
Setting connection in macOS and iOS is simple using my Python script generate-mobileconfig.py. To generate Apple Configuration file, execute the script with the following arguments:
./generate-mobileconfig.py username userpassword yourdomain
Windows 8.1
Setting connection in Windows 8.1 is pretty straightforward. Just set up a new VPN connection, then enter your hostname, user name and password.
Android
Download strongSwan VPN Client from Google Play.