How to Install strongSwan IPsec VPN on Ubuntu 24.04 — IKEv2 Remote Access & Site-to-Site
IPsec with IKEv2 is the standards-based VPN protocol that every modern operating system speaks natively. Unlike WireGuard or OpenVPN, which require a third-party client, IKEv2 connects directly from the built-in VPN settings on iOS, macOS, Windows, Android, and Linux. This guide walks you through installing strongSwan on an Ubuntu 24.04 VPS, building a complete certificate authority with the pki tool, configuring an IKEv2 road-warrior server with EAP-MSCHAPv2 authentication, generating client profiles for every major platform, and extending the setup with a site-to-site tunnel.
Want a VPN without the moving parts? Most home users only need an encrypted tunnel and a new IP. Deploy WireGuard in 15 minutes or OpenConnect for SSL-based access. strongSwan is the right choice when you need native OS integration, site-to-site tunnels, or enterprise authentication.
Table of Contents
What is strongSwan?
strongSwan is the leading open-source IPsec implementation for Linux, FreeBSD, macOS, Windows, and Android. It implements the full IKEv1 and IKEv2 key exchange protocols, the IPsec kernel interfaces (XFRM on Linux), and a comprehensive set of authentication methods including X.509 certificates, pre-shared keys, EAP-MSCHAPv2, EAP-TLS, EAP-Radius, and PKCS#11 hardware tokens. It is the reference IKEv2 implementation in many enterprise and carrier networks.
The project has a long pedigree — it forked from FreeS/WAN in 2005 and has been actively maintained ever since by Andreas Steffen and the strongSwan team. Version 5.9+ introduces swanctl, a modern configuration and control utility that replaced the legacy ipsec.conf / ipsec secrets files. This tutorial uses the modern swanctl interface throughout.
strongSwan is what you use when:
- You need a road-warrior VPN that mobile devices connect to from the native OS settings (no app install, no sideloaded configuration).
- You need site-to-site tunnels between offices, data centers, or cloud VPCs over the public internet.
- You need standards compliance — IKEv2 is defined in RFC 7296, and strongSwan implements the full spec including MOBIKE (RFC 4555) for seamless network handovers.
- You need EAP-Radius integration to authenticate VPN users against an existing corporate directory or 2FA system.
- You need IPv6 support, DPD (dead peer detection), NAT traversal, and other features that have been battle-tested for two decades.
Why Self-Host IPsec vs WireGuard?
WireGuard is the new hotness in VPN-land — it is faster, simpler, and has a smaller attack surface. But strongSwan/IPsec still wins in several scenarios:
- Native OS support. IKEv2 is built into iOS, iPadOS, macOS, Windows 10/11, Android (via the stock VPN menu since 12+), and Linux NetworkManager. Users connect from the system VPN settings without installing any app. WireGuard requires a third-party app on every platform.
- Zero-touch mobile deployment. With a
.mobileconfig(iOS/macOS) or.sswanprofile, the entire VPN — server address, CA certificate, client cert, EAP username — is provisioned with a single tap. WireGuard requires QR code scanning and manual profile management. - MOBIKE roaming. IKEv2 with MOBIKE lets a phone switch between Wi-Fi and cellular without tearing down the tunnel. WireGuard reconnects on every network change.
- Corporate authentication. strongSwan plugs into RADIUS, Active Directory, and TOTP-based 2FA out of the box. WireGuard requires bolt-on tools like
wg-portalorTailscale. - Site-to-site standards. IPsec is the industry standard for interconnecting offices, Cisco ASAs, FortiGates, AWS/Azure VPN gateways, and essentially every enterprise firewall. WireGuard support is growing but not universal.
- Audited crypto. IKEv2 and the IPsec ESP transform have been deployed and audited for 25+ years. The crypto primitives (AES-GCM, SHA-2, ECDH with NIST or Curve25519 curves, Ed25519 signatures) are all supported by strongSwan.
Comparison: strongSwan vs WireGuard vs OpenVPN
| Feature | strongSwan (IKEv2) | WireGuard | OpenVPN |
|---|---|---|---|
| Native OS client | Yes (iOS, macOS, Win, Android) | No (app required) | No (app required) |
| Mobile roaming | MOBIKE (seamless) | Reconnect on network change | Reconnect on network change |
| Throughput (1 Gbps NIC) | ~700-800 Mbps | ~900+ Mbps | ~300-500 Mbps |
| Config complexity | High | Low | Medium |
| Site-to-site standard | Yes (RFC 7296) | Proprietary | Proprietary |
| Enterprise auth (RADIUS/AD) | Yes | No (external) | Yes |
| Codebase size | ~400K LoC | ~4K LoC | ~100K LoC |
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access.
- A public IPv4 address on the server. Note the address now — you will use it as the SAN (subject alternative name) on the server certificate.
- SSH access to the server.
- A domain name (optional but recommended) pointed to the VPS, so you can use a hostname instead of an IP in client profiles. IPsec works fine with IP-only endpoints, but hostnames make later IP changes painless.
- UDP ports 500 and 4500 reachable from the internet. If your provider has an external firewall (AWS security group, Hetzner Cloud firewall, etc.), open these ports there as well.
Recommended Plan: CloudCore Starter>
strongSwan is lightweight — the daemon itself uses less than 50 MB of RAM. For a personal or small-team VPN serving 10-30 concurrent users, the CloudCore Starter plan is ideal:>
- 2 vCPU cores
- 4 GB RAM
- 50 GB NVMe SSD
- Unmetered bandwidth>
CPU is the limiting factor for throughput — IPsec does a lot of crypto per packet. Two vCPUs on modern hardware (AES-NI) easily saturate a 1 Gbps link. For larger deployments (hundreds of concurrent clients or high-throughput site-to-site), step up to a plan with 4+ vCPUs.
Connect to your server via SSH to get started:
ssh root@your-server-ipFor the rest of this guide we assume your public IP is 203.0.113.10 and (optionally) your hostname is vpn.example.com. Substitute your actual values.
Step 1: Update the System
Start by updating your package index and upgrading installed packages:
sudo apt update && sudo apt upgrade -yIf the kernel was updated, reboot before continuing:
sudo rebootReconnect via SSH after a minute and verify the kernel version:
uname -rstrongSwan uses the kernel's XFRM framework for IPsec policy. Any recent Ubuntu 24.04 kernel (6.8+) supports everything we need.
Step 2: Install strongSwan and Plugins
Install the core strongSwan packages plus the extra plugins you need for EAP-MSCHAPv2 and modern cipher suites:
sudo apt install -y strongswan strongswan-pki strongswan-swanctl \
libcharon-extra-plugins libcharon-extauth-plugins \
libstrongswan-extra-pluginsWhat each package provides:
strongswan— the core daemon (charon) and systemd service.strongswan-pki— thepkicommand-line tool for generating keys, certificates, and CRLs.strongswan-swanctl— the modernswanctlcontrol utility and/etc/swanctl/configuration tree.libcharon-extra-plugins— extra authentication and crypto plugins includingeap-mschapv2,xauth, andfarp.libcharon-extauth-plugins— plugins for external authentication backends (RADIUS, PAM).libstrongswan-extra-plugins— extended crypto primitives (Curve25519, Ed25519, BLAKE2).
sudo swanctl --versionExpected output:
strongSwan swanctl 5.9.13Check that the systemd service is enabled:
sudo systemctl status strongswanExpected output:
● strongswan.service - strongSwan IPsec IKEv1/IKEv2 daemon using swanctl
Loaded: loaded (/usr/lib/systemd/system/strongswan.service; enabled; preset: enabled)
Active: active (running) since ...The service is running with an empty configuration at this point. We will populate it in the next steps.
Step 3: Enable IP Forwarding
The VPN server needs to forward packets between the tunnel and the public interface. Enable IPv4 (and optionally IPv6) forwarding in the kernel:
sudo tee /etc/sysctl.d/99-strongswan.conf > /dev/null <<EOF net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1Don't accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0Don't send ICMP redirects (we are not a router for the LAN)
net.ipv4.conf.all.send_redirects = 0Disable path MTU discovery black-holing
net.ipv4.ip_no_pmtu_disc = 0 EOF
sudo sysctl -p /etc/sysctl.d/99-strongswan.conf
Expected output:
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.ip_no_pmtu_disc = 0Step 4: Build the PKI (Certificate Authority)
IKEv2 uses X.509 certificates to authenticate the server to clients. We will build a small private CA, issue a server certificate, and (for the road-warrior setup) use EAP-MSCHAPv2 with username/password for client authentication. The same CA can later issue per-device client certificates if you want mutual TLS-style authentication.
strongSwan ships with the pki tool — a purpose-built certificate manager that is simpler than OpenSSL for IPsec use cases.
Create a working directory with restrictive permissions:
mkdir -p ~/pki/{cacerts,certs,private}
chmod 700 ~/pki
cd ~/pkiGenerate the CA Private Key
pki --gen --type rsa --size 4096 --outform pem > private/ca-key.pem
chmod 600 private/ca-key.pemThe --type rsa --size 4096 flags produce a 4096-bit RSA key — the conservative choice. If you prefer modern elliptic-curve crypto, use --type ed25519 for a much smaller key with equivalent security.
Self-Sign the CA Certificate
Use pki --self to create a self-signed root certificate from the private key:
pki --self --ca --lifetime 3650 \
--in private/ca-key.pem --type rsa \
--dn "CN=VPN Root CA" \
--outform pem > cacerts/ca-cert.pemFlags explained:
--self— self-sign the certificate (no issuer).--ca— mark this as a CA certificate (setsbasicConstraints:CA=TRUE).--lifetime 3650— valid for 10 years. CAs should outlive everything they issue.--dn "CN=VPN Root CA"— distinguished name. The CN is human-readable — it shows up in client trust dialogs.
pki --print --in cacerts/ca-cert.pemYou should see the subject, validity period, and pathlen constraint.
Step 5: Generate the Server Certificate
Create the server's private key:
pki --gen --type rsa --size 4096 --outform pem > private/server-key.pem
chmod 600 private/server-key.pemExtract the public key (used later by the pki --issue step implicitly, but kept for reference):
pki --pub --in private/server-key.pem --type rsa > private/server-pub.pemNow issue the server certificate, signed by your CA. This step is where the subject alternative names (SANs) matter — clients verify that the SAN on the cert matches what they connected to. Include every hostname and IP you expect clients to use:
pki --issue --lifetime 1825 \
--cacert cacerts/ca-cert.pem \
--cakey private/ca-key.pem \
--in private/server-key.pem --type rsa \
--dn "CN=vpn.example.com" \
--san vpn.example.com \
--san 203.0.113.10 \
--flag serverAuth --flag ikeIntermediate \
--outform pem > certs/server-cert.pemFlags explained:
--lifetime 1825— 5 years. Server certificates rotate more often than the CA.--cacert/--cakey— the CA that will sign this cert.--dn "CN=vpn.example.com"— common name. Some older clients match this; modern clients use SAN.--san— subject alternative names. Include every address clients will dial. Repeat the flag for each entry.--flag serverAuth— extended key usage: TLS Web Server Authentication (used by Windows).--flag ikeIntermediate— extended key usage for IKE intermediate (required by iOS/macOS for IKEv2).
sudo cp -r ~/pki/cacerts/* /etc/swanctl/x509ca/
sudo cp -r ~/pki/certs/* /etc/swanctl/x509/
sudo cp -r ~/pki/private/* /etc/swanctl/private/
sudo chown -R root:root /etc/swanctl/
sudo chmod -R 600 /etc/swanctl/private/Step 6: Generate Client Certificates
For pure EAP-MSCHAPv2 (username/password) authentication, clients do not need individual certificates — they only need the CA certificate to verify the server. However, if you want stronger mutual authentication (recommended for production), issue a per-device client cert. This example generates one for a user named alice:
cd ~/pkiAlice's private key
pki --gen --type rsa --size 4096 --outform pem > private/alice-key.pem
chmod 600 private/alice-key.pemIssue the client cert signed by the CA
pki --issue --lifetime 730 \
--cacert cacerts/ca-cert.pem \
--cakey private/ca-key.pem \
--in private/alice-key.pem --type rsa \
--dn "[email protected]" \
--san [email protected] \
--flag clientAuth \
--outform pem > certs/alice-cert.pemExport Alice's cert and key as a PKCS#12 bundle (the format iOS, macOS, and Windows import directly):
openssl pkcs12 -export \
-inkey private/alice-key.pem \
-in certs/alice-cert.pem \
-name "[email protected]" \
-certfile cacerts/ca-cert.pem \
-caname "VPN Root CA" \
-out alice.p12You will be prompted for an export password — set a strong one and share it securely with the user.
Transfer alice.p12 and cacerts/ca-cert.pem to the user's device (AirDrop, encrypted email, signed URL, etc.).
Step 7: Configure swanctl.conf (IKEv2 Road-Warrior)
The modern strongSwan configuration lives in /etc/swanctl/swanctl.conf (or any .conf file in /etc/swanctl/conf.d/). Replace the default file with a complete road-warrior configuration:
sudo tee /etc/swanctl/swanctl.conf > /dev/null <<'EOF' connections {ikev2-eap { version = 2 proposals = aes256gcm16-prfsha384-ecp384,aes256-sha384-ecp384,default
rekey_time = 24h dpd_delay = 30s
# Server side of the IKE SA local_addrs = %any remote_addrs = %any
local { auth = pubkey certs = server-cert.pem id = vpn.example.com }
remote { auth = eap-mschapv2 eap_id = %any }
children { ikev2-eap { local_ts = 0.0.0.0/0, ::/0 esp_proposals = aes256gcm16-ecp384,aes256-sha256,default rekey_time = 8h dpd_action = clear } }
# Virtual IP pool and DNS handed to clients pools = primary-pool-ipv4, primary-pool-ipv6
# Send pushed DNS / split-routes via IKEv2 config payload send_cert = always fragmentation = yes mobike = yes } }
pools { primary-pool-ipv4 { addrs = 10.10.10.0/24 dns = 1.1.1.1, 9.9.9.9 } primary-pool-ipv6 { addrs = fd9b:7bd8:e9f2::/48 dns = 2606:4700:4700::1111, 2620:fe::fe } }
secrets { eap-alice { id = [email protected] secret = "ReplaceWithALongRandomPassword!" } eap-bob { id = [email protected] secret = "AnotherStrongSecret#42" } } EOF
Key sections explained:
connections.ikev2-eap— a single connection definition namedikev2-eap. The name is arbitrary.proposals— IKE SA ciphers offered to clients. The list is preference-ordered: AES-256-GCM with PRF-SHA384 and ECP-384 DH group first, falling back todefault(strongSwan's built-in modern list).local.auth = pubkey— server authenticates with its X.509 certificate.remote.auth = eap-mschapv2— clients authenticate with EAP username/password.children.ikev2-eap.local_ts = 0.0.0.0/0, ::/0— the server advertises it can route all traffic (full-tunnel VPN). Change this to a specific subnet if you want split-tunnel.pools— virtual IP ranges handed to clients via the IKEv2 configuration payload. Pick RFC 1918 ranges (v4) and ULA ranges (v6) that do not overlap with any network your clients are likely to be on.mobike = yes— enable IKEv2 MOBIKE so clients can roam between Wi-Fi and cellular without reconnecting.fragmentation = yes— enable IKEv2 fragmentation (RFC 7383) to handle large cert payloads over lossy networks.
sudo chmod 600 /etc/swanctl/swanctl.confStep 8: Add EAP User Credentials
The secrets block in swanctl.conf above already defines two EAP users ([email protected] and [email protected]). To add more users later, append additional blocks:
secrets {
eap-alice {
id = [email protected]
secret = "..."
}
eap-carol {
id = [email protected]
secret = "AnotherStrongSecret#99"
}
}After editing, reload the secrets without restarting the daemon:
sudo swanctl --load-credsExpected output:
loaded eap secret 'eap-alice'
loaded eap secret 'eap-carol'
loaded certificate from '/etc/swanctl/x509/server-cert.pem'
loaded certificate from '/etc/swanctl/x509ca/ca-cert.pem'
loaded rsa key from '/etc/swanctl/private/server-key.pem'Generate strong passwords — EAP-MSCHAPv2 is the weakest link in this stack. Anything under 16 random characters is vulnerable to offline dictionary attacks if a passive attacker captures the handshake. Use openssl rand -base64 24 or pwgen -s 24 1.
For production deployments with more than a handful of users, replace eap-mschapv2 with eap-radius and authenticate against an external RADIUS server (FreeRADIUS + LDAP, or a cloud 2FA provider like Okta or JumpCloud).
Step 9: Firewall and MASQUERADE
IPsec needs two UDP ports open to the internet plus NAT rules so that client traffic exits through your server's public IP.
Open UDP 500 and 4500
Using UFW (the default Ubuntu firewall):
sudo ufw allow 22/tcp # SSH (don't lock yourself out)
sudo ufw allow 500/udp # IKE
sudo ufw allow 4500/udp # IKE NAT-Traversal
sudo ufw allow esp # IPsec ESP (protocol 50)
sudo ufw enable
sudo ufw status verboseExpected output:
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
500/udp ALLOW Anywhere
4500/udp ALLOW Anywhere
ESP ALLOW AnywhereConfigure MASQUERADE for Client Traffic
UFW's default rules do not apply NAT to forwarded traffic from the VPN pool. Add the MASQUERADE rule manually.
First, find the name of your public interface:
ip -4 route show defaultExpected output:
default via 203.0.113.1 dev eth0 proto staticIn this example the public interface is eth0. Adjust the commands below if yours differs.
Edit UFW's before rules:
sudo tee -a /etc/ufw/before.rules > /dev/null <<'EOF'strongSwan NAT: masquerade VPN clients
*nat
-A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE
-A POSTROUTING -s fd9b:7bd8:e9f2::/48 -o eth0 -j MASQUERADE
COMMIT
EOFEnable forwarding in UFW's default policy:
sudo sed -i 's/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufwApply the changes:
sudo ufw disable && sudo ufw enableVerify NAT is Active
sudo iptables -t nat -L POSTROUTING -n -vExpected output:
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * eth0 10.10.10.0/24 0.0.0.0/0Step 10: Start strongSwan and Load Config
Reload the swanctl configuration into the running daemon:
sudo swanctl --load-all --nopromptExpected output:
loaded certificate from '/etc/swanctl/x509/server-cert.pem'
loaded certificate from '/etc/swanctl/x509ca/ca-cert.pem'
loaded rsa key from '/etc/swanctl/private/server-key.pem'
loaded eap secret 'eap-alice'
loaded eap secret 'eap-bob'
loaded pool 'primary-pool-ipv4'
loaded pool 'primary-pool-ipv6'
loaded connection 'ikev2-eap'
successfully loaded 1 connections, 0 unloadedConfirm strongSwan is listening on UDP 500 and 4500:
sudo ss -ulnp | grep charonExpected output:
UNCONN 0 0 0.0.0.0:500 0.0.0.0:* users:(("charon-systemd",pid=...))
UNCONN 0 0 0.0.0.0:4500 0.0.0.0:* users:(("charon-systemd",pid=...))Enable the service at boot:
sudo systemctl enable strongswan
sudo systemctl restart strongswanView loaded connections:
sudo swanctl --list-connsList active SAs (will be empty until a client connects):
sudo swanctl --list-sasStep 11: Client Configuration
The exact steps depend on the platform. In every case, the client needs:
ca-cert.pem) imported into the device's trust store.vpn.example.com).iOS and macOS (Apple Configurator .mobileconfig)
The most user-friendly approach for Apple devices is to generate a signed .mobileconfig profile. The user double-taps it, enters their device passcode, and the entire VPN — CA cert, server settings, EAP username — is installed. Use Apple Configurator 2 or a tool like iMazing Profile Editor to build the profile.
Alternatively, configure manually:
My VPN.vpn.example.com.vpn.example.com (must match the server certificate SAN).[email protected].ca-cert.pem via Settings → General → VPN & Device Management → Profile so that iOS trusts the server cert.Windows 10 / 11
ca-cert.pem to the Windows machine. Rename to ca-cert.crt.My VPN.vpn.example.com.Android 12+ (Native IKEv2)
Native IKEv2 with EAP-MSCHAPv2 has been in Android since 12:
My VPN.vpn.example.com.[email protected] / your EAP password.Android (strongSwan App — Recommended for Older Devices)
Install the free strongSwan VPN Client from Google Play.
vpn.example.com.ca-cert.pem.Linux (NetworkManager)
Install the strongSwan NetworkManager plugin:
sudo apt install -y network-manager-strongswanThen in GNOME Settings → Network → VPN → Add → IPsec/IKEv2 (strongSwan). Fill in:
- Address:
vpn.example.com - Certificate: path to
ca-cert.pem - Authentication → EAP with username and password
Linux (strongSwan CLI)
For headless Linux clients, install strongSwan and create a client-side swanctl.conf:
sudo apt install -y strongswan strongswan-swanctlsudo cp ca-cert.pem /etc/swanctl/x509ca/
sudo tee /etc/swanctl/conf.d/client.conf > /dev/null <<'EOF' connections { home { remote_addrs = vpn.example.com version = 2 vips = 0.0.0.0
local { auth = eap-mschapv2 eap_id = [email protected] } remote { auth = pubkey id = vpn.example.com } children { home { remote_ts = 0.0.0.0/0 esp_proposals = aes256gcm16-ecp384,default } } } } secrets { eap-home { id = [email protected] secret = "ReplaceWithALongRandomPassword!" } } EOF
sudo swanctl --load-all --noprompt sudo swanctl --initiate --child home
Step 12: Site-to-Site Tunnel Example
In a site-to-site topology, two strongSwan servers (or one strongSwan and one Cisco/FortiGate/AWS VPN Gateway) authenticate to each other with certificates or a pre-shared key (PSK) and route entire LAN subnets through the encrypted tunnel. No user authentication, no virtual IP pool — just two gateways and two subnets.
Topology
Office A Office B
10.0.1.0/24 10.0.2.0/24
| |
[Gateway A] <== IPsec Tunnel ==> [Gateway B]
203.0.113.10 198.51.100.20Configuration on Gateway A (Office A)
Add a second connection block to /etc/swanctl/swanctl.conf. This example uses PSK for brevity — use certificates (auth = pubkey) for production:
connections {# ...existing ikev2-eap connection above...
site-to-site-b { version = 2 proposals = aes256gcm16-prfsha384-ecp384,default mobike = no
local_addrs = 203.0.113.10 remote_addrs = 198.51.100.20
local { auth = psk id = 203.0.113.10 } remote { auth = psk id = 198.51.100.20 }
children { office-b { local_ts = 10.0.1.0/24 remote_ts = 10.0.2.0/24
esp_proposals = aes256gcm16-ecp384,default start_action = start dpd_action = restart close_action = restart rekey_time = 4h } } } }
secrets { # ...existing eap secrets...
ike-site-b { id-a = 203.0.113.10 id-b = 198.51.100.20 secret = "SuperLongRandomPSKAtLeast32Chars!!" } }
Configuration on Gateway B (Office B)
Mirror the configuration with local/remote swapped:
connections { site-to-site-a { version = 2 local_addrs = 198.51.100.20 remote_addrs = 203.0.113.10local { auth = psk; id = 198.51.100.20 } remote { auth = psk; id = 203.0.113.10 }
children { office-a { local_ts = 10.0.2.0/24 remote_ts = 10.0.1.0/24 start_action = start dpd_action = restart } } } }
secrets { ike-site-a { id-a = 198.51.100.20 id-b = 203.0.113.10 secret = "SuperLongRandomPSKAtLeast32Chars!!" } }
Activate and Verify
On both gateways:
sudo swanctl --load-all --noprompt
sudo swanctl --list-sasExpected output (abbreviated):
site-to-site-b: #1, ESTABLISHED, IKEv2, ...
local '203.0.113.10' @ 203.0.113.10
remote '198.51.100.20' @ 198.51.100.20
AES_GCM_16-256/PRF_HMAC_SHA2_384/ECP_384
established 12s ago, rekeying in ...
office-b: #1, reqid 2, INSTALLED, TUNNEL, ESP:AES_GCM_16-256
installed 12s ago, rekeying in 3h59m48s
10.0.1.0/24 === 10.0.2.0/24From a host in Office A, ping a host in Office B:
ping 10.0.2.5Traffic now flows through the IPsec tunnel, encrypted with AES-256-GCM.
Logs, Monitoring, and Troubleshooting
Real-Time Logs
The strongSwan daemon logs to the systemd journal:
sudo journalctl -u strongswan -fFor more verbose debugging, increase the log level in /etc/strongswan.d/charon-logging.conf:
charon {
filelog {
charon {
path = /var/log/charon.log
default = 2
ike = 2
cfg = 2
net = 1
}
}
}Log level 2 = detailed, 3 = controlling messages, 4 = raw packet dumps. Restart strongSwan after editing:
sudo systemctl restart strongswan
sudo tail -f /var/log/charon.logUseful swanctl Commands
| Command | Purpose |
|---|---|
swanctl --list-conns | Show loaded connection definitions |
swanctl --list-sas | Show active IKE and CHILD security associations |
swanctl --list-certs | Show loaded certificates |
swanctl --list-pools | Show virtual IP pools and usage |
swanctl --stats | Daemon statistics (workers, queued jobs) |
swanctl --terminate --ike <name> | Disconnect a specific IKE SA |
swanctl --rekey --ike <name> | Force rekey of an IKE SA |
swanctl --reload-settings | Reload /etc/strongswan.conf without restart |
Common Problems
| Problem | Cause | Fix |
|---|---|---|
| Client connects but no internet | MASQUERADE rule missing or wrong interface | Check iptables -t nat -L POSTROUTING -v; verify interface name with ip route |
IKE_SA established but CHILD_SA failed | Traffic selector mismatch between client and server | Ensure local_ts = 0.0.0.0/0, ::/0 on server; check client's split-tunnel setting |
| iOS/macOS: "VPN server did not respond" | Firewall blocks UDP 500/4500 | Verify ufw status; check cloud provider firewall/security group |
EAP-Identity request was not answered | EAP username mismatch or password wrong | Confirm id in secrets matches username exactly (case-sensitive) |
| Server cert rejected by client | SAN missing client's connection target | Reissue cert with --san matching every hostname/IP clients use |
| Android: "VPN cannot be established" | Missing CA trust on device | Install ca-cert.pem via Settings → Encryption & credentials → Install a certificate |
| Slow throughput (<100 Mbps) | Software crypto on older CPU without AES-NI | Check cat /proc/cpuinfo \</td><td>grep aes; move to a CPU with AES-NI or switch to ChaCha20 proposal |
charon: no shared key found for S2S | PSK identities not matching id-a / id-b | Ensure id-a and id-b in secrets.ike-* match the local.id / remote.id on each side |
Packet Capture for Deep Debugging
When a client cannot connect and the logs are unclear, capture the IKE exchange on the server:
sudo tcpdump -i eth0 -n -v "udp port 500 or udp port 4500" -w /tmp/ike.pcapLet the client attempt to connect, then stop tcpdump (Ctrl+C) and inspect the capture in Wireshark with the IKE dissector. You can see exactly where the handshake fails (IKE_SA_INIT, IKE_AUTH, IKE_FRAGMENTATION).
FAQ
Is IPsec faster or slower than WireGuard?
On the same hardware, WireGuard typically achieves 10-30% higher throughput than strongSwan IPsec, mostly because WireGuard does all its crypto in the kernel with a fixed, modern cipher suite (ChaCha20-Poly1305 or AES-GCM with hardware acceleration). strongSwan runs key management in userspace (the charon daemon) and hands established SAs to the kernel XFRM subsystem — the data-plane is comparable in speed, but connection setup is heavier. For a single-user home VPN, the difference is imperceptible. For a 10 Gbps VPN gateway, WireGuard has the edge.
Can I use both certificate and EAP authentication?
Yes. strongSwan supports EAP-TLS (client authenticates with a certificate instead of username/password) and EAP-MSCHAPv2 + client cert (mutual cert auth plus a username/password second factor). For EAP-TLS, change remote.auth = eap-mschapv2 to remote.auth = eap-tls and issue a client cert per user. For cert + EAP, use remote.auth = pubkey | eap-mschapv2 with a round = 2 block. See the strongSwan docs on EAP for the full syntax.
How do I support more than ~250 concurrent clients?
The default IPv4 pool 10.10.10.0/24 gives you 254 usable addresses. To scale up, either widen the pool (10.10.0.0/16 for ~65k clients) or add multiple pools and reference them in the connection with pools = pool1, pool2. Also bump /etc/strongswan.d/charon.conf parameters like charon.threads = 32 (default 16) and charon.ikesa_table_size = 4096 on busy servers. Run swanctl --stats to see current utilization.
Why do I need both UDP 500 and UDP 4500?
UDP 500 is the IKE control channel used when neither endpoint is behind NAT. UDP 4500 is used for IKE NAT-Traversal (RFC 3948) and for ESP-in-UDP encapsulation when the client is behind NAT — which almost all mobile devices are. Most real-world connections start on 500 and immediately migrate to 4500 after detecting NAT. Block either one and mobile clients will fail.
How do I rotate the server certificate?
Generate a new server cert with pki --issue (same CA, new key, new dates), copy it into /etc/swanctl/x509/ and the key into /etc/swanctl/private/, remove the old files, then run sudo swanctl --load-creds. Existing connections keep their old SAs until rekey. To force all clients to reconnect on the new cert, run sudo systemctl restart strongswan. Rotate the server cert every 12-24 months; rotate the CA only if compromised (it is valid for 10 years).
Can strongSwan act as a VPN client instead of a server?
Yes. Any host with strongSwan installed can --initiate outbound tunnels to another IKEv2 gateway (AWS VPN, Azure VPN Gateway, another strongSwan, a Cisco ASA, etc.). The Linux CLI example at the end of Step 11 shows this pattern. Use start_action = start in the children block to auto-connect at boot.
Next Steps
Now that strongSwan is running, consider these follow-ups to harden and extend the setup:
- Enable RADIUS/AD authentication. Replace static EAP secrets with
eap-radiusand point strongSwan at a FreeRADIUS server backed by LDAP, Active Directory, or a cloud identity provider. Any user who gets deprovisioned in AD instantly loses VPN access. - Add a 2FA layer. Combine
eap-radiuswith a TOTP module (Google Authenticator, Duo, privacyIDEA) so users need both a password and a rotating 6-digit code. - Monitor with Prometheus. Install
prometheus-strongswan-exporterto scrape active SA counts, bytes transferred, and connection success rates into Grafana dashboards. - Compare to WireGuard for specific use cases. For a much simpler personal VPN, try our WireGuard guide. For SSL-VPN (TCP/443) that passes through restrictive firewalls, OpenConnect is the better choice. For legacy client compatibility, see OpenVPN.
- Read the official docs. The strongSwan documentation has deep reference material on every plugin, cipher, and configuration option. Start with the
swanctl.confman page and the conf/keywords reference. - Automate provisioning. Script the
pkicommands and.mobileconfiggeneration so onboarding a new user takes one command instead of 15 minutes of manual work.
Ready to deploy? Spin up a CloudCore Starter VPS — 2 vCPU, 4 GB RAM, 50 GB NVMe, unmetered bandwidth — and have your IKEv2 VPN online in under 40 minutes. All plans include KVM virtualization, IPv6, and full root access so you can build exactly the VPN stack your team needs.