Introduction
IPsec is the VPN protocol built into every major OS โ Windows, macOS, iOS, and Android all support IKEv2/IPsec natively, with no client software needed. This makes it ideal for mobile device VPNs and enterprise deployments. strongSwan is the leading open-source IPsec implementation on Linux.
IPsec vs WireGuard vs OpenVPN:
- IPsec: Native OS support, no client install, complex config
- WireGuard: Fastest, simplest, needs client app
- OpenVPN: Best firewall traversal, needs client app
IPsec Architecture
IKE (Internet Key Exchange):
Phase 1 (IKE SA): Authenticate peers, establish secure channel
Phase 2 (Child SA): Negotiate encryption for actual data
Data plane:
ESP (Encapsulating Security Payload): Encrypts + authenticates data
AH (Authentication Header): Authenticates only (rarely used)
Modes:
Transport mode: Encrypts payload only (host-to-host)
Tunnel mode: Encrypts entire IP packet (gateway-to-gateway, VPN)
Install strongSwan
sudo apt update
sudo apt install strongswan strongswan-pki libcharon-extra-plugins
# Verify
ipsec version
Generate Certificates
# Create PKI directory
mkdir -p ~/pki/{cacerts,certs,private}
chmod 700 ~/pki
# 1. Generate CA key and certificate
ipsec pki --gen --type ecdsa --size 256 --outform pem > ~/pki/private/ca.key.pem
ipsec pki --self --ca --lifetime 3650 \
--in ~/pki/private/ca.key.pem --type ecdsa \
--dn "CN=VPN CA, O=My Company" \
--outform pem > ~/pki/cacerts/ca.cert.pem
# 2. Generate server key and certificate
ipsec pki --gen --type ecdsa --size 256 --outform pem > ~/pki/private/server.key.pem
ipsec pki --pub --in ~/pki/private/server.key.pem --type ecdsa | \
ipsec pki --issue --lifetime 1825 \
--cacert ~/pki/cacerts/ca.cert.pem \
--cakey ~/pki/private/ca.key.pem \
--dn "CN=vpn.example.com, O=My Company" \
--san vpn.example.com \
--flag serverAuth --flag ikeIntermediate \
--outform pem > ~/pki/certs/server.cert.pem
# 3. Copy to strongSwan directories
sudo cp ~/pki/cacerts/ca.cert.pem /etc/ipsec.d/cacerts/
sudo cp ~/pki/certs/server.cert.pem /etc/ipsec.d/certs/
sudo cp ~/pki/private/server.key.pem /etc/ipsec.d/private/
sudo chmod 600 /etc/ipsec.d/private/server.key.pem
Server Configuration
IKEv2 with EAP (Username/Password for Mobile Clients)
sudo nano /etc/ipsec.conf
# /etc/ipsec.conf
config setup
charondebug="ike 1, knl 1, cfg 0"
uniqueids=never
# IKEv2 with EAP-MSCHAPv2 (works with Windows, macOS, iOS, Android natively)
conn ikev2-eap
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
# Server side
left=%any
[email protected]
leftcert=server.cert.pem
leftsendcert=always
leftsubnet=0.0.0.0/0
# Client side
right=%any
rightid=%any
rightauth=eap-mschapv2
rightsourceip=10.10.10.0/24
rightdns=1.1.1.1,8.8.8.8
rightsendcert=never
# Crypto (modern, strong)
ike=aes256gcm16-sha256-ecp256!
esp=aes256gcm16-sha256!
# Timeouts
dpdaction=clear
dpddelay=300s
rekey=no
eap_identity=%identity
# /etc/ipsec.secrets โ user credentials
sudo nano /etc/ipsec.secrets
# /etc/ipsec.secrets
# Server certificate private key
: RSA server.key.pem
# VPN users (username : EAP "password")
alice : EAP "alice-password-123"
bob : EAP "bob-secure-pass"
# Enable IP forwarding
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# NAT for VPN clients
sudo iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o eth0 -j ACCEPT
# Start strongSwan
sudo systemctl enable --now strongswan-starter
sudo ipsec status
Site-to-Site IPsec
# /etc/ipsec.conf โ Site A (192.168.1.0/24)
conn site-to-site
auto=start
type=tunnel
keyexchange=ikev2
# Site A
left=203.0.113.1 # Site A's public IP
leftsubnet=192.168.1.0/24 # Site A's LAN
[email protected]
# Site B
right=203.0.113.2 # Site B's public IP
rightsubnet=192.168.2.0/24 # Site B's LAN
[email protected]
# Authentication
authby=secret # or: authby=rsasig for certificates
# Crypto
ike=aes256gcm16-sha256-ecp256!
esp=aes256gcm16-sha256!
# Keep alive
dpdaction=restart
dpddelay=30s
dpdtimeout=120s
# /etc/ipsec.secrets โ pre-shared key
@site-a.example.com @site-b.example.com : PSK "very-long-random-preshared-key-here"
Client Configuration
Windows (Built-in IKEv2)
# PowerShell โ add VPN connection
Add-VpnConnection -Name "My VPN" `
-ServerAddress "vpn.example.com" `
-TunnelType "IKEv2" `
-AuthenticationMethod "EAP" `
-EncryptionLevel "Required" `
-RememberCredential $true
# Import CA certificate (required for certificate auth)
Import-Certificate -FilePath "ca.cert.pem" `
-CertStoreLocation "Cert:\LocalMachine\Root"
macOS (Built-in IKEv2)
System Preferences โ Network โ + โ VPN โ IKEv2
Server Address: vpn.example.com
Remote ID: vpn.example.com
Authentication: Username
Username: alice
Password: alice-password-123
iOS/Android
Both support IKEv2 natively in Settings โ VPN.
Linux (networkmanager-strongswan)
sudo apt install network-manager-strongswan
# Or configure manually
sudo nano /etc/ipsec.conf
# Linux client config
conn my-vpn
auto=start
keyexchange=ikev2
left=%any
leftauth=eap-mschapv2
leftsourceip=%config
right=vpn.example.com
rightauth=pubkey
rightcert=ca.cert.pem
[email protected]
eap_identity=alice
# /etc/ipsec.secrets
alice : EAP "alice-password-123"
Certificate-Based Authentication (More Secure)
# Generate client certificate
ipsec pki --gen --type ecdsa --size 256 --outform pem > ~/pki/private/alice.key.pem
ipsec pki --pub --in ~/pki/private/alice.key.pem --type ecdsa | \
ipsec pki --issue --lifetime 825 \
--cacert ~/pki/cacerts/ca.cert.pem \
--cakey ~/pki/private/ca.key.pem \
--dn "CN=alice, O=My Company" \
--outform pem > ~/pki/certs/alice.cert.pem
# Create PKCS12 bundle for client import
openssl pkcs12 -export \
-inkey ~/pki/private/alice.key.pem \
-in ~/pki/certs/alice.cert.pem \
-certfile ~/pki/cacerts/ca.cert.pem \
-out alice.p12 \
-passout pass:client-password
# Server config for certificate auth
conn ikev2-cert
auto=add
keyexchange=ikev2
left=%any
[email protected]
leftcert=server.cert.pem
leftsendcert=always
leftsubnet=0.0.0.0/0
right=%any
rightauth=pubkey
rightsourceip=10.10.10.0/24
rightdns=1.1.1.1
ike=aes256gcm16-sha256-ecp256!
esp=aes256gcm16-sha256!
Monitoring and Troubleshooting
# Check connection status
sudo ipsec status
sudo ipsec statusall
# Show Security Associations
sudo ip xfrm state
sudo ip xfrm policy
# Real-time logs
sudo journalctl -u strongswan-starter -f
# Test connectivity
ping 10.10.10.1 # ping VPN server from client
# Debug mode (verbose)
sudo ipsec stop
sudo ipsec start --nofork # runs in foreground with full debug output
# Common issues:
# "no proposal chosen" โ cipher mismatch, check ike= and esp= settings
# "authentication failed" โ wrong credentials or certificate issue
# "no route to host" โ check IP forwarding and NAT rules
# "CHILD_SA failed" โ check esp= cipher settings
Revoking Access
# Revoke a user's certificate
ipsec pki --revoke --cacert ~/pki/cacerts/ca.cert.pem \
--cakey ~/pki/private/ca.key.pem \
--cert ~/pki/certs/alice.cert.pem \
--outform pem > ~/pki/crls/crl.pem
# Copy CRL to strongSwan
sudo cp ~/pki/crls/crl.pem /etc/ipsec.d/crls/
# Reload
sudo ipsec reload
# For EAP users: just remove from /etc/ipsec.secrets and reload
sudo ipsec reload
Comments