GUIDE / VPN / L2TP+IPSEC

L2TP/IPsec.

L2TP (the tunnelling protocol) on top of IPsec (the encryption) is the native road-warrior VPN that Windows, macOS, and iOS clients have shipped for over a decade. Pick it when the client platform doesn't have WireGuard support — RouterOS v6 routers, older corporate-managed Windows boxes, iOS devices behind MDM that blocks third-party VPN apps. Android dropped native L2TP/IPsec in Android 12; install the strongSwan app there.

Step 1 — IPsec policy template + proposal

L2TP/IPsec uses a slightly different IPsec setup from site-to-site: transport mode, dynamic policy generation. RouterOS has a special "policy template" for this.

v6 6 lines · 232 bytes
/ip ipsec profile add name=l2tp \
  hash-algorithm=sha256 enc-algorithm=aes-256 \
  dh-group=modp2048 lifetime=1h
/ip ipsec proposal add name=l2tp \
  auth-algorithms=sha256 enc-algorithms=aes-256-cbc \
  pfs-group=none lifetime=30m
v7 6 lines · 232 bytes
/ip/ipsec/profile add name=l2tp \
  hash-algorithm=sha256 enc-algorithm=aes-256 \
  dh-group=modp2048 lifetime=1h
/ip/ipsec/proposal add name=l2tp \
  auth-algorithms=sha256 enc-algorithms=aes-256-cbc \
  pfs-group=none lifetime=30m

Step 2 — IPsec peer + identity (pre-shared key)

v6 5 lines · 238 bytes
/ip ipsec peer add name=l2tp-roadwarrior passive=yes profile=l2tp \
  send-initial-contact=no
/ip ipsec identity add peer=l2tp-roadwarrior \
  auth-method=pre-shared-key generate-policy=port-strict \
  secret="<long-random-shared-secret>"
v7 5 lines · 238 bytes
/ip/ipsec/peer add name=l2tp-roadwarrior passive=yes profile=l2tp \
  send-initial-contact=no
/ip/ipsec/identity add peer=l2tp-roadwarrior \
  auth-method=pre-shared-key generate-policy=port-strict \
  secret="<long-random-shared-secret>"

generate-policy=port-strict tells RouterOS to generate the IPsec policy dynamically per-client based on the L2TP source port, which is what road-warrior shapes need.

Step 3 — IP pool + PPP profile for L2TP users

v6 4 lines · 229 bytes
/ip pool add name=l2tp-pool ranges=10.20.20.10-10.20.20.50
/ppp profile add name=l2tp-profile local-address=10.20.20.1 \
  remote-address=l2tp-pool dns-server=10.20.20.1 \
  change-tcp-mss=yes use-encryption=required only-one=yes
v7 4 lines · 229 bytes
/ip/pool add name=l2tp-pool ranges=10.20.20.10-10.20.20.50
/ppp/profile add name=l2tp-profile local-address=10.20.20.1 \
  remote-address=l2tp-pool dns-server=10.20.20.1 \
  change-tcp-mss=yes use-encryption=required only-one=yes

Step 4 — L2TP server

v6 4 lines · 171 bytes
/interface l2tp-server server set enabled=yes \
  default-profile=l2tp-profile use-ipsec=required \
  ipsec-secret="<long-random-shared-secret>" \
  authentication=mschap2
v7 4 lines · 171 bytes
/interface/l2tp-server/server set enabled=yes \
  default-profile=l2tp-profile use-ipsec=required \
  ipsec-secret="<long-random-shared-secret>" \
  authentication=mschap2

The ipsec-secret here MUST match the secret in the IPsec identity above. use-ipsec=required means L2TP without IPsec is refused (the right posture; bare L2TP is unencrypted).

Step 5 — Add a user

v6 2 lines · 95 bytes
/ppp secret add name=alice service=l2tp profile=l2tp-profile \
  password="<per-user-password>"
v7 2 lines · 95 bytes
/ppp/secret add name=alice service=l2tp profile=l2tp-profile \
  password="<per-user-password>"

One secret per user. Different from the IPsec PSK — the IPsec PSK is a single shared secret; each user gets their own username + password on top.

Step 6 — Firewall

v6 7 lines · 479 bytes
# Accept IPsec NAT-T (UDP/4500) + IKE (UDP/500) + L2TP (UDP/1701) on WAN
/ip firewall filter add chain=input action=accept protocol=udp dst-port=500,1701,4500 in-interface-list=WAN
# Accept IPsec ESP (50)
/ip firewall filter add chain=input action=accept protocol=ipsec-esp in-interface-list=WAN
# Treat L2TP-side traffic like LAN
/ip firewall filter add chain=forward action=accept in-interface=l2tp-in1
/ip firewall filter add chain=forward action=accept out-interface=l2tp-in1
v7 4 lines · 347 bytes
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=500,1701,4500 in-interface-list=WAN
/ip/firewall/filter add chain=input action=accept protocol=ipsec-esp in-interface-list=WAN
/ip/firewall/filter add chain=forward action=accept in-interface=l2tp-in1
/ip/firewall/filter add chain=forward action=accept out-interface=l2tp-in1

Client setup

Every modern OS has L2TP/IPsec in its system VPN settings. You need three things on the client:

  • Server address: your router's public IP or DDNS hostname.
  • Pre-shared key (IPsec): the secret you set above.
  • Username + password (PPP): per-user, from step 5.

Behind CGN

L2TP/IPsec needs the server to be reachable on UDP 500, 1701, 4500 AND IP protocol 50 (ESP). Most CGN ISPs do NAT-T fine (the 4500 fallback exists for exactly this), but if you can't open UDP 500 inbound at all, L2TP/IPsec won't work. WireGuard's single-UDP-port is more forgiving — see the remote access hierarchy.

Verify

v6 3 lines · 87 bytes
/ppp active print
/ip ipsec active-peers print
/log print where topics~"l2tp,ipsec,ppp"
v7 3 lines · 87 bytes
/ppp/active print
/ip/ipsec/active-peers print
/log print where topics~"l2tp,ipsec,ppp"