L2TP over IPsec using OpenSwan with Freeradius authentication on Ubuntu 16.04

This article is about the layer 2 tunneling protocol (L2TP) with IPsec to provide end-to-end encryption in the layer 2 VPN because security features are not available in L2TP.  The open source implementations of IPsec are StrongSwan and OpenSwan, both are supported on all Linux distributions. In this tutorial, OpenSwan is used to provide the security channel for L2TP VPN. Freeradius is a well-known open source tool which provides different types of authentication for users. Freeradius is used to authenticate the L2TP VPN user before establishing a secure channel. An android based client will be used for the L2TP based secure tunnel.

Installation of required packages

Following important packages will be installed on the Ubuntu 16.04 LTS. 

  • Freeradius Server/Client
  • Poptop Server
  • xl2tpd
  • Openswan for IPsec
  • MySQL Server/client
  • Bison & Flex
  • GMP development library

As shown below, most of the required packages are all available in the Ubuntu 16.04 LTS repository.

apt-get update

Update the Ubuntu Repository

apt-get install -y mysql-server mysql-client freeradius-mysql pptpd xl2tpd

Installing Ubuntu packages

The following screenshot shows how the password for the user "root" of the MySQL database server is being set during the installation process.

Set MySQL root password

The following packages are required for the OpenSwan installation from source on the Ubuntu 16.04 platform.

apt-get install -y build-essential libgmp3-dev bison flex

The Freeradius client and OpenSwan packages are not available in the repository, so both tools have been installed from source.

Installation of the Freeradius client

Download the latest Freeradius client from the following link:

wget https://github.com/FreeRADIUS/freeradius-client/archive/master.zip
unzip master.zip

Download and unpack Freeradius

mv freeradius-client-master freeradius-client
cd freeradius-client

Change Freeradius folder

First, run the configure script with the prefix switch and install the software using the make command.

./configure --prefix=/

Configure Freeradius

make && make install

Build Freeradius

Installation of OpenSwan

The source code of the OpenSwan IPsec tool is available on the following link. Download the archive and unpack it.

wget https://download.openswan.org/openswan/openswan-latest.tar.gz
tar -xzf openswan-latest.tar.gz
cd openswan-*

Download OpenSwan

Run the following command to compile and install OpenSwan.

make programs

Compile OpenSwan

make install  

Install OpenSwan with make.


Before we start with the configuration of the installed packages, the following base configurations (iptables and sysctl) are required on the Ubuntu platform.

