Setting up an L2TP/IPsec VPN on CentOS Stream 9 provides a reliable way to offer remote access to internal resources while preserving compatibility with a wide range of client devices (Windows, macOS, iOS, Android, and Linux). This guide walks you through a secure, production-ready configuration using strong authentication, hardened IPsec parameters, and appropriate firewall and kernel settings. It assumes root or sudo access to a CentOS Stream 9 server with a public IP.
Overview and components
An L2TP/IPsec VPN stack on CentOS Stream 9 typically consists of three main components:
- IPsec implementation (Libreswan or StrongSwan) — handles IKE and ESP for secure tunneling.
- xl2tpd — implements the L2TP protocol to provide the PPP layer for user sessions.
- pppd — negotiates authentication, IP address allocation, and routing options for VPN clients.
This guide uses Libreswan + xl2tpd + pppd because it supports classic L2TP/IPsec well and is widely used for compatibility with client devices that rely on L2TP. If you prefer certificate-based IKE or IKEv2-only deployments, consider StrongSwan, but the overall concepts here apply similarly.
Prerequisites
- CentOS Stream 9 server with a public IPv4 address.
- Sudo or root privileges.
- Basic familiarity with systemd, firewall-cmd, and editing files under /etc.
Step 1 — Install required packages
Enable EPEL and install Libreswan, xl2tpd and PPP:
sudo dnf install epel-release -y
sudo dnf update -y
sudo dnf install libreswan xl2tpd ppp -y
Ensure packages are the latest available and check release notes for CentOS Stream 9 packaging nuances.
Step 2 — Kernel and sysctl settings
Tune kernel parameters for routing, NAT, and IPsec forwarding. Create or edit /etc/sysctl.d/99-l2tp.conf with these recommended values:
net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
Apply immediately:
sudo sysctl --system
Note: Disabling rp_filter is necessary for asymmetric routing scenarios commonly encountered with VPN tunnels. Evaluate your topology before applying in complex environments.
Step 3 — Configure Libreswan (IPsec)
Edit /etc/ipsec.conf or create a minimal connection file in /etc/ipsec.d. Example connection snippet to support L2TP/IPsec with a strong PSK:
config setup
protostack=netkey
conn L2TP-PSK-NAT
right=%any
rightprotoport=17/1701
left=%defaultroute
leftprotoport=17/0
authby=secret
pfs=no
auto=add
keyingtries=3
ike=aes256-sha1;modp2048
phase2alg=aes256-sha1
Save and then add your pre-shared key to /etc/ipsec.secrets:
your.server.ip.address %any : PSK "ReplaceWithAStrongPSK"
Security tip: Use a long, random PSK or, for higher security, configure certificate-based authentication. PSKs are simpler for client configuration but can be weaker if reused or short.
Step 4 — Configure xl2tpd and PPP
Edit /etc/xl2tpd/xl2tpd.conf with a minimal configuration:
[global]
port = 1701
[lns default]
ip range = 10.10.10.10-10.10.10.200
local ip = 10.10.10.1
require chap = yes
refuse pap = yes
require authentication = yes
name = L2TPServer
Configure PPP options for xl2tpd in /etc/ppp/options.xl2tpd:
require-mschap-v2
ms-dns 8.8.8.8
ms-dns 8.8.4.4
asyncmap 0
auth
crtscts
lock
hide-password
mtu 1400
mru 1400
nodefaultroute
debug
MSS/MTU reductions (e.g., 1400) help avoid fragmentation across IPsec overhead and common NAT path MTU issues.
Finally, add user credentials to /etc/ppp/chap-secrets (format: username server password IP-address):
vpnuser L2TPServer StrongPasswordHere *
Prefer individual user accounts and long passwords. For production, integrate with RADIUS or LDAP for centralized auth.
Step 5 — Firewall and NAT
Open necessary ports and enable MASQUERADE for client traffic. Using firewalld:
sudo firewall-cmd --permanent --add-service="ipsec"
sudo firewall-cmd --permanent --add-port=1701/udp
sudo firewall-cmd --permanent --add-masquerade
Also allow ESP and AH if needed (firewalld ipsec service covers these). Reload:
sudo firewall-cmd --reload
If using rich rules or iptables directly, ensure UDP 500 and 4500 for IKE and NAT-T, UDP 1701 for L2TP, and an iptables SNAT/MASQUERADE rule on the external interface for outgoing client traffic.
Step 6 — Enable and start services
Start and enable Libreswan and xl2tpd:
sudo systemctl enable --now ipsec
sudo systemctl enable --now xl2tpd
Verify IPsec status and bring up the connection:
sudo ipsec verify
sudo ipsec auto --add L2TP-PSK-NAT
Check logs for IKE negotiations:
sudo journalctl -u ipsec -f
Step 7 — Testing and client configuration
On the client side, configure an L2TP/IPsec (PSK) connection pointing to the server public IP, using the PSK and username/password specified in chap-secrets. For Windows and mobile devices, enable “Use VPN with IPsec” and provide the pre-shared key. For macOS, select L2TP over IPsec and input the details likewise.
After connecting, verify:
- Assigned IP in the expected range (10.10.10.x in the example).
- Routing table contains a default or split route as intended.
- You can reach internal resources and the internet (if NAT is set).
- Logs on server show pppd and xl2tpd session establishment.
Troubleshooting checklist
- If IPsec fails to negotiate, check UDP 500/4500 reachability and IKE/ESP algorithm mismatches. Match
ikeandphase2algsettings on both ends. - Client connects but no traffic flows: confirm
net.ipv4.ip_forwardand MASQUERADE are configured; check rp_filter settings. - Frequent disconnects or slow throughput: adjust MTU/MRU in ppp options and enable NAT-T (UDP 4500).
- Examine /var/log/secure, journalctl -u xl2tpd, and /var/log/messages for authentication and routing errors.
Hardening and operational recommendations
- Prefer certificate-based IKE over PSKs in enterprise environments to reduce risk of key leakage; use a private CA and issue per-server certificates.
- Limit access by IP or firewall zones to only required networks and management hosts.
- Force strong cryptographic suites: prefer AES-GCM where supported and avoid weak ciphers like DES or MD5. Update ipsec.conf accordingly.
- Monitor logs and use fail2ban to mitigate brute-force attempts against PPP authentication.
- Consider integrating RADIUS for centralized authentication, accounting, and per-user policies.
Performance and scaling
For large numbers of concurrent users, offload crypto to CPUs with AES-NI, evaluate IKEv2 alternatives for lower connection churn, and consider horizontal scaling behind a load balancer with consistent NAT traversal strategies. Track kernel memory and pppd resource limits when designing for many sessions.
This configuration yields a broadly compatible L2TP/IPsec VPN on CentOS Stream 9 with attention to security, NAT traversal, and production readiness. For deployments requiring higher assurance or modern protocols, evaluate IKEv2 with StrongSwan or WireGuard as alternatives.
Published by Dedicated-IP-VPN