Connect your Linux machine to a VPN Gateway using strongSwan
In this blog post I’ll show you how to connect your local machine to a remote VPN server using the IKEv2 and IPSec protocol. Instead of the deprecated ipsec.conf
we’ll use the modern swanctl.conf
.
Why IPSec/IKEv2?
IKEv2 offers high speed and good data security with a stable connection. The protocol is one of the best.
strongSwan provides an open-source implementation of IPSec. strongSwan works on Linux, Android, FrreBSD, macOS, iOs, and Windows.
The tool natively supports forwarding and split-tunneling, thus enabling you to selectively route your traffic through the VPN connection.
Why is that useful?
With split-tunneling you can exclude your local subnets (your home network, or local Docker bridge) from the VPN gateway.
Now you can connect your local machine to the VPN server, but still have access to your wifi-connected printer.
1. Installation
Usually, the Arch wiki is a mine of gold. Unfortunately, the wiki solely describes how to setup a connection with ipsec.conf and ipsec starter.
The newly available swanctl and vici plugin provide a better experience in combination with systemd and strongSwan’s plugins.
In this article, I’ll show you a sample ipsec.conf
with pre-shared keys (EAP), and how to migrate the configuration to swanctl.
We’ll assume that you have access to a remote VPN server, either your own implementation or a commercial provider like NordVPN.
We’ll use yay to install strongSwan:
yay -S strongswan
2. Configuration
1. ipsec/swanctl
Example ipsec.conf
with username and password (NordVPN uses a different approach, see below):
conn vpn
keyexchange=ikev2
dpdaction=clear
dpddelay=300s
eap_identity="<your-username>"
leftauth=eap-mschapv2
left=%defaultroute
leftsourceip=%config
right=<server.name.com>
rightauth=pubkey
rightsubnet=0.0.0.0/0
rightid=%any
type=tunnel
auto=add
Here’s how the configuration translates to swanctl.conf
(on your machine: /etc/swanctl/swanctl.conf
or similar):
connections {
vpn {
version = 2
proposals = aes192gcm16-aes128gcm16-prfsha256-ecp256-ecp521,aes192-sha256-modp3072,default
rekey_time = 0s
fragmentation = yes
dpd_delay = 300s
local_addrs = %defaultroute
remote_addrs = <server.name.com>
vips=0.0.0.0,::
local {
auth = eap-mschapv2
eap_id = "<your-username>"
}
remote {
auth = pubkey
id = %any
}
children {
vpn {
remote_ts = 0.0.0.0/0,::/0
rekey_time = 0s
dpd_action = clear
esp_proposals = aes192gcm16-aes128gcm16-prfsha256-ecp256-modp3072,aes192-sha256-ecp256-modp3072,default
}
}
}
}
secrets {
eap-vpn {
id = "<your-username>"
secret = "<your-password>"
}
}
Don’t forget to replace the remote_addr
with the real server name.
Replace <your-username>
and <your-password>
, too.
Here’s another example configuration where we use a username and certifictate instead of username/password in the ipsec.conf
(NordVPN):
conn NordVPN
keyexchange=ikev2
dpdaction=clear
dpddelay=300s
eap_identity="<your-username>"
leftauth=eap-mschapv2
left=%defaultroute
leftsourceip=%config
right=<server.name.com>
rightauth=pubkey
rightsubnet=0.0.0.0/0
rightid=%any
rightca=/etc/ipsec.d/cacerts/NordVPN.pem
type=tunnel
auto=add
For etc/swanctl/swanctl.conf
:
connections {
nordvpn {
version = 2
proposals = aes192gcm16-aes128gcm16-prfsha256-ecp256-ecp521,aes192-sha256-modp3072,default
rekey_time = 0s
fragmentation = yes
dpd_delay = 300s
local_addrs = %defaultroute
remote_addrs = <server.name.com>
vips=0.0.0.0,::
local {
auth = eap-mschapv2
eap_id = "<your-username>"
}
remote {
auth = pubkey
cacerts=/etc/ipsec.d/cacerts/NordVPN.pem
id = %any
}
children {
nordvpn {
remote_ts = 0.0.0.0/0,::/0
rekey_time = 0s
dpd_action = clear
esp_proposals = aes192gcm16-aes128gcm16-prfsha256-ecp256-modp3072,aes192-sha256-ecp256-modp3072,default
}
}
}
2. Constraints Plugin
You might also want to disable the constraints plugin:
sudo sed -i 's/load = yes/load = no/g' /etc/strongswan.d/charon/constraints.conf
Make sure that your strongSwan basic configuration respects that setting (/etc/strongswan.conf
):
## strongswan.conf - strongSwan configuration file
#
## Refer to the strongswan.conf(5) manpage for details
#
## Configuration changes should be made in the included files
charon-systemd {
threads = 16
plugins {
include strongswan.d/charon/*.conf
}
}
include strongswan.d/*.conf
3. Get Certificates
Your local machine needs a certificate for the VPN server.
With NordVPN you have to download their certificate:
sudo wget https://downloads.nordvpn.com/certificates/root.der -O /etc/ipsec.d/cacerts/NordVPN.der
sudo openssl x509 -inform der -in /etc/ipsec.d/cacerts/NordVPN.der -out /etc/ipsec.d/cacerts/NordVPN.pem
With other providers it might suffice to link the standard OpenSSL certificates with the IPSec certs:
sudo rmdir /etc/ipsec.d/cacerts
sudo ln -s /etc/ssl/certs /etc/ipsec.d/cacerts
4. Restart strongSwan
strongSwan has a systemd script:
sudo systemctl restart strongswan
You can also enable the script for starting strongSwan on boot:
sudo systemctl enable strongswan
You can use the tool via the swanctl
command line utility. For example:
## starts the connection and the remote children setup
sudo swanctl -i -c <name-of-children-connection>
## stops the complete connection
sudo swanctl -t -i <name-of-the-connection>
Example:
sudo swanctl -i -c nordvpn
5. Test Connection
In your browser, go to ipleak.net.