StrongSwan is an open-source IPsec-based VPN solution that supports IKEv1 and IKEv2 key exchange protocols. It creates encrypted tunnels between hosts using certificate-based or pre-shared key authentication, making it a solid choice for site-to-site and remote access VPN deployments. StrongSwan runs on Linux, Android, macOS, iOS, and Windows.
This guide walks through installing and configuring a StrongSwan IPsec VPN server on Rocky Linux 10 or AlmaLinux 10. We cover certificate generation using the strongSwan PKI tool, IKEv2 configuration, firewall rules, IP forwarding, SELinux adjustments, and client setup for Linux, Windows, macOS, and mobile devices.
Prerequisites
- A server running Rocky Linux 10 or AlmaLinux 10 with a public IP address
- Root or sudo access
- A domain name or static IP for the VPN server (e.g., vpn.example.com)
- Ports UDP 500 and UDP 4500 open on any upstream firewall or cloud security group
- Familiarity with firewalld on Rocky Linux / AlmaLinux
Step 1: Enable IP Forwarding
The VPN server needs to forward packets between clients and the network. Enable IPv4 and IPv6 forwarding by adding kernel parameters to /etc/sysctl.d/.
sudo vi /etc/sysctl.d/99-vpn.conf
Add the following sysctl settings:
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
Apply the settings immediately:
sudo sysctl --system
Confirm that IP forwarding is active:
sysctl net.ipv4.ip_forward
The output should show the value set to 1:
net.ipv4.ip_forward = 1
Step 2: Install StrongSwan IPsec VPN on Rocky Linux 10
StrongSwan packages are available in the EPEL repository. Enable EPEL first:
sudo dnf install epel-release -y
Then install StrongSwan:
sudo dnf install strongswan -y
Verify the installation by checking the version:
strongswan version
You should see output confirming the StrongSwan version and kernel:
Linux strongSwan U6.0.0/K6.12.0-55.el10.x86_64
University of Applied Sciences Rapperswil, Switzerland
Step 3: Generate Certificates with StrongSwan PKI
StrongSwan uses X.509 certificates for IKEv2 authentication. We generate a CA certificate, server certificate, and client certificate using the built-in pki tool. This avoids external dependencies for certificate management.
Create PKI Directory Structure
Set up a working directory for certificate generation:
mkdir -p ~/pki/{cacerts,certs,private}
chmod 700 ~/pki
Generate the CA Key and Certificate
Create a 4096-bit RSA private key for the Certificate Authority:
strongswan pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/ca-key.pem
Sign a self-signed CA certificate valid for 10 years:
strongswan 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
Generate the Server Key and Certificate
Create the server private key:
strongswan pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/server-key.pem
Issue the server certificate, signed by the CA. Replace vpn.example.com with your server’s FQDN and 10.0.1.50 with its public IP address:
strongswan pki --pub --in ~/pki/private/server-key.pem --type rsa \
| strongswan 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 \
--san 10.0.1.50 \
--san @10.0.1.50 \
--flag serverAuth --flag ikeIntermediate \
--outform pem > ~/pki/certs/server-cert.pem
The --san (Subject Alternative Name) entries allow clients to connect using either the domain name or IP address. The @ prefix on the IP creates an ID-type SAN required by some clients.
Generate a Client Certificate
For certificate-based client authentication (stronger than EAP), generate a client key and certificate:
strongswan pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/client-key.pem
Issue the client certificate signed by the same CA:
strongswan pki --pub --in ~/pki/private/client-key.pem --type rsa \
| strongswan pki --issue --lifetime 730 \
--cacert ~/pki/cacerts/ca-cert.pem \
--cakey ~/pki/private/ca-key.pem \
--dn "[email protected]" \
--san [email protected] \
--outform pem > ~/pki/certs/client-cert.pem
Copy Certificates to StrongSwan Directory
Copy the generated certificates and keys to the StrongSwan IPsec directory:
sudo cp -r ~/pki/* /etc/strongswan/ipsec.d/
Set appropriate permissions so the StrongSwan daemon can read the files:
sudo chmod -R 750 /etc/strongswan/ipsec.d/private/
Step 4: Configure StrongSwan IKEv2 VPN
StrongSwan configuration files live in /etc/strongswan/. The two main files are ipsec.conf (connection definitions) and ipsec.secrets (authentication credentials). Refer to the official StrongSwan documentation for the full configuration reference.
Configure ipsec.conf
Back up the default configuration first:
sudo cp /etc/strongswan/ipsec.conf /etc/strongswan/ipsec.conf.bak
Open the configuration file:
sudo vi /etc/strongswan/ipsec.conf
Replace the contents with the following IKEv2 configuration. Adjust leftid, leftsubnet, rightsourceip, and rightdns to match your environment:
config setup
charondebug="ike 2, knl 2, cfg 2"
uniqueids=no
conn ikev2-vpn
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
dpdaction=clear
dpddelay=300s
rekey=no
# Server (left) side
left=%any
[email protected] # Your FQDN or IP (without @ if using IP)
leftcert=server-cert.pem # Server certificate in /etc/strongswan/ipsec.d/certs/
leftsendcert=always
leftsubnet=0.0.0.0/0 # Route all client traffic through VPN
# Client (right) side
right=%any
rightid=%any
rightauth=eap-mschapv2
rightsourceip=10.10.10.0/24 # Virtual IP pool for VPN clients
rightdns=8.8.8.8,8.8.4.4 # DNS servers assigned to clients
rightsendcert=never
eap_identity=%identity
# Cipher suites
ike=aes256-sha256-modp2048,aes256-sha384-modp4096,aes256gcm16-sha384-modp2048!
esp=aes256-sha256,aes256gcm16-sha256!
Key settings explained:
- leftsubnet=0.0.0.0/0 – routes all client traffic through the VPN (full tunnel mode). Use a specific subnet like
192.168.1.0/24for split tunneling - rightsourceip=10.10.10.0/24 – the virtual IP pool assigned to connecting clients
- rightauth=eap-mschapv2 – clients authenticate with username/password over EAP-MSCHAPv2
- dpdaction=clear – clears dead peer connections automatically
- forceencaps=yes – forces UDP encapsulation for NAT traversal
Configure ipsec.secrets
Generate a strong password for VPN client authentication:
head -c 24 /dev/urandom | base64
The command produces a random 32-character string to use as the EAP password:
xK9mT3vRpLqW8nYfBz2hJcA7dE5gN1sU
Open the secrets file:
sudo vi /etc/strongswan/ipsec.secrets
Define the server private key and EAP credentials. Add one line per VPN user:
# Server private key
: RSA "server-key.pem"
# VPN user credentials (username : EAP "password")
vpnuser1 : EAP "xK9mT3vRpLqW8nYfBz2hJcA7dE5gN1sU"
vpnuser2 : EAP "anotherStrongPasswordHere"
Step 5: Configure Firewall for IPsec VPN
StrongSwan requires UDP ports 500 (IKE) and 4500 (NAT traversal) to be open. Enable IP masquerading so VPN clients can reach external networks.
sudo firewall-cmd --permanent --add-port=500/udp
sudo firewall-cmd --permanent --add-port=4500/udp
sudo firewall-cmd --permanent --add-service=ipsec
sudo firewall-cmd --permanent --add-masquerade
sudo firewall-cmd --reload
Verify the firewall rules are applied:
sudo firewall-cmd --list-all
You should see ports 500/udp and 4500/udp listed under ports, ipsec under services, and masquerade set to yes:
public (active)
target: default
services: cockpit dhcpv6-client ipsec ssh
ports: 500/udp 4500/udp
masquerade: yes
...
Step 6: Configure SELinux for StrongSwan
On Rocky Linux 10 and AlmaLinux 10, SELinux is enforcing by default. StrongSwan needs to read certificates from its ipsec.d directory. If you encounter permission errors, restore the correct SELinux context on the certificate files:
sudo restorecon -Rv /etc/strongswan/ipsec.d/
If StrongSwan still fails to start, check the audit log for denials and create a local policy module:
sudo ausearch -m AVC -ts recent | audit2allow -M strongswan-local
sudo semodule -i strongswan-local.pp
Verify the current SELinux status:
getenforce
The output should show Enforcing – never set SELinux to permissive or disabled in production.
Step 7: Start and Enable StrongSwan
Start StrongSwan and enable it to run on boot:
sudo systemctl enable --now strongswan
Check the service status:
systemctl status strongswan
The service should show active (running):
● strongswan.service - strongSwan IPsec IKEv1/IKEv2 daemon
Loaded: loaded (/usr/lib/systemd/system/strongswan.service; enabled; preset: disabled)
Active: active (running)
Main PID: 12345 (charon)
...
Run a full status check to confirm the VPN configuration is loaded:
sudo strongswan statusall
Look for your connection definition and the virtual IP pool in the output:
Status of IKE charon daemon (strongSwan 6.0.0, Linux 6.12.0-55.el10.x86_64, x86_64):
uptime: 15 seconds, since Mar 21 10:30:00 2026
loaded plugins: charon pkcs11 tpm aesni aes des sha2 sha1 md5 mgf1 random nonce x509
revocation constraints pubkey pkcs1 pkcs7 pkcs12 pem openssl gcrypt fips-prf gmp
curve25519 xcbc cmac hmac kdf ctr ccm gcm kernel-netlink resolve socket-default
stroke vici updown eap-identity eap-mschapv2 eap-tls xauth-generic
Virtual IP pools (size/online/offline):
10.10.10.0/24: 254/0/0
Connections:
ikev2-vpn: %any...%any IKEv2, dpddelay=300s
ikev2-vpn: local: [vpn.example.com] uses public key authentication
ikev2-vpn: cert: "CN=vpn.example.com"
ikev2-vpn: remote: uses EAP_MSCHAPV2 authentication with EAP identity '%any'
ikev2-vpn: child: 0.0.0.0/0 === dynamic TUNNEL, dpdaction=clear
Security Associations (0 up, 0 connecting):
none
Zero security associations at this point is expected – associations appear when clients connect.
Step 8: Configure VPN Clients
Clients need the CA certificate (ca-cert.pem) from the server and the EAP credentials configured in ipsec.secrets. Copy the CA certificate from the server to each client machine.
Linux Client (Rocky/AlmaLinux/RHEL)
Install StrongSwan on the client:
sudo dnf install epel-release -y
sudo dnf install strongswan -y
Copy the CA certificate from the VPN server to the client. Replace 10.0.1.50 with your server IP:
scp [email protected]:/etc/strongswan/ipsec.d/cacerts/ca-cert.pem ~/
sudo cp ~/ca-cert.pem /etc/strongswan/ipsec.d/cacerts/
Configure the client secrets. Open the file:
sudo vi /etc/strongswan/ipsec.secrets
Add the EAP credentials matching what was set on the server:
vpnuser1 : EAP "xK9mT3vRpLqW8nYfBz2hJcA7dE5gN1sU"
Configure the client connection. Open the IPsec config:
sudo vi /etc/strongswan/ipsec.conf
Add the following client configuration:
config setup
conn ikev2-vpn
right=vpn.example.com # VPN server FQDN or IP
[email protected] # Must match leftid on the server
rightsubnet=0.0.0.0/0 # Route all traffic through VPN
rightauth=pubkey
leftsourceip=%config # Receive IP from server pool
leftid=vpnuser1
leftauth=eap-mschapv2
leftcacert=ca-cert.pem
eap_identity=%identity
auto=start
Start the StrongSwan client:
sudo systemctl restart strongswan
Check the connection status:
sudo strongswan status
A successful connection shows an established CHILD_SA with assigned virtual IP:
Security Associations (1 up, 0 connecting):
ikev2-vpn[1]: ESTABLISHED 5 seconds ago, 10.0.1.100[vpnuser1]...10.0.1.50[vpn.example.com]
ikev2-vpn{1}: INSTALLED, TUNNEL, reqid 1, ESP SPIs: c906aacf_i c421b22b_o
ikev2-vpn{1}: 10.10.10.1/32 === 0.0.0.0/0
Ubuntu/Debian Client
Install StrongSwan and the required EAP plugin:
sudo apt update
sudo apt install strongswan libcharon-extra-plugins -y
Copy the CA certificate to the client:
scp [email protected]:/etc/strongswan/ipsec.d/cacerts/ca-cert.pem ~/
sudo cp ~/ca-cert.pem /etc/ipsec.d/cacerts/
Edit the secrets file at /etc/ipsec.secrets and the connection file at /etc/ipsec.conf using the same configuration shown in the Linux client section above. Then restart the service:
sudo systemctl restart strongswan-starter
Windows Client
Windows 10/11 has a built-in IKEv2 VPN client. Import the CA certificate first:
- Copy
ca-cert.pemto the Windows machine and rename it toca-cert.crt - Double-click the file, select “Install Certificate” – choose “Local Machine” – place it in “Trusted Root Certification Authorities”
- Go to Settings – Network & Internet – VPN – Add a VPN connection
- VPN provider: Windows (built-in)
- Connection name: any descriptive name
- Server name or address: vpn.example.com (or the server IP)
- VPN type: IKEv2
- Sign-in info: Username and password (use the EAP credentials from ipsec.secrets)
macOS Client
macOS supports IKEv2 natively:
- Import the CA certificate by double-clicking
ca-cert.pem– it opens in Keychain Access. Mark it as “Always Trust” under the certificate trust settings - Go to System Settings – VPN – Add VPN Configuration – IKEv2
- Server Address: vpn.example.com
- Remote ID: vpn.example.com (must match leftid on the server)
- Local ID: leave empty
- Authentication: Username, enter the EAP credentials
iOS and Android
Both iOS and Android support IKEv2 VPN connections. On iOS, go to Settings – General – VPN & Device Management – Add VPN Configuration and select IKEv2. On Android, use the strongSwan VPN Client app from the Play Store. Import the CA certificate and enter your server address with EAP credentials.
Step 9: Verify the VPN Connection
After a client connects, run the following on the server to see active security associations:
sudo strongswan statusall
The output shows established tunnels with assigned virtual IPs and traffic counters:
Security Associations (1 up, 0 connecting):
ikev2-vpn[1]: ESTABLISHED 2 minutes ago, 10.0.1.50[vpn.example.com]...203.0.113.45[vpnuser1]
ikev2-vpn{1}: INSTALLED, TUNNEL, reqid 1, ESP SPIs: ab12cd34_i ef56gh78_o
ikev2-vpn{1}: 0.0.0.0/0 === 10.10.10.1/32
On the client side, verify connectivity through the tunnel by checking your public IP – it should show the VPN server’s IP:
curl -s ifconfig.me
If you configured WireGuard VPN previously and want to compare, StrongSwan’s IPsec approach provides broader client compatibility since IKEv2 is built into Windows, macOS, and iOS without additional software.
Troubleshooting StrongSwan VPN
Common issues and their fixes:
Certificate errors – verify the CA certificate is properly installed on the client and the server certificate CN or SAN matches the leftid value exactly.
Connection timeout – confirm ports UDP 500 and 4500 are open on both the server firewall and any cloud security group. Test with:
sudo ss -ulnp | grep -E '500|4500'
Both ports should show the charon process listening:
UNCONN 0 0 *:500 *:* users:(("charon",pid=12345,fd=22))
UNCONN 0 0 *:4500 *:* users:(("charon",pid=12345,fd=23))
No traffic after connection – verify IP forwarding is active and masquerading is enabled in firewalld. Check the Ansible-based VPN deployment guide for automated setup if manual configuration proves error-prone.
SELinux denials – check the audit log for AVC messages related to strongswan or charon processes:
sudo ausearch -m AVC -c charon -ts recent
Debug logging – increase charon debug verbosity temporarily by setting charondebug="ike 4, net 4" in ipsec.conf and restarting StrongSwan. View logs with:
sudo journalctl -u strongswan -f
Conclusion
StrongSwan IPsec VPN is now running on Rocky Linux 10 / AlmaLinux 10 with IKEv2 certificate-based server authentication and EAP client authentication. Clients on Linux, Windows, macOS, iOS, and Android can connect using the native IKEv2 support available on each platform.
For production deployments, consider using Let’s Encrypt certificates instead of self-signed ones, implementing certificate revocation lists (CRLs), setting up Pritunl for a web-based VPN management interface, and monitoring tunnel status with centralized logging.