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.