IKEv2/IPSec VPN Setup Guide (Ubuntu + Huawei/macOS Client)
IKEv2 Basics
Protocol Overview
- IKEv2 (Internet Key Exchange v2) is the signaling protocol; IPSec handles the actual encryption
- Transport: UDP only — port 500 (handshake) + port 4500 (NAT traversal)
- Two modes:
- Tunnel Mode — entire IP packet is encapsulated in ESP, client gets a virtual IP. Used for road warrior / mobile clients
- Transport Mode — only payload is encrypted, both endpoints keep real IPs. Used for server-to-server encryption
Authentication Methods
| Type | Description |
|---|---|
| PSK | Pre-shared key, simplest to configure |
| MSCHAPv2 | PSK + username/password via EAP |
| RSA | Certificate-based, most secure |
Key Concepts
- SA (Security Association) — negotiated session parameters (keys, algorithms)
- DPD (Dead Peer Detection) — heartbeat mechanism.
dpddelay=300smeans send a probe after 300s idle - NAT-T — when NAT is detected, traffic switches from UDP/500 to UDP/4500 automatically
- MASQUERADE — dynamic SNAT, replaces client virtual IP with server's public IP. Third-party servers only see the VPN server's IP
Server Setup (Ubuntu)
1. Install strongSwan
apt update && apt install strongswan strongswan-pki libcharon-extra-plugins -y
2. /etc/ipsec.conf
config setup
charondebug="ike 1, knl 1, cfg 0"
conn ikev2-psk
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
ike=aes256-sha256-modp2048!
esp=aes256-sha256!
dpdaction=clear
dpddelay=300s
rekey=no
left=%any
leftid=@myserver # must match client's Remote ID
leftsubnet=0.0.0.0/0 # routes pushed to client (0.0.0.0/0 = full tunnel)
right=%any
rightid=%any
rightsourceip=10.10.30.0/24 # virtual IP pool for clients
rightdns=8.8.8.8
authby=secret
leftauth=psk
rightauth=psk
Field notes:
leftid— server identity used for PSK lookup. Use@stringprefix to avoid being parsed as IPforceencaps=yes— force NAT-T even without NAT, improves traversalike=...!—!means strict match, no fallback negotiationrightsourceip— must be a valid CIDR range, never0.0.0.0
3. /etc/ipsec.secrets
: PSK "your_strong_password_here"
4. Enable IP Forwarding
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
5. /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
udp dport { 500, 4500 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
# IKEv2 clients (routed through enp1s0, no tun device)
iif "enp1s0" oif "enp1s0" ip saddr 10.10.30.0/24 accept
iif "enp1s0" oif "enp1s0" ip daddr 10.10.30.0/24 ct state established,related accept
# ICMP diagnostics
icmp type { time-exceeded, destination-unreachable, echo-reply } accept
}
chain postrouting {
type nat hook postrouting priority 100;
ip saddr 10.10.30.0/24 oif "enp1s0" masquerade
}
}
Replace enp1s0 with your actual interface (ip link to verify).
6. Start Services
systemctl restart strongswan-starter
systemctl enable strongswan-starter
systemctl restart nftables
systemctl enable nftables
Note: On Ubuntu 22.04+, the service is
strongswan-starter, notstrongswan
Client Configuration
Huawei (EMUI/HarmonyOS)
Huawei only supports the three built-in IKEv2 types — no OpenVPN or WireGuard native support.
Settings → Wi-Fi & Network → VPN → Add
| Field | Value |
|---|---|
| Type | IKEv2/IPSec PSK |
| Server | server public IP |
| IPSec identifier | same as server leftid (e.g. myserver) |
| IPSec pre-shared key | your PSK password |
macOS
System Settings → VPN → Add VPN Configuration → IKEv2
| Field | Value |
|---|---|
| Server | server public IP |
| Remote ID | same as server leftid |
| Local ID | leave blank |
| Authentication | Shared Secret |
| Shared Secret | your PSK password |
Troubleshooting
Check Logs
journalctl -u strongswan-starter -f
Common Errors
| Log Message | Cause | Fix |
|---|---|---|
AUTH_FAILED |
PSK mismatch or leftid mismatch | Verify leftid matches client Remote ID; check ipsec.secrets for typos |
DH group unacceptable |
Client proposes different DH group | Normal — strongSwan sends INVAL_KE and renegotiates, connection proceeds |
no config found |
No matching conn for client | Check rightid=%any and auto=add |
| Stuck at "Connecting" | Packet not reaching server | Check cloud security group (UDP 500/4500), verify with ss -ulnp | grep -E "500|4500" |
Verify Listening Ports
ss -ulnp | grep -E "500|4500"
Verify nftables
nft list ruleset
Reload Config Without Restart
ipsec reload
ipsec statusall
Notes
- Cloud security groups (Alibaba Cloud, AWS, etc.) must allow UDP 500 and 4500 inbound — nftables alone is not enough
- leftid as plain number will be parsed as IP address by charon. Always use
@prefixfor non-IP identifiers - DPD vs UDP timeout: if using a UDP proxy (e.g. v2ray dokodemo-door), set
dpddelaylower than the proxy's UDP session timeout (default 60s), e.g.dpddelay=50s - IKEv2 routing mode (no tun device) is more efficient than OpenVPN (userspace) — kernel-level forwarding with AES-NI hardware acceleration