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 ike and phase2alg settings on both ends.
  • Client connects but no traffic flows: confirm net.ipv4.ip_forward and 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