Randy Apps


Convenient Apps changing tomorrow.

【Ubuntu】How to Build an IKEv2 VPN with Ubuntu + StrongSwan (No Client App Needed & Supports All Major OS)


VPNs are incredibly useful when you want to safely use public Wi-Fi on the go or securely access your home or company network.

While OpenVPN and WireGuard are popular choices, in this post, we will build an “IKEv2” VPN. The biggest advantage is that you don’t need to install a dedicated client app or even a client-side certificate. You can connect instantly using only a username and password via the native features built into Mac, Windows, iPhone, and Android.

This article is a memo of the steps I took to build an IKEv2 VPN server using an Ubuntu server and StrongSwan.
*Note: While the official StrongSwan documentation is shifting towards a new configuration method using swanctl, I intentionally chose the traditional strongswan-starter (using ipsec.conf) for this guide. It has a wealth of information online and is more intuitive to configure.

I’ll also cover essential real-world tips, such as automating Let’s Encrypt renewals without a web server, the specific certificate “trap” for iOS (iPhone), and optimizing “cipher suites (ike/esp)” for stable connections across all major OSes. I hope this helps anyone trying to set up a similar environment.

1. Prerequisites and Port Configuration

For this setup, I used a VPS (Ubuntu Server). The requirements are:

  • Server: VPS (Sakura VPS, etc.)
  • OS: Ubuntu Server (20.04 / 22.04 / 24.04, etc.)
  • Domain: A custom domain linked to your server’s IP (e.g., vpn.example.com)

Before starting, ensure the following ports are open in your firewall (e.g., ufw):

  • TCP 80: For Let’s Encrypt certificate issuance and auto-renewal.
  • UDP 500: For IKEv2 communication control.
  • UDP 4500: For IPsec communication over NAT.

*Note: Please replace the example domain (vpn.example.com) with your actual domain throughout this guide.

If you use Ubuntu’s standard firewall (ufw), use the following commands:

sudo ufw allow 80/tcp
sudo ufw allow 500/udp
sudo ufw allow 4500/udp

2. Installing StrongSwan

Install the core VPN software, “StrongSwan,” along with the necessary plugins. We specify strongswan-starter to use the user-friendly ipsec.conf format.

sudo apt update
sudo apt install strongswan strongswan-starter strongswan-pki libcharon-extra-plugins libcharon-extauth-plugins libstrongswan-extra-plugins

3. Getting and Automating Let’s Encrypt Certificates

We’ll use free “Let’s Encrypt” certificates. To keep things simple, we’ll use Certbot’s “Standalone mode,” which spins up a temporary server only during the renewal process.

# Install Certbot
sudo apt install certbot

Crucial Note for iOS Users:

💡 [Memo] The iOS (iPhone/iPad) Certificate Trap
By default, Let’s Encrypt issues “ECDSA” certificates. However, iOS IKEv2 clients often silently reject these due to specific security requirements. To avoid this (and I spent hours troubleshooting this!), we must explicitly request the traditional “RSA format.”

sudo certbot certonly --standalone -d vpn.example.com --key-type rsa

Automating Certificate Deployment (Hooks)

Because of Ubuntu’s “AppArmor” security, StrongSwan cannot directly read certificates from the Certbot directory. We must copy them to /etc/ipsec.d/.

sudo nano /etc/letsencrypt/renewal-hooks/deploy/strongswan-reload.sh

Create this script to automate the copy and service reload:

#!/bin/bash
cp -f /etc/letsencrypt/live/vpn.example.com/fullchain.pem /etc/ipsec.d/certs/
cp -f /etc/letsencrypt/live/vpn.example.com/chain.pem /etc/ipsec.d/cacerts/
cp -f /etc/letsencrypt/live/vpn.example.com/privkey.pem /etc/ipsec.d/private/

# Reload certificates without restarting the service
ipsec rereadall

Grant permissions and run it once manually for the initial setup:

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/strongswan-reload.sh
sudo /etc/letsencrypt/renewal-hooks/deploy/strongswan-reload.sh

4. Configuring StrongSwan

Editing ipsec.conf

Here, we strictly define the cipher suites. By adding a ! at the end, we force the server to only use secure, modern encryption supported by all major OSes.

sudo nano /etc/ipsec.conf
config setup
    uniqueids=never

