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
leftidfrom 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.