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:
- Download Raspbian Image
- Write Image to SD Card with Etcher
- 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:
- Boot your Pi
- Find your Pi's IP Address by checking your router's DHCP lease allocation table
- SSH into your Pi with the default username pi and password raspberry
Prepare to install OpenVPN
Change the default password
- passwd
Optional: Authorise one or more SSH keys
- mkdir ~/.ssh
- chmod 0700 ~/.ssh
- 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:
- PasswordAuthentication no
Update the Raspberry Pi
- sudo apt update
- sudo apt upgrade
- sudo apt autoremove
Install OpenVPN
Download and run PiVPN
- sudo su -
- 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:
- Change your router's DHCP lease allocation table's range such that there are several local addresses available for static allocation, then choose one such available local address for the Raspberry Pi when PiVPN prompts for it.
- If you have a dynamic public IP address, use a dynamic DNS service so that you can avoid providing an IP address that you would have to keep changing manually (i.e., you can then select "DNS Entry" in response to "Public IP or DNS").
- If you have a DigitalOcean account managing networking for a domain name and want to use your own subdomain to access the VPN server, consider placing my dnsyncmyip script on the Raspberry Pi to do the DNS entry updates.
- If all the devices that you will use to connect to the VPN server are running OpenVPN 2.4 or later, absolutely select "yes" for "version 2.4 improvements". It really is faster, especially for setup.
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)
- # Accept traffic to the Raspberry Pi on the loopback interface:
- sudo iptables -A INPUT -i lo -j ACCEPT
- # Accept traffic to the Raspberry Pi for established or related connections:
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
- # Accept new traffic to the Raspberry Pi for OpenVPN:
- sudo iptables -A INPUT -p udp --dport openvpn -m conntrack --ctstate NEW -j ACCEPT
- # Accept new traffic to the Raspberry Pi for SSH:
- sudo iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j ACCEPT
- # Accept echo requests (ping) to the Raspberry Pi:
- sudo iptables -A INPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW -j ACCEPT
- # Drop all other traffic to the Raspberry Pi:
- sudo iptables -A INPUT -j DROP
- # Accept traffic to be forwarded by the VPN server for established or related connections:
- sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
- # Accept new traffic to be forwarded by the VPN server from the VPN subnet:
- sudo iptables -A FORWARD -i tun+ -o eth0 -s 10.8.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
- # Drop all other traffic that the VPN server is requested to forward:
- 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:
- sudo iptables -A FORWARD -i tun+ -o eth0 -s 10.8.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
to:
- 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
- sudo sh -c "iptables-save > /etc/iptables.rules"
Create a script for loading the saved configuration on startup:
- sudo nano /etc/network/if-pre-up.d/iptablesload
- #!/bin/sh
- iptables-restore < /etc/iptables.rules
- exit 0
Create a script for saving the configuration on shutdown:
- sudo nano /etc/network/if-post-down.d/iptablessave
- #!/bin/sh
- iptables-save > /etc/iptables.rules
- if [ -f /etc/iptables.downrules ]; then
- iptables-restore < /etc/iptables.downrules
- fi
- exit 0
Make both scripts executable
- sudo chmod +x /etc/network/if-pre-up.d/iptablesload
- 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
- cat /etc/iptables.rules | grep MASQUERADE
If you see this in the result:
- -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:
- 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:
- sudo iptables -t nat --line-numbers -L
You will get a result such as:
- Chain POSTROUTING (policy ACCEPT)
- num target prot opt source destination
- 1 MASQUERADE all -- 10.8.0.0/24 anywhere
then delete the masquerade rule with the corresponding number, in this case 1:
- sudo iptables -t nat -D POSTROUTING 1
References
- OpenVPN Community Wiki's page on Bridging and Routing, section on Using routing and OpenVPN not running on the default gateway