IPsec VPN with strongSwan on Linux
IPsec is the standard suite of protocols for network-layer encryption, built into every major operating system and most enterprise routers and firewalls. strongSwan is the leading open-source IKE daemon for Linux, supporting IKEv1, IKEv2, certificate and PSK authentication, and both site-to-site and road-warrior (remote access) topologies.
This guide covers installation, IKEv2 configuration with certificate authentication, site-to-site tunnels, and road-warrior setups with virtual IP pools.
Part of the VPN and SSH guide series. See also: WireGuard Setup | OpenVPN Guide | VPN Protocol Comparison
Installation
# Debian / Ubuntu
sudo apt update
sudo apt install strongswan strongswan-pki libcharon-extra-plugins
# RHEL / Fedora
sudo dnf install strongswan
Verify:
ipsec version
# strongSwan 5.x ...
PKI: Generating Certificates
strongSwan includes pki for certificate management. Create a self-signed CA
and server certificate:
# Create directories
mkdir -p ~/pki/{cacerts,certs,private}
chmod 700 ~/pki
# CA private key and self-signed certificate
pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/ca-key.pem
pki --self --ca --lifetime 3650 --in ~/pki/private/ca-key.pem \
--type rsa --dn "CN=VPN Root CA" --outform pem > ~/pki/cacerts/ca-cert.pem
# Server key and certificate signed by the CA
pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/server-key.pem
pki --pub --in ~/pki/private/server-key.pem --type rsa |
pki --issue --lifetime 1825 \
--cacert ~/pki/cacerts/ca-cert.pem \
--cakey ~/pki/private/ca-key.pem \
--dn "CN=vpn.example.com" \
--san vpn.example.com \
--flag serverAuth --flag ikeIntermediate \
--outform pem > ~/pki/certs/server-cert.pem
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/
Client certificate
pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/client1-key.pem
pki --pub --in ~/pki/private/client1-key.pem --type rsa |
pki --issue --lifetime 1825 \
--cacert ~/pki/cacerts/ca-cert.pem \
--cakey ~/pki/private/ca-key.pem \
--dn "[email protected]" \
--san [email protected] \
--outform pem > ~/pki/certs/client1-cert.pem
Core Configuration: ipsec.conf
Create /etc/ipsec.conf:
config setup
charondebug="ike 2, knl 2, cfg 2"
uniqueids=no
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
authby=pubkey
# ── Site-to-site tunnel ──────────────────────────
conn site-to-site
left=%defaultroute
leftcert=server-cert.pem
leftsubnet=10.1.0.0/24
[email protected]
right=203.0.113.50
rightsubnet=10.2.0.0/24
[email protected]
auto=start
# ── Road-warrior (remote access) ─────────────────
conn roadwarrior
left=%defaultroute
leftcert=server-cert.pem
leftsubnet=0.0.0.0/0
[email protected]
right=%any
rightauth=pubkey
rightsourceip=10.10.10.0/24
rightdns=1.1.1.1,9.9.9.9
auto=add
Directive reference
| Directive | Meaning |
|---|---|
left / right |
Local / remote endpoint. %defaultroute auto-detects. |
leftcert |
Certificate file (looked up in /etc/ipsec.d/certs/). |
leftsubnet |
Traffic selectors -- which subnets sit behind this endpoint. |
rightsourceip |
Virtual IP pool for road-warrior clients. |
auto=start |
Initiate the tunnel at startup. |
auto=add |
Load the connection but wait for the remote side to initiate. |
Secrets: ipsec.secrets
For certificate-based auth, point to the private key:
# /etc/ipsec.secrets
: RSA server-key.pem
For PSK (pre-shared key) authentication instead:
# /etc/ipsec.secrets
@vpn.example.com @remote.example.com : PSK "V3ryS3cur3Passphrase!"
Set restrictive permissions:
sudo chmod 600 /etc/ipsec.secrets
IP Forwarding and Firewall
# Persistent forwarding
cat <<'EOF' | sudo tee /etc/sysctl.d/99-ipsec.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
EOF
sudo sysctl --system
# Allow IPsec traffic (nftables example)
sudo nft add rule inet filter input udp dport { 500, 4500 } accept
sudo nft add rule inet filter input ip protocol { esp, ah } accept
Starting and Managing the Tunnel
sudo systemctl enable --now strongswan-starter
# or on newer installs:
sudo systemctl enable --now strongswan
# Check SA status
sudo ipsec statusall
# Manually bring up a connection
sudo ipsec up site-to-site
# Tear down
sudo ipsec down site-to-site
# Reload config after editing
sudo ipsec reload
Example status output:
Security Associations (1 up, 0 connecting):
site-to-site[1]: ESTABLISHED 5 minutes ago, 10.1.0.1[vpn.example.com]...203.0.113.50[remote.example.com]
site-to-site{1}: INSTALLED, TUNNEL, ESP SPIs: c1a2b3d4_i 5e6f7a8b_o
site-to-site{1}: 10.1.0.0/24 === 10.2.0.0/24
Road-Warrior Client (Linux)
On the client install strongSwan and copy the CA cert plus the client key and
cert. Create /etc/ipsec.conf:
conn myvpn
keyexchange=ikev2
left=%defaultroute
leftauth=pubkey
leftcert=client1-cert.pem
[email protected]
right=vpn.example.com
rightauth=pubkey
[email protected]
rightsubnet=0.0.0.0/0
auto=start
sudo ipsec up myvpn
For Windows and macOS clients, export the CA certificate and a PKCS#12
bundle (openssl pkcs12 -export ...) and import them into the native VPN
settings. Both support IKEv2 natively.
Troubleshooting
Increase debug output:
# ipsec.conf
config setup
charondebug="ike 4, knl 4, cfg 4, net 4"
Then watch the log:
journalctl -u strongswan -f
| Symptom | Fix |
|---|---|
NO_PROPOSAL_CHOSEN |
Cipher mismatch. Ensure both sides offer the same IKE and ESP proposals. |
AUTHENTICATION_FAILED |
Certificate not trusted. Verify the CA cert is in /etc/ipsec.d/cacerts/. |
TS_UNACCEPTABLE |
Traffic selector mismatch -- check leftsubnet/rightsubnet. |
| SA established but no traffic | Missing firewall rule for ESP, or IP forwarding disabled. |
Return to the VPN and SSH hub for more guides, or continue with the VPN Protocol Comparison.