Skip to main content Logo (IEC resistor symbol)logo

Quis custodiet ipsos custodes?
Home | About | All pages | RSS Feed | Gopher

IPSEC L2TP VPN on Arch Linux on a Raspberry Pi with OpenSwan, xl2tpd and ppp

Published: 01-12-2014 | Author: Remy van Elst | Text only version of this article

Table of Contents


The Raspberry Pi is a great little small computer, both for tinkering but alsoas a low power 24/7 running homeserver system. I've got multiple Pi's, onerunning as my home VPN gateway. It is running an IPSEC/L2TP VPN server. This isa guide on setting up an IPSEC/L2TP vpn server with Arch Linux on the RaspberryPi using Openswan as the IPsec server, xl2tpd as the l2tp provider and ppp orlocal users / PAM for authentication. It has a detailed explanation with everystep. We choose the IPSEC/L2TP protocol stack because of recent vulnerabilitiesfound in pptpd VPNs.

This tutorial is available for the following platforms:

If you like this article, consider sponsoring me by trying out a Digital OceanVPS. With this link you'll get $100 credit for 60 days). (referral link)

This tutorial was tested on a Raspberry Pi running Arch Linux ARM, installed viaNOOBS. It ran the current up to date Arch Linux ARM, here are the versions used:

IPSec encrypts your IP packets to provide encryption and authentication, so noone can decrypt or forge data between your clients and your server. L2TPprovides a tunnel to send data. It does not provide encryption andauthentication though, that is why we combine the two.

To work trough this tutorial you should have:

I do all the steps as the root user. You should do to, but only via sudo -i orsu -. Do not allow root to login via SSH!

Install ppp openswan and xl2tpd

First we will install the required packages:

pacman -Sy openswan xl2tpd ppp lsof python2

If you are running normal Arch (x86), you need to install OpenSWAN from the AUR.For the ARM/Pi version there is a package available. Python2 is required forOpenSWAN, but not listed as a dependency, therefore it is installed.

Firewall and sysctl

We are going to set the firewall and make sure the kernel forwards IP packets:

Execute this command to enable the iptables firewall to allow vpn traffic:

iptables --table nat --append POSTROUTING --jump MASQUERADE

Execute the below commands to enable kernel IP packet forwarding and disable ICPredirects.

echo "net.ipv4.ip_forward = 1" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.all.accept_redirects = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.all.send_redirects = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.default.rp_filter = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.default.accept_source_route = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.conf.default.send_redirects = 0" |  tee -a /etc/sysctl.confecho "net.ipv4.icmp_ignore_bogus_error_responses = 1" |  tee -a /etc/sysctl.conf

Set these settings for other network interfaces:

