Raspberry Pi OpenVPN Server

  • Home
  • Raspberry Pi OpenVPN

Background

This is a beginner's guide on setting up a VPN server — OpenVPN — on a Raspberry Pi. The bulk of the work will be done by the PiVPN script, so the guide is more on getting started with the Raspberry Pi and then securing it by configuring a firewall. My own setup was done using a Raspberry Pi 3B+ with Raspbian Stretch Lite.

Guide Convention

You will see code blocks with line numbering as well as code blocks in which lines are prefixed by $ or # throughout this guide. Code blocks with line numbering denote output from the terminal or code to be entered in a text editor like nano. Like the prompt that you would see in a terminal, code blocks in which lines are prefixed by $ denote commands to be entered as the pi user when logged into the Raspberry Pi via secure shell (SSH). Code blocks in which lines are prefixed by # denote commands to be entered as the Raspberry Pi root user via SSH.

Install Raspbian

NOOBS

If you already have the Raspberry Pi New Out Of the Box Software (NOOBS) pre-installed on a microSD card, you could hook up a monitor and a keyboard and then run through the installation of Raspbian with NOOBS. If not, you can download NOOBS.

Headless Raspberry Pi

As I was troubleshooting my OpenVPN setup and wanted to keep restarting from a pristine new installation, I found it easier to flash Raspbian to the microSD card on each new try rather than have to keep plugging and unplugging peripherals. This is called "Raspberry Pi headless", and I found James Mackenzie's article on a Headless Raspberry Pi Setup to be invaluable. In case the article goes missing:

  1. Download Raspbian Image
  2. Write Image to SD Card with Etcher
  3. Enable SSH by placing a file named "ssh" (without any extension) onto the boot partition of the SD card.

Log into the Raspberry Pi

Once you have installed Raspbian, there are three more steps to go:

  1. Boot your Pi
  2. Find your Pi's IP Address by checking your router's DHCP lease allocation table
  3. SSH into your Pi with the default username pi and password raspberry

Prepare to install OpenVPN

Change the default password

                    
  1. passwd

Optional: Authorise one or more SSH keys

                    
  1. mkdir ~/.ssh
  2. chmod 0700 ~/.ssh
  3. nano ~/.ssh/authorized_keys

The creation of an SSH key pair is beyond the scope of this guide, but it will likely involve either ssh-keygen or PuTTY (if on Windows). Additionally, disable password authentication by modifying /etc/ssh/sshd_config to set:

                    
  1. PasswordAuthentication no

Update the Raspberry Pi

                    
  1. sudo apt update
  2. sudo apt upgrade
  3. sudo apt autoremove

Install OpenVPN

Download and run PiVPN

                    
  1. sudo su -
  2. curl -L https://install.pivpn.io | bash

The PiVPN installer should be fairly straightforward as it provides recommendations that you should follow unless you know better. Jason Rigden's How to use PiVPN to create your own VPN tutorial could be helpful if you want an abbreviated walk through of the process. I have a few suggestions:

Configure the firewall

It is not absolutely necessary to have a firewall on the Raspberry Pi itself as it is protected by the router's firewall, but having a firewall anyway is a matter of defense-in-depth.

Network Assumptions

For convenience, I shall assume the following; change the values to suit your own network:

  • The LAN is on the subnet 192.168.1.0/24
  • The router has a local IP address of 192.168.1.1
  • The Raspberry Pi has a local IP address of 192.168.1.10
  • The VPN subnet is 10.8.0.0/24
  • SSH is configured for the default port 22
  • OpenVPN shall be configured for the default port 1194 with the default UDP protocol

Insert the firewall rules

(the lines starting with # are comments that you can but do not have to enter)

                    
  1. # Accept traffic to the Raspberry Pi on the loopback interface:
  2. sudo iptables -A INPUT -i lo -j ACCEPT
  3. # Accept traffic to the Raspberry Pi for established or related connections:
  4. sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  5. # Accept new traffic to the Raspberry Pi for OpenVPN:
  6. sudo iptables -A INPUT -p udp --dport openvpn -m conntrack --ctstate NEW -j ACCEPT
  7. # Accept new traffic to the Raspberry Pi for SSH:
  8. sudo iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j ACCEPT
  9. # Accept echo requests (ping) to the Raspberry Pi:
  10. sudo iptables -A INPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW -j ACCEPT
  11. # Drop all other traffic to the Raspberry Pi:
  12. sudo iptables -A INPUT -j DROP
  13. # Accept traffic to be forwarded by the VPN server for established or related connections:
  14. sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  15. # Accept new traffic to be forwarded by the VPN server from the VPN subnet:
  16. sudo iptables -A FORWARD -i tun+ -o eth0 -s 10.8.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
  17. # Drop all other traffic that the VPN server is requested to forward:
  18. sudo iptables -A FORWARD -j DROP

Optional: Restrict traffic via the VPN to the LAN

Traffic via the VPN to the Internet is allowed. To restrict traffic via the VPN to the LAN, change this:

                    
  1. sudo iptables -A FORWARD -i tun+ -o eth0 -s 10.8.0.0/24 -m conntrack --ctstate NEW -j ACCEPT

to:

                    
  1. sudo iptables -A FORWARD -i tun+ -o eth0 -s 10.8.0.0/24 -d 192.168.1.0/24 -m conntrack --ctstate NEW -j ACCEPT

Save firewall configuration for reboot

As-is, the firewall configuration will be wiped when you reboot the Raspberry Pi. We shall create two shell scripts to load and save the firewall configuration on startup and shutdown respectively

Save the firewall configuration

                    
  1. sudo sh -c "iptables-save > /etc/iptables.rules"

Create a script for loading the saved configuration on startup:

                    
  1. sudo nano /etc/network/if-pre-up.d/iptablesload
                    
  1. #!/bin/sh
  2. iptables-restore < /etc/iptables.rules
  3. exit 0

Create a script for saving the configuration on shutdown:

                    
  1. sudo nano /etc/network/if-post-down.d/iptablessave
                    
  1. #!/bin/sh
  2. iptables-save > /etc/iptables.rules
  3. if [ -f /etc/iptables.downrules ]; then
  4. iptables-restore < /etc/iptables.downrules
  5. fi
  6. exit 0

Make both scripts executable

                    
  1. sudo chmod +x /etc/network/if-pre-up.d/iptablesload
  2. sudo chmod +x /etc/network/if-post-down.d/iptablessave

Port forwarding

Add a port forwarding rule on the router to forward UDP packets on port 1194 to 192.168.1.10 on port 1194.

Masquerade rule

Add masquerade rule if it does not exist

Check if there is a masquerade rule in iptables

                    
  1. cat /etc/iptables.rules | grep MASQUERADE

If you see this in the result:

                    
  1. -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Then you are done. Otherwise, add it to masquerade all VPN clients as coming from the VPN server's LAN IP address:

                    
  1. sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.8.0.0/24 -j MASQUERADE

Alternative: Configure routing table

It would be ideal for the routing table on the router to be modified to add a route for the VPN subnet, i.e., 10.8.0.0/24 to be sent via 192.168.1.10, but this is not always possible, especially on a home router. If you do want to modify the routing table but have already added the masquerade rule, run:

                    
  1. sudo iptables -t nat --line-numbers -L

You will get a result such as:

                    
  1. Chain POSTROUTING (policy ACCEPT)
  2. num target prot opt source destination
  3. 1 MASQUERADE all -- 10.8.0.0/24 anywhere

then delete the masquerade rule with the corresponding number, in this case 1:

                    
  1. sudo iptables -t nat -D POSTROUTING 1

References