IPsec is the standard VPN protocol of the networking world. Office firewalls (FortiGate, pfSense, Cisco, MikroTik, Sophos) and cloud VPN gateways (AWS, Azure, Google Cloud) all speak it. When you need to connect your VPS or dedicated server to such equipment, WireGuard often isn’t an option, and strongSwan, the leading open-source IPsec implementation for Linux, is the tool.
For server-to-server links where you control both ends, WireGuard is simpler. See WireGuard site-to-site.
IPsec in brief
- IKE (IKEv2) negotiates keys and authenticates the peers, over UDP 500, then UDP 4500 when NAT is detected.
- ESP encrypts the actual traffic (IP protocol 50, or encapsulated in UDP 4500 behind NAT).
- Security associations (SAs) define what’s encrypted between which subnets (“traffic selectors”).
Both sides must agree on: IKE version, authentication method, encryption and integrity algorithms, DH group, lifetimes, and the local/remote subnets.
Example plan
| Your server (strongSwan) | Office firewall | |
|---|---|---|
| Public IP | 203.0.113.10 | 198.51.100.1 |
| Local subnet | 10.0.1.0/24 (or the server’s own IP /32) | 192.168.50.0/24 |
| Auth | Pre-shared key (or certificates) | same |
| Proposal | AES-256-GCM, SHA-256 PRF, DH group 19/20 (ECP) | same |
Install
sudo apt install strongswan strongswan-swanctl charon-systemd
sudo systemctl enable --now strongswan
(On RHEL-family systems: dnf install strongswan, service strongswan.)
Modern strongSwan is configured with swanctl (/etc/swanctl/swanctl.conf). The older ipsec.conf style still exists, but is deprecated.
Configure the tunnel
/etc/swanctl/conf.d/office.conf:
connections {
office {
version = 2
local_addrs = 203.0.113.10
remote_addrs = 198.51.100.1
proposals = aes256gcm16-prfsha256-ecp256
local {
auth = psk
id = 203.0.113.10
}
remote {
auth = psk
id = 198.51.100.1
}
children {
office-net {
local_ts = 10.0.1.0/24
remote_ts = 192.168.50.0/24
esp_proposals = aes256gcm16-ecp256
start_action = start
dpd_action = restart
}
}
dpd_delay = 30s
rekey_time = 8h
}
}
secrets {
ike-office {
id-1 = 203.0.113.10
id-2 = 198.51.100.1
secret = "a-very-long-random-pre-shared-key"
}
}
Generate a strong PSK with openssl rand -base64 48. For many tunnels or higher security, use certificates instead of PSKs (auth = pubkey with certificates in /etc/swanctl/x509/).
Load and start:
sudo swanctl --load-all
sudo swanctl --initiate --child office-net
sudo swanctl --list-sas
Configure the other side
On the firewall or cloud gateway, mirror the settings:
- IKEv2, the same PSK, IDs = the public IPs (or as configured);
- identical proposals (encryption, integrity/PRF, DH group) for both phase 1 (IKE) and phase 2 (ESP/child SA);
- local and remote subnets swapped.
Cloud gateways usually provide a downloadable config for “generic strongSwan”. Use it as the reference.
Firewall and forwarding on Linux
Open the IPsec ports to the peer:
sudo ufw allow from 198.51.100.1 to any port 500,4500 proto udp
# ESP (protocol 50), if no NAT-T is in use:
sudo iptables -A INPUT -p esp -s 198.51.100.1 -j ACCEPT
If the server routes for a subnet behind it, enable forwarding (net.ipv4.ip_forward=1), and make sure NAT rules don’t rewrite traffic headed into the tunnel. Exclude it from masquerading:
sudo iptables -t nat -I POSTROUTING -s 10.0.1.0/24 -d 192.168.50.0/24 -j ACCEPT
See NAT explained.
IPsec on Linux is policy-based by default: there’s no tunnel interface, and the kernel encrypts traffic matching the traffic selectors. For route-based setups (needed for dynamic routing or overlapping policies), strongSwan supports XFRM interfaces (if_id_in/if_id_out).
Test
ping -I 10.0.1.1 192.168.50.10 # source from the local subnet if needed
sudo swanctl --list-sas # established IKE SA + installed CHILD SA with traffic counters
sudo ip xfrm policy # kernel policies
sudo ip xfrm state # kernel SAs
Debugging
sudo journalctl -u strongswan -f
Typical problems:
| Log message / symptom | Cause |
|---|---|
NO_PROPOSAL_CHOSEN |
Algorithms or DH groups don’t match |
AUTHENTICATION_FAILED |
Wrong PSK, or mismatched IDs |
TS_UNACCEPTABLE |
Traffic selectors (subnets) don’t match the other side |
| SA up, but no traffic | Firewall or NAT rules, missing routes on LAN hosts, overlapping subnets |
| Tunnel drops every few hours | Rekey settings mismatched. Align lifetimes, enable DPD |
Increase logging temporarily in /etc/strongswan.d/charon-logging.conf (ike = 2, cfg = 2).
Remote-access IPsec (IKEv2) for devices
strongSwan can also serve IKEv2 VPN clients. Windows, macOS, iOS and Android have built-in IKEv2 clients, so no extra app is needed. It requires certificates (server certificate from a trusted CA) and EAP authentication. It’s more complex than WireGuard, but useful where installing apps isn’t allowed.
Quick reference
| Task | Command |
|---|---|
| Load config | swanctl --load-all |
| Start tunnel | swanctl --initiate --child NAME |
| Status | swanctl --list-sas |
| Kernel view | ip xfrm state / ip xfrm policy |
| Logs | journalctl -u strongswan |
| Ports | UDP 500, UDP 4500, ESP (50) |
Related: OpenVPN vs WireGuard and MTU explained.