A virtual private network, or VPN, allows you to securely encrypt traffic as it travels through untrusted networks, such as those at the coffee shop, a conference, or an airport.
IKEv2, or Internet Key Exchange v2, is a protocol that allows for direct IPSec tunneling between the server and client. In IKEv2 VPN implementations, IPSec provides encryption for the network traffic. IKEv2 is natively supported on new platforms (OS X 10.11+, iOS 9.1+, and Windows 10) with no additional applications necessary, and it handles client hiccups quite smoothly.
In this tutorial, you’ll set up an IKEv2 VPN server using StrongSwan on an Ubuntu 16.04 server and connect to it from Windows, iOS, and macOS clients.
To complete this tutorial, you will need:
In addition, you should be familiar with IPTables. Review How the Iptables Firewall Works before you proceed.
First, we’ll install StrongSwan, an open-source IPSec daemon which we’ll configure as our VPN server. We’ll also install the StrongSwan EAP plugin, which allows password authentication for clients, as opposed to certificate-based authentication. We’ll need to create some special firewall rules as part of this configuration, so we’ll also install a utility which allows us to make our new firewall rules persistent.
Execute the following command to install these components:
- sudo apt-get install strongswan strongswan-plugin-eap-mschapv2 moreutils iptables-persistent
Note: While installing
iptables-persistent, the installer will ask whether or not to save current IPv4 and IPv6 rules. As we want any previous firewall configurations to stay the same, we’ll select yes on both prompts.
Now that everything’s installed, let’s move on to creating our certificates:
An IKEv2 server requires a certificate to identify itself to clients. To help us create the certificate required, StrongSwan comes with a utility to generate a certificate authority and server certificates. To begin, let’s create a directory to store all the stuff we’ll be working on.
- mkdir vpn-certs
- cd vpn-certs
Now that we have a directory to store everything, let’s generate our root key. This will be a 4096-bit RSA key that will be used to sign our root certificate authority, so it’s very important that we also secure this key by ensuring that only the root user can read it.
Execute these commands to generate and secure the key:
- ipsec pki --gen --type rsa --size 4096 --outform pem > server-root-key.pem
- chmod 600 server-root-key.pem
Now that we have a key, we can move on to creating our root certificate authority, using the key to sign the root certificate:
- ipsec pki --self --ca --lifetime 3650 \
- --in server-root-key.pem \
- --type rsa --dn "C=US, O=VPN Server, CN=VPN Server Root CA" \
- --outform pem > server-root-ca.pem
You can change the distinguished name (DN) values, such as country, organization, and common name, to something else to if you want to. The common name here is just the indicator, so you could even make something up.
Later, we’ll copy the root certificate (
server-root-ca.pem) to our client devices so they can verify the authenticity of the server when they connect.
Now that we’ve got our root certificate authority up and running, we can create a certificate that the VPN server will use.
We’ll now create a certificate and key for the VPN server. This certificate will allow the client to verify the server’s authenticity.
First, create a private key for the VPN server with the following command:
- ipsec pki --gen --type rsa --size 4096 --outform pem > vpn-server-key.pem
Then create and sign the VPN server certificate with the certificate authority’s key you created in the previous step. Execute the following command, but change the Common Name (CN) and the Subject Alternate Name (SAN) field to your VPN server’s DNS name or IP address:
- 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=US, O=VPN Server, CN=server_name_or_ip" \
- --san server_name_or_ip \
- --flag serverAuth --flag ikeIntermediate \
- --outform pem > vpn-server-cert.pem
Copy the certificates to a path which would allow StrongSwan to read the certificates:
- 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
Finally, secure the keys so they can only be read by the root user.
- 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
In this step, we’ve created a certificate pair that would be used to secure communications between the client and the server. We’ve also signed the certificates with our root key, so the client will be able to verify the authenticity of the VPN server. Now that we’ve got all the certificates ready, we’ll move on to configuring the software.
We’ve already created all the certificates that we need, so it’s time to configure StrongSwan itself.
StrongSwan has a default configuration file, but before we make any changes, let’s back it up first so that we’ll have a reference file just in case something goes wrong:
- sudo cp /etc/ipsec.conf /etc/ipsec.conf.original
The example file is quite long, so to prevent misconfiguration, we’ll clear the default configuration file and write our own configuration from scratch. First, clear out the original configuration:
- echo '' | sudo tee /etc/ipsec.conf
Then open the file in your text editor:
- sudo nano /etc/ipsec.conf
First, we’ll tell StrongSwan to log daemon statuses for debugging and allow duplicate connections. Add these lines to the file:
config setup charondebug="ike 1, knl 1, cfg 0" uniqueids=no
Then, we’ll create a configuration section for our VPN. We’ll also tell StrongSwan to create IKEv2 VPN Tunnels and to automatically load this configuration section when it starts up. Append the following lines to the file:
conn ikev2-vpn auto=add compress=no type=tunnel keyexchange=ikev2 fragmentation=yes forceencaps=yes
Next, we’ll tell StrongSwan which encryption algorithms to use for the VPN. Append these lines:
We’ll also configure dead-peer detection to clear any “dangling” connections in case the client unexpectedly disconnects. Add these lines:
dpdaction=clear dpddelay=300s rekey=no
Then we’ll configure the server (left) side IPSec parameters. Add this to the file:
left=%any leftid=@server_name_or_ip leftcert=/etc/ipsec.d/certs/vpn-server-cert.pem leftsendcert=always leftsubnet=0.0.0.0/0
Note: When configuring the server ID (
leftid), only include the
@ character if your VPN server will be identified by a domain name:
If the server will be identified by its IP address, just put the IP address in:
Then we configure the client (right) side IPSec parameters, like the private IP address ranges and DNS servers to use:
right=%any rightid=%any rightauth=eap-mschapv2 rightsourceip=10.10.10.0/24 rightdns=188.8.131.52,184.108.40.206 rightsendcert=never
Finally, we’ll tell StrongSwan to ask the client for user credentials when they connect:
The configuration file should look like this:
config setup charondebug="ike 1, knl 1, cfg 0" uniqueids=no conn ikev2-vpn auto=add compress=no type=tunnel keyexchange=ikev2 fragmentation=yes forceencaps=yes ike=aes256-sha1-modp1024,3des-sha1-modp1024! esp=aes256-sha1,3des-sha1! dpdaction=clear dpddelay=300s rekey=no left=%any leftid=@server_name_or_ip 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=220.127.116.11,18.104.22.168 rightsourceip=10.10.10.0/24 rightsendcert=never eap_identity=%identity
Save and close the file once you’ve verified that you’ve configured things as shown.
Now that we’ve configured the VPN parameters, let’s move on to creating an account so our users can connect to the server.
Our VPN server is now configured to accept client connections, but we don’t have any credentials configured yet, so we’ll need to configure a couple things in a special configuration file called
Let’s open the secrets file for editing:
- sudo nano /etc/ipsec.secrets
First, we’ll tell StrongSwan where to find our private key.
server_name_or_ip : RSA "/etc/ipsec.d/private/vpn-server-key.pem"
Then we’ll create the user credentials. You can make up any username or password combination that you like, but we have to tell StrongSwan to allow this user to connect from anywhere:
your_username %any% : EAP "your_password"
Save and close the file. Now that we’ve finished working with the VPN parameters, we’ll reload the VPN service so that our configuration would be applied:
- sudo ipsec reload
Now that the VPN server has been fully configured with both server options and user credentials, it’s time to move on to configuring the most important part: the firewall.
Now that we’ve got the VPN server configured, we need to configure the firewall to forward and allow VPN traffic through. We’ll use IPTables for this.
First, disable UFW if you’ve set it up, as it can conflict with the rules we need to configure:
- sudo ufw disable
Then remove any remaining firewall rules created by UFW:
- iptables -P INPUT ACCEPT
- iptables -P FORWARD ACCEPT
- iptables -F
- iptables -Z
To prevent us from being locked out of the SSH session, we’ll accept connections that are already accepted. We’ll also open port
22 (or whichever port you’ve configured) for future SSH connections to the server. Execute these commands:
- sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
- sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
We’ll also need to accept connections on the local loopback interface:
- sudo iptables -A INPUT -i lo -j ACCEPT
Then we’ll tell IPTables to accept IPSec connections:
- sudo iptables -A INPUT -p udp --dport 500 -j ACCEPT
- sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT
Next, we’ll tell IPTables to forward ESP (Encapsulating Security Payload) traffic so the VPN clients will be able to connect. ESP provides additional security for our VPN packets as they’re traversing untrusted networks:
- 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
Our VPN server will act as a gateway between the VPN clients and the internet. Since the VPN server will only have a single public IP address, we will need to configure masquerading to allow the server to request data from the internet on behalf of the clients; this will allow traffic to flow from the VPN clients to the internet, and vice-versa:
- 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
To prevent IP packet fragmentation on some clients, we’ll tell IPTables to reduce the size of packets by adjusting the packets’ maximum segment size. This prevents issues 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
For better security, we’ll drop everything else that does not match the rules we’ve configured:
- sudo iptables -A INPUT -j DROP
- sudo iptables -A FORWARD -j DROP
Now we’ll make the firewall configuration persistent, so that all our configuration work won’t get wiped on reboot:
- sudo netfilter-persistent save
- sudo netfilter-persistent reload
Finally, we’ll enable packet forwarding on the server. Packet forwarding is what makes it possible for our server to “route” data from one IP address to the other. Essentially, we’re making our server act like a router.
Edit the file
- sudo nano /etc/sysctl.conf
We’ll need to configure a few things here:
The changes you need to make to the file are highlighted in the following code:
. . . # Uncomment the next line to enable packet forwarding for IPv4 net.ipv4.ip_forward=1 . . . # Do not accept ICMP redirects (prevent MITM attacks) net.ipv4.conf.all.accept_redirects = 0 # Do not send ICMP redirects (we are not a router) net.ipv4.conf.all.send_redirects = 0 . . . net.ipv4.ip_no_pmtu_disc = 1
Make those changes, save the file, and exit the editor. Then restart the server:
- sudo reboot
You’ll get disconnected from the server as it reboots, but that’s expected. After the server reboots, log back in to the server as the sudo, non-root user. You’re ready to test the connection on a client.
Now that you have everything set up, it’s time to try it out. First, you’ll need to copy the root certificate you created and install it on your client device(s) that will connect to the VPN. The easiest way to do this is to log into your server and execute this command to display the contents of the certificate file:
- cat ~/vpn-certs/server-root-ca.pem
You’ll see output similar to this:
Output-----BEGIN CERTIFICATE----- MIIFQjCCAyqgAwIBAgIIFkQGvkH4ej0wDQYJKoZIhvcNAQEMBQAwPzELMAkGA1UE . . . EwbVLOXcNduWK2TPbk/+82GRMtjftran6hKbpKGghBVDPVFGFT6Z0OfubpkQ9RsQ BayqOb/Q -----END CERTIFICATE-----
Copy this output to your computer, including the
-----BEGIN CERTIFICATE----- and
-----END CERTIFICATE----- lines, and save it to a file with a recognizable name, such as
vpn_root_certificate.pem. Ensure the file you create has the
Alternatively, use SFTP to transfer the file to your computer.
Once you have the
vpn_root_certificate.pem file downloaded to your computer, you can set up the connection to the VPN.
First, import the root certificate by following these steps:
WINDOWS+R to bring up the Run dialog, and enter
mmc.exe to launch the Windows Management Console.
From the File menu, navigate to Add or Remove Snap-in, select Certificates from the list of available snap-ins, and click Add.
We want the VPN to work with any user, so select Computer Account and click Next.
We’re configuring things on the local computer, so select Local Computer, then click Finish.
Under the Console Root node, expand the Certificates (Local Computer) entry, expand Trusted Root Certification Authorities, and then select the Certificates entry:
From the Action menu, select All Tasks and click Import to display the Certificate Import Wizard. Click Next to move past the introduction.
On the File to Import screen, press the Browse button and select the certificate file that you’ve saved. Then click Next.
Ensure that the Certificate Store is set to Trusted Root Certification Authorities, and click Next.
Click Finish to import the certificate.
Then configure the VPN with these steps:
Your new VPN connection will be visible under the list of networks. Select the VPN and click Connect. You’ll be prompted for your username and password. Type them in, click OK, and you’ll be connected.
To configure the VPN connection on an iOS device, follow these steps:
Follow these steps to import the certificate:
Now that the certificate is important and trusted, configure the VPN connection with these steps:
Finally, click on Connect to connect to the VPN. You should now be connected to the VPN.
If you are unable to import the certificate, ensure the file has the
.pem extention, and not
If you’re unable to connect to the VPN, check the server name or IP address you used. The server’s domain name or IP address must match what you’ve configured as the common name (CN) while creating the certificate. If they don’t match, the VPN connection won’t work. If you set up a certificate with the CN of
vpn.example.com, you must use
vpn.example.com when you enter the VPN server details. Double-check the command you used to generate the certificate, and the values you used when creating your VPN connection.
Finally, double-check the VPN configuration to ensure the
leftid value is configured with the
@ symbol if you’re using a domain name:
And if you’re using an IP address, ensure that the
@ symbol is omitted.
In this tutorial, you’ve built a VPN server that uses the IKEv2 protocol. Now you can be assured that your online activities will remain secure wherever you go!
To add or remove users, just take a look at Step 5 again. Each line is for one user, so adding or removing users is as simple as editing the file.
From here, you might want to look into setting up a log file analyzer, because StrongSwan dumps its logs into syslog. The tutorial How To Install and Use Logwatch Log Analyzer and Reporter on a VPS has more information on setting that up.
You might also be interested in this guide from the EFF about online privacy.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Click below to sign up and get $200 of credit to try our products over 60 days!
Enter your email to get $200 in credit for your first 60 days with DigitalOcean.
Five times I install this truly won’t working. Don’t waste your time with this tutorial.
$ sudo apt-get install strongswan strongswan-plugin-eap-mschapv2 moreutils iptables-persistent Reading package lists… Done Building dependency tree
Reading state information… Done E: Unable to locate package moreutils E: Unable to locate package iptables-persistent
What I should do next ?
Is there a similar guide where LetsEncrypt certificate is used instead of a self-signed one?
Sounds good, doesn’t work.
This comment has been deleted
Hi I did try with this tutorial but no luck nothing is working for me in ubuntu it is not showing any error two times formatted server to start from scratch but no luck what I am missing don’t know spent a lot of my time but not succeed. Can someone help me to configure it out?
I can connect to the VPN i set up,but i can’t connect to internet when I connected to my VPN,could you tell me what is wrong?
I’m trying to build a .mobileconfig file to put on my iphone for this setup and enable on demand connections – like this:
But I can’t seem to get it to work. Installing the profile gives me various errors. Can anyone help me build a valid .mobileconfig file that works for this setup?
Any chances to have it using (instead of disabling) ufw?
This was really helpful but one problem is the security is configured for iOS however on Android which uses StrongSwan, you need to have a higher level of security. Change the ipsec.conf file to use the following: