Today I will be going over how to bring up a L2TP+IPSec VPN on OpenBSD. I am doing this because while I have been operating my own WireGuard VPN servers for the past few months now, I have experienced issues when the WireGuard server initiates over 100 connections. I know WireGuard is obviously still beta software, and that the issues could be caused by multiple things, but I wanted to give another option a shot.

Having set up WireGuard VPNs multiple times, I can say that setting up this new VPN was slightly more complicated, as there are more moving parts. However, the tools install on OpenBSD have been around a long time and have been thoroughly bug tested. Though, WireGuard does seem to be a quicker setup. However, the tools available in OpenBSD, namely ipsecctl, isakmpd, pppd and pf definitely have the ability to be tweaked more than WireGuard at this time.

1. Apply proper sysctl parameters to server


Enable all settings by running this for loop:

for i in $(cat /etc/sysctl.conf); do sysctl $i;done

Next up, we need to configure npppd. The default config already has the complete framework set, however, we do need to tweak the last few lines slightly. We want the tunnels to utilize a single interface for now, and the default is to create an interface per-session. Modify the ending of npppd.conf to be as below:

# use pppx(4) interface.  use an interface per a ppp session.
#interface pppx0 address ipcp IPCP
#bind tunnel from L2TP authenticated by LOCAL to pppx0

# use tun(4) interface.  multiple ppp sessions concentrate one interface.
interface tun0  address ipcp IPCP
bind tunnel from L2TP authenticated by LOCAL to tun0

Now we need to create a user to log in as over the tunnel. Modify the existing npppd-users file with a user at the bottom of the file:


Creating an ipsec tunnel on openbsd is rather simple. We simply need to add a couple lines into the ipsec.conf. You can specify one of multiple security “groups”, of which the default is modp3072. As apparently this is rather high, we can also drop down the level of security, but do so at your own discretion. You can read about the groups with man ipsec.conf. iPhones will not authenticate above modp1024 to the best of my knowledge. The password listed here is the “group” password requested from clients when they connect.

ike passive esp tunnel from <server public ip> to any \
    main group "modp1024" quick group "modp1024" \
    psk "<password>"

This is the configuration that I am going with currently on my testing VPN server. This is pretty bare, and could obviously be tweaked for your own purposes.

vpn_if = "tun0"
vpn_net = ""

set loginterface egress

set skip on { lo enc0 }

block return    # block stateless traffic

match out log on egress inet from !(egress:network) to any nat-to (egress:0)

# allow esp protocol
pass in log on egress proto esp

# allow ssh connection
pass in log on egress proto tcp to any port 22

# allow tcp and udp connections for ipsec and l2tp
pass in log on egress proto { tcp udp } to port { 500 4500 1701 }

# allow icmp requests
pass in log on egress proto icmp

# allow all IPSec traffic
pass log on enc0 keep state (if-bound)

# Allow IPv4 traffic in on vpn interface
pass in on $vpn_if inet

# allow all traffic out to the VPN network
pass log on $vpn_if to $vpn_net
pass out log on egress from any to any keep state

Now we will actually start the VPN server.

rcctl enable ipsec isakmpd npppd
rcctl set isakmpd flags -K
rcctl start ipsec isakmpd npppd

# Inject ipsec.conf
ipsecctl -f /etc/ipsec.conf

This should initialize the tunnel, allowing clients to connect to the VPN server.

You can check to see if clients have created ipsec flows with ipsecctl -sa. You can also see if any clients are logged in npppd with the command npppd session all.

More notes

For more info, read the docs from the folks over with OpenBSD.

In order to allow chromebooks to connect, the following ipsec.conf is required:

ike dynamic esp transport from <vpn ip> to any \
    main group "modp1024" auth hmac-sha1 enc 3des\
    quick group "modp1024" auth hmac-sha1 enc 3des \
    psk "<my psk>"

Has been tested on OpenBSD 6.5