Monday, 15 December 2014

OpenVPN with 2 factor authentication on the Raspberry Pi

This guide, describes how to set up a VPN (Virtual Private Network) on your raspberry pi to allow you to remotely connect to your home network.

A VPN allows a remote computer to act as though its part of your home newtork - vpn clients can see computers sitting on your home lan.  I've found it really useful when I've been working away staying in hotels with relatively slow internet connections.  The VPN in itself does not take up much band width, so once you are connected, and remote desktopped to one of your home PC's, you can operate at your home networks speed.  As the VPN is configured to use UDP, you get a much more stable connection (believe it or not!).


  • Vanilla install of Raspbian (You should be able to login using pi/raspberry)


We're going to use OpenVPN and Ansible to orchestrate the install, and set up the configuration.  

We'll use google authenticator to provide 2 factor authentication, configured as a PAM module.

To test, we'll use a mobile phone, connected to the internet via 3g.

Setup Ansible

We're going to install ansible directly onto the Pi.  Log onto the raspberry pi, using pi/raspberry:

ssh-keygen    (go with defaults and no password)
sudo apt-get update
sudo apt-get install python-dev python-pip sshpass git
sudo pip install ansible
git clone
cd raspi-ansible
Register the raspberry pi with anisble:

ssh  (selecting yes when asked about key fingerprint, password: raspberry)
cd ~/raspi-ansible
ansible-playbook -i live bootstrap.yml -k     (password: raspberry)

Edit inventory

The live file is called the inventory.  This lists the network config, which openvpn needs.  Edit this to match your own network configuration:

[pi] isp_ip="" local_lan="" local_lan_mask="" vpn_lan="" vpn_lan_mask=""
  • isp_ip - set this to your ip address.  You can find your ip address here
  • local_lan - set this to your network subnet.  *** important!
  • local_lan_mask - usually
  • vpn_lan - go with the default.
  • vpn_lan_mask - go with the default.

Run the playbook

cd ~/raspi-ansible
ansible-playbook -i live vpn.yml
sudo /etc/network/if-up.d/openvpn_firewall
This will configure and start the openvpn server.

It also will create a client file: /etc/openvpn/client.ovpn which can be used to configure the openvpn client.

Home router configuration

  • Forward port 1194 (UDP) to your raspberry pi.


We'll test the vpn connection using a mobile phone, simply because its the quickest way to prove that its working:
  • Install openvpn on your phone.
  • Install google authenticator on your phone.
  • Somehow get the client.ovpn onto your phone. (You could email it to yourself then download it!)

Create VPN user 

For each user of your vpn, you will need to generate a user on the raspberry pi, and a run google-authenticator.  Log onto the raspberry pi using pi/raspberry:

sudo adduser fred (provide password as 'monday', and go with defaults for the remaining of the prompts)
su - fred   (password: monday)
google-authenticator  (Answer y to the questions)
This will generate a QR code. Scan this into your phone using the google authenticator app. There is also a URL, which you could email to the user:

On your phone

  • Disable wifi, to ensure that you are not connecting via your home network. Use mobile data ie. 3g.
  • Open openvpn and import client.ovpn
You will be prompted for a username and password:

username: fred password: monday13520

The password, is fred's password concatenated with the google authenticator verification code provided by the app.

If everything is happy, you should now be connected and able  to navigate to your routers home page ie.:

SSL Certs

You should generate your own certificates and private keys and copy them into /home/vagrant/playbooks/roles/vpn-server/templates/etc/openvpn. Until you do this, a potential hacker would in theory be able to intercept your and inspect your VPN traffic.  On ubuntu I use tinyca2 and on windows XCA to generate my certificates.

Route all traffic through VPN

Edit  /home/vagrant/playbooks/roles/vpn-server/templates/etc/openvpn. Uncomment the line:

push "redirect-gateway def1"


 If things are not working, try connecting using the openvpn client whilst running:

sudo tail -f /var/log/syslog 
sudo tail -f /var/log/auth.log
Look in  syslog for openvpn issues, and auth.log for google authenticator issues.

Good luck!


Raspberry Pi

Latest Raspbian image

Ansible VPN playbook

Windows SSL Certificate Manager

Update (Feb 2016)

1) VPN SSL certificate updated to never expire
2) server.conf updated to point to correct pam module:
3) Added config to optionally route all traffic through vpn