As mentioned in my previous post, I want to use my Raspberry Pi as a VPN server. If you followed along with the install guide you should have a basic Raspbian OS running on your Pi. You may have installed other software, or configured the Pi however you prefer. If you have made any changes it may alter the following VPN setup.
For this guide I will be continuing on with the basic install as it was after the previous post.
Note - Using a VPN from outside your home network will require port forwarding on your router. Through the router admin console you should be able to forward all traffic to your Pi’s ‘tun0’ device, which is created later. You will also need your external IP address. Use a site such as whatismyip.com.
There are a number of VPN server options out there, but the most popular is OpenVPN. It is incredibly easy to install, and works with the default configuration. There is a web based management console which enables you to adjust the settings quickly.
First things first, let’s make sure our Pi is up to date then we can install OpenVPN. We will also install easy-rsa
, OpenVPN’s CA utility
sudo apt update
sudo apt upgrade
sudo apt install openvpn easy-rsa
As root copy config file from OpenVPN’s example files. If the command doesn’t work with sudo, run as root as shown below (needs root password)
cd /usr/share/doc/openvpn/examples/sample-config-files/
su -c "gunzip -c server.conf.gz > /etc/openvpn/server.conf"
Open the config file for editing
sudo vi /etc/openvpn/server.conf
Change the Diffie hellman parameter from 1024 to 2048 Before
dh dh1024.pem
After
dh dh2048.pem
Remove comment (‘;’) from the DHCP redirect line
push "redirect-gateway def1 bypass-dhcp"
Remove comment (‘;’) from the two DNS lines. If you want to change the DNS servers edit the IP addresses on these lines. I have opted to stick with the defaults which are OpenDNS
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
Finally reduce privileges by running as nobody, remove the comment (‘;’) from the following lines
user nobody
group nogroup
Save and exit your text editor.
Now we need to set up the firewall. Firewall configuration on Linux is a sore subject for a lot of people, especially when trying to use the iptables
commands. To make life easier you can opt to use a tool such as ufw
which makes configuring the rules really easy. My guide will use the iptables
commands because the only way to learn is by doing!
Forward IPv4 traffic
echo 1 > /proc/sys/net/ipv4/ip_forward
Make persistant. In /etc/sysctl.conf, uncomment line
net.ipv4.ip_forward=1
Show iptables rules (should be blank)
sudo iptables -L
We are going to set up a number of rules. First we need to allow established outgoing connections. This makes life easier as we don’t always know which port will be used for an outgoing connection, such as HTTP. If you prefer you can set this rule separately for each port you open, but for ease we will set it globally. The second rule is to allow incoming SSH connections. If you changed the port number used for SSH (see my Raspbian Install Guide) then you need to specify the port number. The third rule we need to set if to allow OpenVPN traffic. This port number can also be changed in the OpenVPN config file, the default is 1194. Then we need to allow TUN interface connections. We will also allow TUN connections to be forwarded through our other interface. Finally we need to NAT the OpenVPN traffic using our TUN interface.
sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2222 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -i eth0 -p udp --dport 1194 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -i tun+ -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
sudo iptables -I FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -d 192.168.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A FORWARD -i tun+ -j ACCEPT
sudo iptables -A FORWARD -i tun+ -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
Save the firewall changes in a backup file, then make the rules persistent after a reboot.
sudo iptables-save > 20170527_iptables_rules.bak
sudo invoke-rc.d iptables-persistent save
If you ever need to apply the saved rules, if iptables is flushed for example, run the following
sudo iptables-apply 20170527_iptables_rules.bak
You can now run sudo iptables -L
again to see all the rules you have entered
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:2222 ctstate NEW,ESTABLISHED
ACCEPT udp -- anywhere anywhere udp dpt:openvpn ctstate NEW,ESTABLISHED
ACCEPT all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 10.8.0.0/24 192.168.0.0/24 ctstate NEW
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate ESTABLISHED
The next step is to generate the keys using easy-rsa
. Copy the “easy-rsa” directory into our OpenVPN config directory, then create a new “keys” directory
sudo cp -r /usr/share/easy-rsa/ /etc/openvpn/
sudo mkdir /etc/openvpn/easy-rsa/keys
Before we generate the keys we need to change the following fields in “/etc/openvpn/easy-rsa/vars”
export KEY_COUNTRY="US"
export KEY_PROVINCE="CA"
export KEY_CITY="SanFrancisco"
export KEY_ORG="Fort-Funston"
export KEY_EMAIL="me@myhost.mydomain"
export KEY_OU="MyOrganizationalUnit"
export KEY_NAME="EasyRSA"
Change the values to reflect your location and details. Also choose a name for your key (i.e. “server”), we will need this later. Save and quit your text editor
Generate the Diffie-Hellman pem file, this will take a while
sudo openssl dhparam -out /etc/openvpn/dh2048.pem 2048
When that has finished we can generate the certificates. It is easier to do this as root as we need to source the variables. When running build-key-server
change the server name to the one you specified in the “vars” config file
sudo -i
cd /etc/openvpn/easy-rsa
source ./vars
./clean-all
./build-ca
./build-key-server server
exit
Copy the newly generated keys to your OpenVPN directory
sudo cp /etc/openvpn/easy-rsa/keys/{server.crt,server.key,ca.crt} /etc/openvpn
Now we can start our OpenVPN server
sudo systemctl start openvpn
sudo systemctl status openvpn
We then have to generate keys for the clients we want on our VPN. It is good practice to have individual key pairs for each client, and not to share one key pair. This makes life easier if a device is lost or stolen, we only have to revoke one device’s key pair.
Generate the keys for the first client, changing the name to the device you will be using (run as root again)
sudo -i
cd /etc/openvpn/easy-rsa
source ./vars
./build-key client
exit
Create a new directory to keep things tidy then copy an example client configuration file, and the keys we have just created
mkdir ~/client
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client/client.ovpn
sudo cp /etc/openvpn/easy-rsa/keys/{client.crt,client.key,ca.crt} ~/client
Next open up the config file “client.ovpn”. Uncomment the “nobody” and “nogroup” lines as before, also comment out the certificate and key lines
user nobody
group nogroup
;ca ca.crt
;cert client.crt
;key client.key
Also change the line specifying the IP address of your OpenVPN server. From
remote my-server-1 1194
To
remote 192.30.252.153 1194
Replace the IP address with your network’s external IP address.
Save and quit your text editor.
Instead of copying the .ovpn file the two certs and the key across to our client, we can echo the contents of our certs into our .ovpn file and only copy the one file across to our client.
The syntax for this is in XML, for example
<tag_name>
contents
</tag_name>
So we can run the following commands (as root)
sudo -i
cd /home/pyratebeard/client
echo "<ca>" >> client.ovpn
cat ca.crt >> client.ovpn
echo "</ca>" >> client.ovpn
echo "<cert>" >> client.ovpn
cat client.crt >> client.ovpn
echo "</cert>" >> client.ovpn
echo "<key>" >> client.ovpn
cat client.key >> client.ovpn
echo "</key>" >> client.ovpn
exit
Securely copy the “client.ovpn” file across to your device.
For the purposes of this demonstration we are going to use a mobile phone as our device.
Install and open the OpenVPN Connect app on your mobile. Import the profile file we copied across and hit connect. After a couple of seconds you should be connected to your VPN. Congrats!
As mentioned at the start you will have to enable port forwarding on your router to allow traffic from outside your network into the Pi.