for vpn in /proc/sys/net/ipv4/conf/*; do echo 0 > $vpn/accept_redirects; echo 0 > $vpn/send_redirects; done

Apply them:

sysctl -p
Persistent settings via systemd

Arch Linux uses systemd. Init script functionality like rc.local is notavailable. To have these settings applied at boot we can however create a customsystemd service which starts at boot.

Add the following code to /usr/local/bin/

#!/usr/bin/env bashfor vpn in /proc/sys/net/ipv4/conf/*; do     echo 0 > $vpn/accept_redirects;     echo 0 > $vpn/send_redirects; doneiptables --table nat --append POSTROUTING --jump MASQUERADEsysctl -p

Make it executable:

chmod 755 /usr/local/bin/

Using the following systemd service we can start the script which sets the abovethings at boot:

Add the following code to /etc/systemd/system/vpnboot.service:

[Unit]Description=VPN Settings at bootAfter=netctl@eth0.serviceBefore=openswan.service xl2tpd.service[Service]ExecStart=/usr/local/bin/[Install] 

Then enable it:

systemctl enable vpnboot.service

Configure Openswan (IPSEC)

Use your favorite editor to edit the following file:

vim /etc/ipsec.conf  

Replace the contents with the following:

(Most lines have a comment below it explaining what it does.)

version 2 config setup    dumpdir=/var/run/pluto/    #in what directory should things started by setup (notably the Pluto daemon) be allowed to dump core?    nat_traversal=yes    #whether to accept/offer to support NAT (NAPT, also known as "IP Masqurade") workaround for IPsec    virtual_private=%v4:,%v4:,%v4:,%v6:fd00::/8,%v6:fe80::/10    #contains the networks that are allowed as subnet= for the remote client. In other words, the address ranges that may live behind a NAT router through which a client connects.    protostack=netkey    #decide which protocol stack is going to be used.    plutoopts="--interface=eth0"    # replace with your ethernet interface.    force_keepalive=yes    keep_alive=60    # Send a keep-alive packet every 60 seconds.conn L2TP-PSK-noNAT    authby=secret    #shared secret. Use rsasig for certificates.    pfs=yes    #Enable pfs    auto=add    #the ipsec tunnel should be started and routes created when the ipsec daemon itself starts.    keyingtries=3    #Only negotiate a conn. 3 times.    ikelifetime=8h    keylife=1h    type=transport    #because we use l2tp as tunnel protocol    left=%SERVERIP%    #fill in server IP above    leftprotoport=17/1701    right=%any    rightprotoport=17/%any    dpddelay=10    # Dead Peer Dectection (RFC 3706) keepalives delay    dpdtimeout=20    #  length of time (in seconds) we will idle without hearing either an R_U_THERE poll from our peer, or an R_U_THERE_ACK reply.    dpdaction=clear    # When a DPD enabled peer is declared dead, what action should be taken. clear means the eroute and SA with both be cleared.

Replace %SERVERIP% with the external IP of your Raspberry Pi. You can find itout by:

The shared secret

The shared secret is defined in the /etc/ipsec.secrets file. Make sure it islong and random:

%SERVERIP%  %any:   PSK "Your secret random key"

Again, replace %SERVERIP% with the external IP of your Raspberry Pi. If you wantto generate a random key you can use the following openssl command:

openssl rand -hex 30

Example output:

Verify IPSEC Settings

Now to make sure IPSEC works, execute the following command:

ipsec verify

My output looks like this:

 Checking if IPsec got installed and started correctly:Version check and ipsec on-path                     [OK]Openswan U2.6.39/K3.10.25-1-ARCH (netkey)See `ipsec --copyright' for copyright information.Checking for IPsec support in kernel                [OK] NETKEY: Testing XFRM related proc values         ICMP default/send_redirects                [OK]         ICMP default/accept_redirects              [OK]         XFRM larval drop                           [OK]Hardware random device check                        [N/A]Two or more interfaces found, checking IP forwarding    [OK]Checking rp_filter                                  [ENABLED] /proc/sys/net/ipv4/conf/default/rp_filter          [ENABLED] /proc/sys/net/ipv4/conf/eth0/rp_filter             [ENABLED] /proc/sys/net/ipv4/conf/ifb0/rp_filter             [ENABLED] /proc/sys/net/ipv4/conf/ifb1/rp_filter             [ENABLED]Checking that pluto is running                      [OK] Pluto listening for IKE on udp 500               fail in else:State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port    [FAILED] Pluto listening for IKE on tcp 500                 [NOT IMPLEMENTED] Pluto listening for IKE/NAT-T on udp 4500          [DISABLED] Pluto listening for IKE/NAT-T on tcp 4500          [NOT IMPLEMENTED] Pluto listening for IKE on tcp 10000 (cisco)       [NOT IMPLEMENTED]Checking NAT and MASQUERADEing                      [TEST INCOMPLETE]Checking 'ip' command                               [OK]Checking 'iptables' command                         [OK]ipsec verify: encountered errors

However, a netstat -tulpan shows that pluto is listening on the ports thatgive errors:

Active Internet connections (servers and established)Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name[...]udp        0      0*                           4624/plutoudp        0      0  *                           4443/xl2tpdudp        0      0 *                           4624/pluto[...]

Enable Openswan:

systemctl enable openswan

Configure xl2tpd

Use your favorite editor to edit the following file:


Replace the contents with the following:

[global]ipsec saref = yessaref refinfo = 30[lns default]ip range = ip = pap = yesrequire authentication = yesppp debug = yespppoptfile = /etc/ppp/options.xl2tpdlength bit = yes

Also create the following folder for xl2tpd's control file:

mkdir /var/run/xl2tpd/

Local user (PAM//etc/passwd) authentication

To use local user accounts via pam (or /etc/passwd), and thus not having plaintext user passwords in a text file you have to do a few extra steps. Huge thanksto Sascha Scandella for the hard work and troubleshooting.

In your /etc/xl2tpd/xl2tpd.conf add the following line:

unix authentication = yes

and remove the following line:

refuse pap = yes

In the file /etc/ppp/options.xl2tpd make sure you do not add the followingline (below it states to add it, but not if you want to use UNIXauthentication):


Also in that file (/etc/ppp/options.xl2tpd) add the following extra line:


Change /etc/pam.d/ppp to this:

auth    required        pam_nologin.soauth    required        pam_unix.soaccount required        pam_unix.sosession required

Add the following to /etc/ppp/pap-secrets:

*       l2tpd           ""              *

(And, skip the chap-secrets file below (adding users).)

Configuring PPP

Use your favorite editor to edit the following file:


Replace the contents with the following:

require-mschap-v2ms-dns 1200mru 1000crtsctshide-passwordmodemname l2tpdproxyarplcp-echo-interval 30lcp-echo-failure 4

Adding users

Every user should be defined in the /etc/ppp/chap-secrets file. Below is anexample file.

# Secrets for authentication using CHAP# client       server  secret                  IP addressesalice          l2tpd   0F92E5FC2414101EA            *bob            l2tpd   DF98F09F74C06A2F             *

Testing it

To make sure everything has the newest config files restart openswan and xl2tpd:

systemctl restart openswansystemctl restart xl2tpd

On the client connect to the server IP address (or add a DNS name) with a validuser, password and the shared secret. Test if you have internet access and whichIP you have (via for example If it is the VPN servers IPthen it works.

If you experience problems make sure to check the client log files. Also, onArch Linux, the system log can be viewed by using journalctl -f (that emulatestail -f /var/log/syslog). Arch Linux uses systemd logging. For more info aboutsystemd services, see this page

If you have your Raspberry Pi behind a NAT router, you might need to change your%SERVERIP% to the internal IP of your Raspberry Pi (like insteadof your external IP address.

If you google the error messages you most of the time get a good answer.

Thanks to Keith's article for help with boot persistency.

Tags: arch, ipsec, l2tp, openvpn, pptp, raspberry-pi, systemd, tutorials, vpn