conn ikev2-vpn
    auto=add
    mobike=no
    compress=no
    type=tunnel
    keyexchange=ikev2
    ike=aes256gcm16-prfsha256-ecp256,aes256-sha256-modp2048!
    esp=aes256gcm16-ecp256,aes256-sha256!
    fragmentation=yes
    forceencaps=yes
    rekey=yes
    left=%any4
    leftid=@vpn.example.com
    leftcert=fullchain.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0
    right=%any4
    rightid=%any
    rightauth=eap-mschapv2
    rightsourceip=10.10.10.0/24
    rightdns=8.8.8.8,8.8.4.4
    rightsendcert=never
    eap_identity=%identity
    reauth=no
    ikelifetime=24h
    lifetime=24h
    dpddelay=30s
    dpdtimeout=120s
    dpdaction=clear

💡 Key Optimization Points for Stability

  • Why Let’s Encrypt? (No Client-Side Installation)
    Using a “Self-Signed” certificate requires you to manually install and “trust” a certificate file on every single device. By using Let’s Encrypt (a publicly trusted CA), no certificate installation is needed on the client side.
  • rightauth=eap-mschapv2 (User Auth)
    Combined with the public certificate, this allows users to connect instantly using just a username and password, much like logging into a website.
  • uniqueids=never
    Allows multiple devices (e.g., your Mac and iPhone) to stay connected simultaneously using the same account without dropping sessions.
  • mobike=no
    Disables the mobility protocol. While it sounds useful, disabling it significantly improves compatibility with the Windows native client and prevents issues in NAT environments.
  • reauth=no / rekey=yes
    Prevents momentary connection drops by performing key updates in the background.

Editing ipsec.secrets

sudo nano /etc/ipsec.secrets
# Private key
: RSA "privkey.pem"

# User credentials (username : EAP "password")
my_vpn_user : EAP "my_super_secret_password"

Editing strongswan.conf (Fixing Packet Clogs)

sudo nano /etc/strongswan.conf
charon {
        load_modular = yes
        keep_alive = 15
        plugins {
                include strongswan.d/charon/*.conf
                kernel-netlink {
                        mtu = 1380
                        mss = 1340
                }
        }
}
include strongswan.d/*.conf

5. Firewall and Routing

Enable IPv4 forwarding so VPN traffic can reach the internet.

sudo nano /etc/sysctl.conf

Enable net.ipv4.ip_forward=1 and apply with sudo sysctl -p.

Then, update ufw to enforce MSS clamping and allow IPsec traffic:

sudo nano /etc/ufw/before.rules
# --- (Add near the top under *nat) ---
*nat
-A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE
COMMIT

*mangle
-A FORWARD --match policy --pol ipsec --dir in -s 10.10.10.0/24 -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
COMMIT

# --- (Add inside *filter) ---
-A ufw-before-forward --match policy --pol ipsec --dir in --proto esp -s 10.10.10.0/24 -j ACCEPT
-A ufw-before-forward --match policy --pol ipsec --dir out --proto esp -d 10.10.10.0/24 -j ACCEPT

Reload ufw and restart StrongSwan:

sudo ufw reload
sudo systemctl restart strongswan-starter

💡 Why are MTU/MSS values different in two places?

We use a “two-tiered defense.” By restricting MSS to 1340 at the VPN entrance (StrongSwan) and capping it at 1360 at the network exit (ufw), we create a safety margin. This prevents “packet clogs” where websites fail to load due to encrypted packets exceeding the standard size limits.

6. Connection Test

Go to your device’s native VPN settings (e.g., iOS Settings > General > VPN) and create a new IKEv2 configuration:

  • Type: IKEv2
  • Description: Home VPN
  • Server: Your domain (e.g., vpn.example.com)
  • Remote ID: The leftid from your config, without the @ (e.g., vpn.example.com)
  • User Authentication: Username
  • Username / Password: As set in ipsec.secrets

No certificates or profiles need to be installed. Just enter your credentials and connect!

Conclusion

Setting up IKEv2 can be tricky due to iOS certificate requirements and Windows compatibility issues. However, once configured correctly, it provides a powerful, “zero-config” client-side experience. You get a secure, app-free VPN that works seamlessly across all your devices.