AlmaLinux

Install StrongSwan IPsec VPN on Rocky Linux 10 / AlmaLinux 10

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/24 for 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.pem to the Windows machine and rename it to ca-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.

Related Articles

Windows Install and Configure DHCP Server on Windows Server 2019 AlmaLinux Installing Ruby on Rails on Rocky Linux 9 | AlmaLinux 9 Desktop Setup Fingerprint Reader Authentication with PAM on Linux Books New Cisco Security Certifications (2026): Best Study Book Guide

Press ESC to close