Raspberry Pi VPN Router

My gist is an update to superjamie’s jessie vpn guide using stretch.

My updated version allows auto-reconnect and checks to maintain connection while the pi is live.

set up root and replace default user

pi@raspberrypi:~# sudo su
root@raspberrypi:/home/pi# passwd
root@raspberrypi:/home/pi# reboot

log in as root and set up new user

root@raspberrypi:~# useradd -d /home/user user
root@raspberrypi:~# passwd user

delete default account

root@raspberrypi:~# deluser pi
root@raspberrypi:~# rm -rf /home/pi

Configure raspbian

root@raspberrypi:~# dpkg-reconfigure tzdata
root@raspberrypi:~# dpkg-reconfigure locales

Set Hostname (I called mine vpn)

root@raspberrypi:~# nano /etc/hosts
root@raspberrypi:~# nano /etc/hostname

Set keyboard layout

root@raspberrypi:~# nano /etc/default/keyboard
XKBLAYOUT="us"

UPDATE to stretch

root@raspberrypi:~# sed -i 's/jessie/stretch/g' /etc/apt/sources.list
root@raspberrypi:~# apt-get update
root@raspberrypi:~# apt-get dist-upgrade

Remove references to eth0 in interfaces

root@raspberrypi:~# nano /etc/network/interfaces

(Comment or delete everything below iface lo inet loopback)

# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

Install network-manager and openvpn

root@raspberrypi:~# aptitude install network-manager network-manager-openvpn openvpn

Allow network-manager ifupdown management

root@raspberrypi:~# nano /etc/NetworkManager/NetworkManager.conf

(you want managed=true)

[main]
plugins=ifupdown,keyfile

[ifupdown]
managed=true

reboot

root@raspberrypi:~# reboot

Set up lan

root@vpn:~# nmcli c add con-name eth0 ifname eth0 type ethernet ip4 192.168.1.5/24 gw4 192.168.1.1
root@vpn:~# nmcli c mod eth0 ipv4.dns "8.8.8.8 8.8.4.4"
root@vpn:~# nmcli c up eth0
root@vpn:~# nmcli c 
NAME                UUID                                  TYPE            DEVICE 
eth0                a8864abf-5cbf-4a9e-94be-ba67f39e5d88  802-3-ethernet  eth0   
Wired connection 1  8107e4e8-a1aa-368a-ac8d-6de3edfdfaa6  802-3-ethernet  --     
root@vpn:~# nmcli c del 8107e4e8-a1aa-368a-ac8d-6de3edfdfaa6
root@vpn:~# reboot

import pia scripts

root@vpn:~# aptitude install unzip
root@vpn:~# cd /etc/openvpn
root@vpn:/etc/openvpn# wget https://privateinternetaccess.com/openvpn/openvpn-strong-tcp.zip
root@vpn:/etc/openvpn# unzip openvpn-strong-tcp.zip
root@vpn:/etc/openvpn# rm openvpn-strong-tcp.zip

copy files to edit

(in case you make a mistake, this also makes the nmcli commands easier)

root@vpn:/etc/openvpn# cp /etc/openvpn/AU\ Sydney.ovpn /etc/openvpn/sydney.ovpn
root@vpn:/etc/openvpn# cp /etc/openvpn/Hong\ Kong.ovpn /etc/openvpn/hongkong.ovpn

import into network manager

root@vpn:/etc/openvpn# nmcli c import type openvpn file /etc/openvpn/sydney.ovpn
root@vpn:/etc/openvpn# nmcli c import type openvpn file /etc/openvpn/hongkong.ovpn

add your username and password to the files you imported

root@vpn:/etc/openvpn# nano /etc/NetworkManager/system-connections/sydney
root@vpn:/etc/openvpn# nano /etc/NetworkManager/system-connections/hongkong

set password flag, then add password and user details

password-flags=0
proto-tcp=yes
remote=aus.privateinternetaccess.com:501
remote-cert-tls=server
reneg-seconds=0
username=%username%
service-type=org.freedesktop.NetworkManager.openvpn

[vpn-secrets]
password=%password%

reboot

root@vpn:/etc/openvpn# reboot

Check connections

root@vpn:~# nmcli c
NAME      UUID                                  TYPE            DEVICE 
eth0      a8864abf-5cbf-4a9e-94be-ba67f39e5d88  802-3-ethernet  eth0   
hongkong  fc7eea3b-5041-4a6d-acc1-0d45664da82f  vpn             --     
sydney    7fb33267-665a-4f31-9466-0c94d33d8a86  vpn             --     

set up ip forwarding

root@vpn:~# echo -e '\n#Enable IP Routing\nnet.ipv4.ip_forward = 1' | tee -a /etc/sysctl.conf
root@vpn:~# sysctl -p
root@vpn:~# iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
root@vpn:~# iptables -A FORWARD -i tun0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
root@vpn:~# iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT
root@vpn:~# aptitude install iptables-persistent
root@vpn:~# netfilter-persistent save
root@vpn:~# systemctl enable netfilter-persistent

add autoconnect script

root@vpn:~# nano /opt/vpn-auto-sydney.sh
#!/bin/bash +x

