Setting up an IKEv2 (strongSwan) VPN server
Contents
A side entry in the VPN setup notes series. I found some old notes on IKEv2, so here they are.
Note: IKEv2 is IPSec-based, which makes it easily detectable by China’s GFW (Great Firewall). Not recommended for connections into or out of China. This guide targets environments without censorship, such as domestic use in Japan.
What is IKEv2?
IKEv2 (Internet Key Exchange version 2) is a key exchange protocol for IPSec VPN. It excels at reconnecting on mobile devices and has native support on iOS, macOS, and Windows.
How it compares to other protocols:
- IKEv2: IPSec-based. Mobile-friendly. Supported natively by major OSes
- OpenConnect: SSL/TLS-based. Can masquerade as HTTPS traffic
- WireGuard: Custom protocol. Simple and fast
Server setup
These steps are for CentOS 7, using strongSwan.
Installation
yum -y install epel-release
yum -y install strongswan
yum update -y openssl
If the package is not found:
yum clean all
# Try again
Certificate placement
Place certificates obtained from Let’s Encrypt.
# Server certificate
vi /etc/strongswan/ipsec.d/certs/cert.pem
# Intermediate certificate (CA)
vi /etc/strongswan/ipsec.d/cacerts/chain.pem
# Private key
vi /etc/strongswan/ipsec.d/private/privkey.pem
Note: Let’s Encrypt certificates expire every 3 months. Make sure certbot auto-renewal is configured.
ipsec.conf
vi /etc/strongswan/ipsec.conf
# Add connections here.
conn %default
keyexchange=ikev2
ike=aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024!
esp=aes128gcm16-ecp256,aes256gcm16-ecp384,aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024,aes128gcm16,aes256gcm16,aes128-sha256,aes128-sha1,aes256-sha384,aes256-sha256,aes256-sha1!
dpdaction=clear
dpddelay=300s
rekey=no
conn IPSec-IKEv2
keyexchange=ikev2
left=%any
leftsubnet=0.0.0.0/0
leftid=vpn.example.com
leftcert=cert.pem
leftsendcert=always
right=%any
rightid=%any
rightdns=1.1.1.1,8.8.8.8
rightsourceip=192.168.10.0/19
auto=add
conn IPSec-IKEv2-EAP
also="IPSec-IKEv2"
rightauth=eap-mschapv2
eap_identity=%any
auto=add
Key points:
- Change
leftidto your server’s domain name rightsourceipdefines the IP range assigned to clientsrightdnsspecifies the DNS servers distributed to clients
ipsec.secrets
vi /etc/strongswan/ipsec.secrets
# ipsec.secrets - strongSwan IPsec secrets file
: RSA privkey.pem
username : EAP "password"
To add more users, append lines in the same format:
user1 : EAP "password1"
user2 : EAP "password2"
Logging configuration
vi /etc/strongswan/strongswan.d/charon-logging.conf
# Default loglevel.
default = 2
# flush_line = no
flush_line = yes
# time_format =
time_format = %F %T
Kernel parameters
vi /etc/sysctl.conf
net.ipv4.ip_forward=1
Apply the settings:
sysctl -p
File descriptor limits
vi /etc/security/limits.conf
root soft nofile 51200
root hard nofile 51200
Firewall configuration
Using firewalld:
firewall-cmd --permanent --zone=public --add-service=ipsec
firewall-cmd --permanent --zone=public --add-port=500/udp
firewall-cmd --permanent --zone=public --add-port=4500/udp
firewall-cmd --permanent --add-masquerade
firewall-cmd --direct --permanent --add-rule ipv4 mangle FORWARD 1 -p tcp -m tcp --tcp-flags SYN,RST SYN -s 192.168.10.0/19 -m tcpmss --mss 1301:1536 -j TCPMSS --set-mss 1300
echo 1 >/proc/sys/net/ipv4/ip_no_pmtu_disc
firewall-cmd --reload
If firewalld is inactive, start it first:
systemctl status firewalld
systemctl start firewalld
systemctl enable firewalld
Starting the service
systemctl enable strongswan
systemctl start strongswan
Client configuration
iOS / macOS
Settings > VPN > Add VPN Configuration > IKEv2
- Server: vpn.example.com
- Remote ID: vpn.example.com
- Local ID: (leave blank)
- User Authentication: Username
- Username: as set in ipsec.secrets
- Password: as set in ipsec.secrets
Windows
Settings > Network & Internet > VPN > Add a VPN connection
- VPN provider: Windows (built-in)
- Connection name: anything
- Server name or address: vpn.example.com
- VPN type: IKEv2
- Type of sign-in info: User name and password
Android
Settings > Network & Internet > VPN > Add VPN
- Name: anything
- Type: IKEv2/IPSec MSCHAPv2
- Server address: vpn.example.com
- IPSec identifier: vpn.example.com
User management script
A script for managing a large number of users:
vi ikev2.sh
#!/bin/bash
cd /etc/strongswan
rm -f ipsec.secrets
wget -O ipsec.secrets https://example.com/api/users
systemctl stop strongswan
systemctl start strongswan
chmod +x ikev2.sh
./ikev2.sh
Notes for 2025 and beyond
Using IKEv2 in China
IKEv2 is not recommended for connections to/from China.
Reasons:
- The IPSec protocol is easily detected by the GFW
- UDP ports 500/4500 are distinctive signatures
- In 2024, Microsoft deprecated L2TP/IPsec (same IPSec family)
For China, consider OpenConnect or V2Ray instead.
IKEv3
IKEv3 has been proposed as RFC 9370 but is still in draft. IKEv2 will remain the practical choice for the foreseeable future.
Recommended use cases
Where IKEv2 works well:
- VPN within Japan or other environments without censorship
- When you want native OS support on iOS / macOS / Windows
- When stable reconnection on mobile devices is needed
Related: Comparison of VPN protocols for bypassing China’s GFW