Enter following iptables rules for both networks ( & on the terminal.

iptables -t nat -I POSTROUTING -s -j SNAT --to
iptables -t nat -I POSTROUTING -s -j SNAT --to

Configure IPTables

Above rules should be saved into the /etc/iptables.rc file to apply them at boot time.

Save iptables rules

chmod +x /etc/iptables.rc
sed -i "/iptables.rc/d" /etc/rc.local
sed -i "1a/etc/iptables.rc" /etc/rc.local

Edit rc.local content

Add the following lines in the /etc/sysctl.conf file to enable forwarding on the Linux machine.

net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.icmp_ignore_bogus_error_responses = 1

Enable Forwarding

Run the following command to apply changes.

sysctl -p

apply sysctl changes
Configuration of the Freeradius Server

Run the following command to change the password for freeradius.

sed -i "s/PASSWORD('radpass')/PASSWORD('test')/g" /etc/freeradius/sql/mysql/admin.sql

Change Freeradius password

The following MySQL commands will configure the Freeradius server on Ubuntu.

mysql --protocol=tcp -h localhost -u root -ptest
create database radius  # create DB radius

Create the Radius MySQL database

mysql --protocol=tcp -h localhost -u root -ptest radius < /etc/freeradius/sql/mysql/admin.sql

Connect to MySQL

mysql --protocol=tcp -h localhost -u root -ptest radius < /etc/freeradius/sql/mysql/cui.sql

Import Freeradius MySQL database scheme

Adding a proper date to fix the invalid default value issue in /etc/freeradius/sql/mysql/cui.sql.

Fix date issue

After correction in the /etc/freeradius/sql/mysql/cui.sql file and rerun above command to fix the above error.

Rerun command

mysql --protocol=tcp -h localhost -u root -ptest radius < /etc/freeradius/sql/mysql/ippool.sql

Import MySQL DB Scheme

mysql --protocol=tcp -h localhost -u root -ptest radius < /etc/freeradius/sql/mysql/nas.sql

Import MySQL DB Scheme

mysql --protocol=tcp -h localhost -u root -ptest radius < /etc/freeradius/sql/mysql/schema.sql

Import MySQL DB Scheme

mysql --protocol=tcp -h localhost -u root -ptest radius < /etc/freeradius/sql/mysql/wimax.sql

Import MySQL DB Scheme
Run the folowing sed command to change the default password of user "radius".  In this tutorial, the password for the user "radius" is "test". Chose a secure password on your server.

sed -i "s/password = \"radpass\"/password = \"test\"/g" /etc/freeradius/sql.conf

Change radius password

Creating a soft link for the sql configuration in the modules directory of the Freeradius server.

ln -sf /etc/freeradius/sql.conf /etc/freeradius/modules/sql

Create link to sql configuration
Following files are not present on Ubuntu 16.04, therefore, create all required files with the described content.

  • /etc/freeradius/modules/hourlylytraffic
  • /etc/freeradius/modules/dailytraffic
  • /etc/freeradius/modules/monthlytraffic


sqlcounter hourlytrafficcounter {
    counter-name = Hourly-Traffic
    check-name = Hourly-Traffic
    sqlmod-inst = sql
    key = User-Name
    reset = 1h
    query = "SELECT SUM(acctinputoctets + acctoutputoctets) DIV 1048576 FROM radacct WHERE UserName='%{%k}' AND UNIX_TIMESTAMP(AcctStartTime) > '%b'"


sqlcounter dailytrafficcounter {
    counter-name = Daily-Traffic
    check-name = Daily-Traffic
    sqlmod-inst = sql
    key = User-Name
    reset = daily
    query = "SELECT SUM(acctinputoctets + acctoutputoctets) DIV 1048576 FROM radacct WHERE UserName='%{%k}' AND UNIX_TIMESTAMP(AcctStartTime) > '%b'"


sqlcounter monthlytrafficcounter {
    counter-name = Monthly-Traffic
    check-name = Monthly-Traffic
    sqlmod-inst = sql
    key = User-Name
    reset = monthly
    query = "SELECT SUM(acctinputoctets + acctoutputoctets) DIV 1048576 FROM radacct WHERE UserName='%{%k}' AND UNIX_TIMESTAMP(AcctStartTime) > '%b'"

The following file is important for freeradius server configuration. Our running configurations are given below.


authorize {
    eap {
        ok = return
authenticate {
    Auth-Type PAP {
    Auth-Type CHAP {
    Auth-Type MS-CHAP {
preacct {
accounting {
session {
post-auth {
    Post-Auth-Type REJECT {
pre-proxy {
post-proxy {

Use the following command to restart the freeradius server and to verify the configuration.

/etc/init.d/freeradius restart

Restart Freeradius

Configuration of the Freeradius client

Following command sets the hostname and secret in the "servers" file of the freeradius client. 

echo -e "localhost\ttesting123" >> /etc/radiusclient/servers

    Set Freeradius Hostname

Create the dictionary.microsoft configuration file for Windows based clients.

vi /etc/radiusclient/dictionary.microsoft
#       Microsoft's VSA's, from RFC 2548
#       \$Id: poptop_ads_howto_8.htm,v 1.8 2008/10/02 08:11:48 wskwok Exp \$
VENDOR          Microsoft       311     Microsoft
BEGIN VENDOR    Microsoft
ATTRIBUTE       MS-CHAP-Response        1       string  Microsoft
ATTRIBUTE       MS-CHAP-Error           2       string  Microsoft
ATTRIBUTE       MS-CHAP-CPW-1           3       string  Microsoft
ATTRIBUTE       MS-CHAP-CPW-2           4       string  Microsoft
ATTRIBUTE       MS-CHAP-LM-Enc-PW       5       string  Microsoft
ATTRIBUTE       MS-CHAP-NT-Enc-PW       6       string  Microsoft
ATTRIBUTE       MS-MPPE-Encryption-Policy 7     string  Microsoft
# This is referred to as both singular and plural in the RFC.
# Plural seems to make more sense.
ATTRIBUTE       MS-MPPE-Encryption-Type 8       string  Microsoft
ATTRIBUTE       MS-MPPE-Encryption-Types  8     string  Microsoft
ATTRIBUTE       MS-RAS-Vendor           9       integer Microsoft
ATTRIBUTE       MS-CHAP-Domain          10      string  Microsoft
ATTRIBUTE       MS-CHAP-Challenge       11      string  Microsoft
ATTRIBUTE       MS-CHAP-MPPE-Keys       12      string  Microsoft encrypt=1
ATTRIBUTE       MS-BAP-Usage            13      integer Microsoft
ATTRIBUTE       MS-Link-Utilization-Threshold 14 integer        Microsoft
ATTRIBUTE       MS-Link-Drop-Time-Limit 15      integer Microsoft
ATTRIBUTE       MS-MPPE-Send-Key        16      string  Microsoft
ATTRIBUTE       MS-MPPE-Recv-Key        17      string  Microsoft
ATTRIBUTE       MS-RAS-Version          18      string  Microsoft
ATTRIBUTE       MS-Old-ARAP-Password    19      string  Microsoft
ATTRIBUTE       MS-New-ARAP-Password    20      string  Microsoft
ATTRIBUTE       MS-ARAP-PW-Change-Reason 21     integer Microsoft
ATTRIBUTE       MS-Filter               22      string  Microsoft
ATTRIBUTE       MS-Acct-Auth-Type       23      integer Microsoft
ATTRIBUTE       MS-Acct-EAP-Type        24      integer Microsoft
ATTRIBUTE       MS-CHAP2-Response       25      string  Microsoft
ATTRIBUTE       MS-CHAP2-Success        26      string  Microsoft
ATTRIBUTE       MS-CHAP2-CPW            27      string  Microsoft
ATTRIBUTE       MS-Primary-DNS-Server   28      ipaddr
ATTRIBUTE       MS-Secondary-DNS-Server 29      ipaddr
ATTRIBUTE       MS-Primary-NBNS-Server  30      ipaddr Microsoft
ATTRIBUTE       MS-Secondary-NBNS-Server 31     ipaddr Microsoft
#ATTRIBUTE      MS-ARAP-Challenge       33      string  Microsoft
#       Integer Translations
#       MS-BAP-Usage Values
VALUE           MS-BAP-Usage            Not-Allowed     0
VALUE           MS-BAP-Usage            Allowed         1
VALUE           MS-BAP-Usage            Required        2
#       MS-ARAP-Password-Change-Reason Values
VALUE   MS-ARAP-PW-Change-Reason        Just-Change-Password            1
VALUE   MS-ARAP-PW-Change-Reason        Expired-Password                2
VALUE   MS-ARAP-PW-Change-Reason        Admin-Requires-Password-Change  3
VALUE   MS-ARAP-PW-Change-Reason        Password-Too-Short              4
#       MS-Acct-Auth-Type Values
VALUE           MS-Acct-Auth-Type       PAP             1
VALUE           MS-Acct-Auth-Type       CHAP            2
VALUE           MS-Acct-Auth-Type       MS-CHAP-1       3
VALUE           MS-Acct-Auth-Type       MS-CHAP-2       4
VALUE           MS-Acct-Auth-Type       EAP             5
#       MS-Acct-EAP-Type Values
VALUE           MS-Acct-EAP-Type        MD5             4
VALUE           MS-Acct-EAP-Type        OTP             5
VALUE           MS-Acct-EAP-Type        Generic-Token-Card      6
VALUE           MS-Acct-EAP-Type        TLS             13
END-VENDOR Microsoft

The dictionary.microsoft file

vi /etc/radiusclient/dictionary.merit
#       Experimental extensions, configuration only (for check-items)
#       Names/numbers as per the MERIT extensions (if possible).
ATTRIBUTE       NAS-Identifier          32      string
ATTRIBUTE       Proxy-State             33      string
ATTRIBUTE       Login-LAT-Service       34      string
ATTRIBUTE       Login-LAT-Node          35      string
ATTRIBUTE       Login-LAT-Group         36      string
ATTRIBUTE       Framed-AppleTalk-Link   37      integer
ATTRIBUTE       Framed-AppleTalk-Network 38     integer
ATTRIBUTE       Framed-AppleTalk-Zone   39      string
ATTRIBUTE       Acct-Input-Packets      47      integer
ATTRIBUTE       Acct-Output-Packets     48      integer
# 8 is a MERIT extension.
VALUE           Service-Type            Authenticate-Only       8

Add the following lines to the /etc/radiusclient/dictionary file.

INCLUDE /etc/radiusclient/dictionary.merit
INCLUDE /etc/radiusclient/dictionary.microsoft
ATTRIBUTE Hourly-Traffic 1000 integer
ATTRIBUTE Daily-Traffic 1001 integer
ATTRIBUTE Monthly-Traffic 1002 integer

The following is the run configuration of the radius client.

# General settings
# specify which authentication comes first respectively which
# authentication is used. possible values are: "radius" and "local".
# if you specify "radius,local" then the RADIUS server is asked
# first then the local one. if only one keyword is specified only
# this server is asked.
auth_order    radius,local
# maximum login tries a user has
login_tries    4
# timeout for all login tries
# if this time is exceeded the user is kicked out
login_timeout    60
# name of the nologin file which when it exists disables logins. it may
# be extended by the ttyname which will result in
#a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable
# logins on /dev/ttyS2)
nologin /etc/nologin
# name of the issue file. it's only display when no username is passed
# on the radlogin command line
issue    /etc/radiusclient/issue
seqfile /var/run/freeradius/freeradius.pid

## RADIUS listens separated by a colon from the hostname. if
# no port is specified /etc/services is consulted of the radius
authserver     localhost
# RADIUS server to use for accouting requests. All that I
# said for authserver applies, too.
acctserver     localhost

# file holding shared secrets used for the communication
# between the RADIUS client and server
servers        /etc/radiusclient/servers
# dictionary of allowed attributes and values just like in the normal
# RADIUS distributions
dictionary     /etc/radiusclient/dictionary

# program to call for a RADIUS authenticated login
login_radius    /sbin/login.radius
# file which specifies mapping between ttyname and NAS-Port attribute
mapfile        /etc/radiusclient/port-id-map
# default authentication realm to append to all usernames if no
# realm was explicitly specified by the user

# time to wait for a reply from the RADIUS server
radius_timeout    10
# resend request this many times before trying the next server
radius_retries    3
# local address from which radius packets have to be sent
bindaddr *
# program to execute for local login
# it must support the -f flag for preauthenticated login
login_local    /bin/login

Radius Client configuration
Following configuration (which is related to IPv6)  in /etc/radiusclient/dictionary file should be commented out to run the radius client.

ATTRIBUTE       NAS-Filter-Rule         92      string
ATTRIBUTE       Originating-Line-Info   94      string
ATTRIBUTE       NAS-IPv6-Address        95      string
ATTRIBUTE       Framed-Interface-Id     96      string
ATTRIBUTE       Framed-IPv6-Prefix      97      ipv6prefix
ATTRIBUTE       Login-IPv6-Host         98      string
ATTRIBUTE       Framed-IPv6-Route       99      string
ATTRIBUTE       Framed-IPv6-Pool        100     string
ATTRIBUTE       Error-Cause             101     integer
ATTRIBUTE       EAP-Key-Name            102     string
#       RFC6911 IPv6 attributes
ATTRIBUTE       Framed-IPv6-Address     168     ipv6addr
ATTRIBUTE       DNS-Server-IPv6-Address 169     ipv6addr
ATTRIBUTE       Route-IPv6-Information  170     ipv6prefix

Configuration of the Poptop server

Add the following configuration in the /etc/pptpd.conf file.


Run  following sed command on the /etc/ppp/pptpd-options file.

sed -i "/^ms-dns/d" /etc/ppp/pptpd-options
sed -i -e "/radius.so/d" -e "/radattr.so/d" /etc/ppp/pptpd-options

Add the following lines in /etc/ppp/pptpd-options file.

plugin /usr/lib/pppd/2.4.7/radius.so
plugin /usr/lib/pppd/2.4.7/radattr.so

Restart the pptpd service to apply the above changes.

service pptpd restart

Configuration of xl2tp

Include following configuration lines in the /etc/xl2tpd/xl2tpd.conf file as shown in following figure.

ipsec saref = yes

[lns default]
ip range =
local ip =
refuse chap = yes
refuse pap = yes
require authentication = yes
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes

Configuration of OpenSwan

Add the following setting of the ipsec secret file in  /etc/ipsec.secrets. %any PSK "test"

IPsec configuration for L2TP tunnel is included in /etc/ipsec.conf file.

version 2.0    

config setup
        #protostack=mast  # used for SAref + MAST only

conn psk-l2tp
        # overlapip=yes   # for SAref + MAST
        # sareftrack=yes  # for SAref + MAST

Configuration of PPP server

Add the following configuration in /etc/ppp/options.xl2tpd file.

idle 1800
mtu 1200
mru 1200
connect-delay 5000
plugin /usr/lib/pppd/2.4.7/radius.so
plugin /usr/lib/pppd/2.4.7/radattr.so

After successful configuration of all required packages, now restart all services to test L2TP VPN.

Restarting IPsec & xl2tp services.

The following figure shows that the freeradius server is running in daemon mode which is helpful to identify that the server is working.

Insert a user account in the MySQL database to test the configuration.

INSERT INTO radius.radcheck (username, attribute, op, value) VALUES ('username','User-Password',':=','userpassword');

The following command checks that the Freeradius server is working on localhost.

radtest username userpassword localhost 0 testing123

Configuration of L2TP Android client

Go to settings  ==> More ==> VPN ==>Add VPN Network on android phone and create new L2TP PSK VPN as shown below.

After creation of new L2TP VPN, click on it and enter username/password (configured on the the freeradius server).

Following figure shows that L2TP VPN is connecting.

Following screens shows that L2TP VPN is successfully connected using an android client.


L2TP VPN Status

Freeradius shows the successful authentication of L2TP android client.

Following command shows the IPsec tunnel status

ip xfrm state

OpenSwan log (/var/log/auth.log) and xl2tp log (/var/log/syslog) also shows the status of L2TP VPN.

tail -f /var/log/auth.log

tail -f /var/log/syslog

In this tutorial, layer 2 tunneling protocol is used with IPSec and Freeradius to provide security and authentication mechanisms. An android based client is used to demonstrate the working of L2TP over IPsec.

Share this page:

3 Comment(s)

Add comment

Please register in our forum first to comment.


By: Koushik Chatterjee

Hi All,

Thanks for sharing this awesome Documentation. I really like it. Someone please tell me on iptables section in details. I can't understand on that section.

By: Eko Prasetyo

Nice documentation. Keep sharing  ...

By: steven

I'm getting the following error when trying to connect VPN from the android phone.

Oct 18 14:10:47 modem-ThinkPad-W550s kernel: [12181.422625] [UFW BLOCK] IN=enp0s25 OUT= MAC=54:ee:75:42:cf:63:e8:91:20:c1:a8:f2:08:00 SRC= DST= LEN=136 TOS=0x00 PREC=0x00 TTL=64 ID=47290 DF PROTO=ESP SPI=0x96ca7e7c