# Source: http://www.gabsoftware.com/tips/automatically-reconnect-to-your-vpn-on-linux/

# Description:
# Make the script executable "chmod +x /path/to/the/script.sh
# Put the script in .profile or .bashrc so it can be run on user login:
# Example: echo "/path/to/the/script.sh start &" >> .bashrc
# The script can be bound to shortcut keys with these commands:
#   /path/to/the/script.sh start # starts and monitors VPN connection
#   /path/to/the/script.sh stop  # stops the monitor and also the VPN connection

##########
# Config #
##########

# You can see those with "nmcli con" command
VPN_NAME="sydney"
VPN_UID="7fb33267-665a-4f31-9466-0c94d33d8a86"

# Delay in secconds
DELAY=30

# File path with write permission to the executing user to store script status information
LOG="/var/log/vpn-sydney.log"

# Enable/disable ping connection check
PING_CHECK_ENABLED=true

# Check IP/Hostname
CHECK_HOST="8.8.8.8"

# Configure DISPLAY variable for desktop notifications
#DISPLAY=0.0

##################
# Implementation #
##################

if [[ $1 == "stop" ]]; then
  nmcli con down uuid $VPN_UID

  echo "VPN monitoring service STOPPED!"
  echo "$(date +%Y/%m/%d\ %H:%M:%S) -> VPN monitoring service STOPPED!" >> $LOG
  #notify-send "VPN monitoring service STOPPED!"
  
  SCRIPT_FILE_NAME=`basename $0`
  PID=`pgrep -f $SCRIPT_FILE_NAME`
  kill $PID  
elif [[ $1 == "start" ]]; then
  while [ "true" ]
  do
    VPNCON=$(nmcli con show --active | grep "$VPN_NAME" | cut -f1 -d " ")
    if [[ $VPNCON != $VPN_NAME ]]; then
      echo "$(date +%Y/%m/%d\ %H:%M:%S) -> Disconnected from $VPN_NAME, trying to reconnect..." >> $LOG
      (sleep 1s && nmcli con up uuid $VPN_UID)
    else
      echo "$(date +%Y/%m/%d\ %H:%M:%S) -> Already connected to $VPN_NAME!" >> $LOG
    fi
    sleep $DELAY

    if [[ $PING_CHECK_ENABLED = true ]]; then
      PINGCON=$(ping $CHECK_HOST -c2 -q -W 3 |grep "2 received")
      if [[ $PINGCON != *2*received* ]]; then
        echo "$(date +%Y/%m/%d\ %H:%M:%S) -> Ping check timeout ($CHECK_HOST), trying to reconnect..." >> $LOG
        (nmcli con down uuid $VPN_UID)
        (sleep 1s && nmcli con up uuid $VPN_UID)
      else
        echo "$(date +%Y/%m/%d\ %H:%M:%S) -> Ping check ($CHECK_HOST) - OK!" >> $LOG
      fi
    fi
  done

  echo "VPN monitoring service STARTED!"
  echo "$(date +%Y/%m/%d\ %H:%M:%S) -> VPN monitoring service STARTED!" >> $LOG
  #notify-send "VPN monitoring service STARTED!"
else 
  echo "$(date +%Y/%m/%d\ %H:%M:%S) -> Unrecognised command: $0 $@" >> $LOG
  echo "Please use $0 [start|stop]" 
  #notify-send "UNRECOGNIZED COMMAND" "VPN monitoring service could not recognise the command!"
fi

add startup script

root@vpn:~# nano /etc/init.d/pia 
#! /bin/sh
# /etc/init.d/pia
#

# Some things that run always
touch /var/lock/pia

# Carry out specific functions when asked to by the system
case "$1" in
  start)
    echo "Starting script pia"
    /opt/vpn-auto-sydney.sh start
    ;;
  stop)
    echo "Stopping script pia"
    /opt/vpn-auto-sydney.sh stop
    ;;
  *)
    echo "Usage: /etc/init.d/pia {start|stop}"
    exit 1
    ;;
esac

exit 0

Enable Service

root@vpn:~# chmod 755 /opt/vpn-auto-sydney.sh
root@vpn:~# update-rc.d pia defaults
root@vpn:~# reboot

check that the VPN auto connects

(sydney and the tunnel interface have connected correctly below)

root@vpn:~# nmcli c
NAME      UUID                                  TYPE            DEVICE 
eth0      a8864abf-5cbf-4a9e-94be-ba67f39e5d88  802-3-ethernet  eth0   
sydney    7fb33267-665a-4f31-9466-0c94d33d8a86  vpn             eth0   
tun0      9fd7bf45-095f-4b12-94a2-5255729b226d  tun             tun0   
hongkong  fc7eea3b-5041-4a6d-acc1-0d45664da82f  vpn             --     

Configure Other Systems on the LAN

Now we’re ready to tell other systems to send their traffic through the Raspberry Pi.

Configure other systems’ network so they are like:

  • Default Gateway: Pi’s static IP address (eg: 192.168.1.5)
  • DNS: Something public like Google DNS (8.8.8.8 and 8.8.4.4)

Don’t use your existing internet router (eg: 192.168.1.1) as DNS, or your DNS queries will be visible to your ISP and hence may be visible to organizations who wish to see your internet traffic.