IPsec VPNs provide strong, standards-based encryption and are natively supported by Windows, macOS, and iOS without additional client software. StrongSwan is a full-featured IKEv2/IPsec implementation that runs well on RHEL 9. This tutorial walks you through installing StrongSwan, generating a PKI certificate chain, and configuring an IKEv2 VPN server that accepts connections from native OS clients. By the end you will have a production-ready VPN endpoint secured with certificate-based authentication.
Prerequisites
- RHEL 9 server with a static public IP address
- A fully qualified domain name (FQDN) pointed at the server (used in the certificate)
- Root or sudo access
- Firewalld running or direct iptables access
- Basic familiarity with PKI concepts
Step 1 — Install StrongSwan
StrongSwan is available in the EPEL repository. Enable EPEL and install the package along with the PKI utility:
dnf install -y epel-release
dnf install -y strongswan strongswan-charon-nm
systemctl enable strongswan-starter
StrongSwan 5.x on RHEL 9 uses the swanctl interface with VICI (Versatile IKE Control Interface). Configuration lives under /etc/strongswan/swanctl/.
Step 2 — Generate the Certificate Authority and Server Certificate
StrongSwan ships a PKI utility for generating keys and certificates. Create a working directory and build the chain:
# Create directory layout
mkdir -p /etc/strongswan/swanctl/private
mkdir -p /etc/strongswan/swanctl/x509
mkdir -p /etc/strongswan/swanctl/x509ca
# Generate CA private key
pki --gen --type rsa --size 4096
--outform pem > /etc/strongswan/swanctl/private/ca-key.pem
# Self-sign the CA certificate (10-year validity)
pki --self --ca --lifetime 3650
--in /etc/strongswan/swanctl/private/ca-key.pem
--dn "CN=VPN Root CA"
--outform pem > /etc/strongswan/swanctl/x509ca/ca-cert.pem
# Generate server private key
pki --gen --type rsa --size 2048
--outform pem > /etc/strongswan/swanctl/private/server-key.pem
# Generate a certificate signing request and issue it from the CA
# Replace vpn.example.com with your actual FQDN
pki --pub --in /etc/strongswan/swanctl/private/server-key.pem
--outform pem |
pki --issue --lifetime 730
--cacert /etc/strongswan/swanctl/x509ca/ca-cert.pem
--cakey /etc/strongswan/swanctl/private/ca-key.pem
--dn "CN=vpn.example.com"
--san "vpn.example.com"
--flag serverAuth
--outform pem > /etc/strongswan/swanctl/x509/server-cert.pem
# Secure private keys
chmod 600 /etc/strongswan/swanctl/private/*.pem
Copy ca-cert.pem to your client devices. On Windows, import it into the “Trusted Root Certification Authorities” store. On macOS, add it to the System keychain and set it to “Always Trust”.
Step 3 — Configure swanctl.conf
Create the main configuration file at /etc/strongswan/swanctl/swanctl.conf:
connections {
ikev2-rw {
version = 2
proposals = aes256gcm16-prfsha384-ecp384,aes256-sha384-ecp384
local_addrs = %any # listen on all interfaces
remote_addrs = %any
local {
auth = pubkey
certs = server-cert.pem
id = vpn.example.com
}
remote {
auth = eap-mschapv2
eap_id = %any
}
children {
ikev2-rw-child {
local_ts = 0.0.0.0/0 # tunnel all client traffic
remote_ts = dynamic
esp_proposals = aes256gcm16-ecp384,aes256-sha256
mode = tunnel
dpd_action = clear
}
}
pools = client-pool
send_certreq = yes
dpd_delay = 30s
}
}
pools {
client-pool {
addrs = 10.10.10.0/24
dns = 1.1.1.1, 8.8.8.8
}
}
secrets {
eap-user1 {
id = user1
secret = "ChangeMe123!"
}
}
Step 4 — Enable IP Forwarding and NAT
Clients need to reach the internet through the server, which requires forwarding and masquerade NAT. Replace ens3 with your public interface name.
# Persist IP forwarding
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/99-vpn.conf
sysctl -p /etc/sysctl.d/99-vpn.conf
# NAT masquerade (iptables)
iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o ens3 -j MASQUERADE
iptables -A FORWARD -i xfrm0 -j ACCEPT
iptables -A FORWARD -o xfrm0 -j ACCEPT
# Persist iptables rules
dnf install -y iptables-services
iptables-save > /etc/sysconfig/iptables
systemctl enable --now iptables
# Allow IKE and ESP in firewalld (if using firewalld instead)
firewall-cmd --permanent --add-service=ipsec
firewall-cmd --permanent --add-masquerade
firewall-cmd --reload
Step 5 — Load Configuration and Start StrongSwan
# Start the daemon
systemctl start strongswan-starter
# Load all swanctl configuration
swanctl --load-all
# Verify loaded connections
swanctl --list-conns
# After a client connects, monitor active SAs
swanctl --list-sas
# View logs for troubleshooting
journalctl -u strongswan-starter -f
Step 6 — Connect a Native IKEv2 Client
Windows 10/11: Open Settings → VPN → Add a VPN connection. Set the VPN type to IKEv2, enter the server FQDN, choose Username and Password as the sign-in type, and enter the credentials from swanctl.conf. Before connecting, import the CA certificate into Local Machine → Trusted Root Certification Authorities.
macOS: Navigate to System Settings → VPN → Add VPN Configuration → IKEv2. Enter the server address and remote ID (matching the server certificate CN), then set authentication to Username and enter credentials.
iOS/Android: Use the built-in IKEv2 profile or the official StrongSwan app. Provide the server address, CA certificate, and EAP credentials.
Conclusion
You now have a fully functional IKEv2/IPsec VPN server on RHEL 9. StrongSwan handles key exchange and re-keying automatically, and the EAP-MSCHAPv2 authentication allows you to add users simply by extending the secrets block. For production deployments, consider issuing per-user certificates instead of EAP passwords and storing private keys in a hardware security module.
Next steps: How to Configure Certificate-Based EAP Authentication in StrongSwan, How to Monitor IPsec Traffic with tcpdump and Wireshark on RHEL 9, and How to Set Up a Split-Tunnel VPN with StrongSwan on RHEL 9.