Recently, I’ve been recommending to most of my readers to use a VPN server on their routers for secure access to their home network. More so, the point came up in response to my blog post, Xiaomi Smart 1080P WiFi IP Camera with RTSP Streaming Hack. Such a setup would enable access to the camera stream via a secure connection.
Although most newer (expensive) routers nowadays do come with VPN capabilities, it may not be your case or you may feel that your router lacks the processing power to adequately support your needs. But hold on, there’s another choice. We won’t need VPN capabilities on our routers. As long as your router has port forwarding, this guide may prove useful to you.
Read on if you’re the least bit interested. I bet you’re are, ’cause you’re here, aren’t you!
- What’s a VPN?
- OpenVPN Server
- Installing OpenVPN
- Key Generation
- CA Certificate / Root CA certificate
- Client Side Keys
- Diffie-Hellman Key Exchange
- HMAC key
- Server Configuration
Before we begin, I’d like to preface this guide with the following message: this guide assumes you are somewhat comfortable with the Raspberry Pi (i.e.: writing images, simple configurations changes, and you have a certain ease with the Linux command line (SSH) and a text editor like nano or vi. I’ll try to be as thorough as possible, but there’s a limit. Please brush up the aforementioned concepts prior to continuing.
A few things to get out of the way before we begin.
First, even though this guide deals with the Raspberry Pi, I can’t see why it shouldn’t work on any other box running Linux – the instructions are pretty generic.
Oh, I imagine that there are probably simpler ways of setting up a VPN server on your Pi, like “one-click” installers, specific tailored distros, and whatnot. But by doing it by hand – step-by-step in this fashion – would give you a little more insight into the inner workings of the Pi and of the OpenVPN software itself, all the while arming you with the needed info if things go south as they say and you need to troubleshoot.
Another thing, give credit where credit is due, right? This post has been inspired by Lauren Orsini’s original post on the subject found here. I’ve adapted it and made some changes to account for Raspbian Jessie.
- Raspberry Pi 3/2/1/0
- MicroSD card and an SD card reader
- HDMI cable, Ethernet cable, Keyboard…
- Mini USB power adapter (at least 2 Amps for Pi 2/3)
- Another device to act as the client (either another computer, virtual machine, Android phone) preferably on another network
- Plenty of free time…
- Swear jar (when things don’t work)
For those that don’t know, a Virtual Private Network (VPN) is a network technology that creates a secure network connection over a public network such as the Internet or a private network owned by a service provider. More specifically, one will be able to connect to their Rapberry Pi over the internet and from there connect to one’s home network and access shared files and media over a secure connection. OpenVPN is the go-to software for this typical setup. What’s more, is the fact that it can be install almost an any platform, including the Raspberry Pi.
Once installed and configured, we’ll simply need to port forward from our router to the Raspberry Pi to connect to our brand new VPN server.
All righty, enough of that boring techno-babble. I assume you’re all eager to get on with the instructions, but beware, this setup could very well take hours to configure and test correctly – so set aside enough free time!
Download the Jessie Lite image file from the official download page, currently as of this writing it’s up to version dated on 2017-04-10. After you unzip this file you’ll need to write the image to your SD card. Various options exist to accomplish this feat.
You’ll need to get to the command line and proceed as follows. To list the disks currently connected:
Next locate the target disk/card (assume disk2 for this example) and un-mount the disk.
diskutil unmountDisk /dev/disk2
Then write the image.
dd if=/path/to/2017-04-10-raspbian-jessie-lite.img of=/dev/rdisk2 bs=1m
On Linux, very similar to Mac OS X, get to the command line with Terminal App and proceed as follows (assuming your SD card is sdb.)
dd if=/path/to/2017-04-10-raspbian-jessie-lite.img of=/dev/sdb bs=1M
To make our lives somewhat easier, we’ll assign a static IP to the Pi. So assuming you can now boot up into Jessie, let’s go ahead and do that. Login with the standard credentials.
If you don’t know what they are:
Now, modify the file
/etc/dhcpcd.conf and add the following lines to the bottom of the file. Be mindful to make the appropriate changes based on your setup. In this example, my Pi will have the IP 192.168.1.11 and my router is set to 192.168.1.1.
interface eth0 static ip_address=192.168.1.11/24 static routers=192.168.1.1 static domain_name_servers=192.168.1.1
Since we’re here, might as well enable SSH. To enable SSH, all you need to do is to put a file called
ssh in the
A smart thing to do at this point would be to change the default password.
Finally, let’s to some housekeeping and update the Raspberry Pi.
sudo apt-get update sudo apt-get upgrade
Okay great, now that the easy stuff is out of the way, we’ll embark on the much bigger task of installing / configuring OpenVPN. Buckle up, it’s gonna be a little long, I mean, really long…
We’ll begin by installing the main software that’s gonna make this all tick; OpenVPN.
Issue the following command.
sudo apt-get install openvpn
We’ll also want to make our OpenVPN server as secure as possible and deny any would-be cyber-hoodlums from connecting to our network. To do so, we’ll need to generate some keys – analogous to the keys we use for our front doors.
Let’s begin by becoming root on our fresh new Jessie install (be cautious as root, irreparable damage could occur if you’re not careful.)
OpenVPN comes with a light and friendly package for using the RSA encryption method, it’s called Easy_RSA. The technology, developed in 1977, was one of the first usable cryptosystems concocted and is very much still in wide use today. In essence, the encryption key is public, while the decryption key is secret. Easy_RSA will aid us in the creation of these keys.
Let’s begin by copying some files over to our working directory.
mkdir /etc/openvpn/easy-rsa/ cp -R /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/ cd /etc/openvpn/easy-rsa
Next, use your favorite editor and edit the following file
And change line 15 to read:
There’s also another modification you could make in this file to alter the key strength, that is, taking it down from 2048-bit to 1024-bit. Leave it at 2048 if you are paranoid, but keep in mind that it will take longer for the keys to be generated versus reducing it to 1024. I made the change:
An entity that issues digital certificates is called a certificate authority (CA). These certificates basically certifies the ownership of a public key. In fact, whenever you access a secured site (i.e.: HTTPS) and hit that lock icon in your browser’s address bar, you may notice certain companies performing this duty, which ultimately help establish the legitimacy of the website.
However, in this example, we’ll act as the certificate authority and sign the OpenVPN keys directly, instead of trusting it to a third party company.
Let’s begin by going in the right directory:
And then running the following commands sequentially:
source ./vars ./clean-all ./build-ca
After the last command, you’ll be prompted for some info. Here, I’ll recommend to do something which I rarely suggest – mindlessly hit the enter key until you’re back at the prompt. Easy enough, huh?
Now we can name the server, I chose to use “vpnserver” for mine. You can called it anything you like, but keep track of the name as we proceed along.
Once again, the Pi is going to want some info. Press enter a bunch of times while paying attention to the three following fields:
Common Name Imperative that it is the server name you chose, however, it should have defaulted to it.
A challenge password? Leave it blank.
Sign the certificate? [y/n] Type “y.”
You’ll get a message that says the certificate will be certified for 3,650 more days. 10 years? Good enough for our needs
1 out of 1 certificate requests certified, commit? [y/n] Here once more, type “y” once more.
With the server-side keys generated, it’s now time to turn our attention to the client-side of things. Here we’ll build keys for each user you’ll have. I chose to use “user1”, “user2”, etc…
You could use anything you like here.
The syntax is as follows.
You’ll be prompted for a password to enter twice. Remember it!
The next prompts, you can enter as such:
A challenge password? Leave blank.
Sign the certificate? [y/n] Type “y.”
Now change directory:
And issue the command for every one of your clients:
openssl rsa -in user1.key -des3 -out user1.3des.key
The above command will keep hackers from breaking through it with brute force. OpenSSL stands for an open source implementation of Secure Socket Layer, a standard method of setting up a secure connection.
You’ll be prompted once for a passphrase, simply use the same one as before.
Server keys…done. Client keys…done.
What we’ll build next is an important bit of code that aids with the exchange of secret keys between two entities with no prior knowledge of one another – another important cryptosystem. Keep in mind that this could take some time if you kept 2048-bit encryption.
cd /etc/openvpn/easy-rsa ./build-dh
Lastly, we’ll prevent Denial of Service (DoS) attacks by using an HMAC key. OpenVPN prevents DoS attacks from happening even before it begins the authentication process through this mechanism. By using this, our VPN server will simply ignore requests unless it detects this static key first. Would-be hackers won’t be able to brute force our server with repeated attempts and their attacks will be all but thwarted – at least, that’s what I tell myself every morning.
The command is as follows:
openvpn --genkey --secret keys/ta.key
Great. We’re almost there. Next, we’ll configure our server. We’ll need to provide a few important things, namely what keys to use, kind of connection, and port you’ll use.
So create a file called
/etc/openvpn/server.conf and put the following, I’ll highlight the lines you should be concerned with at this point.
dev tun proto udp port 33333 ca /etc/openvpn/easy-rsa/keys/ca.crt cert /etc/openvpn/easy-rsa/keys/vpnserver.crt key /etc/openvpn/easy-rsa/keys/vpnserver.key dh /etc/openvpn/easy-rsa/keys/dh1024.pem server 10.8.0.0 255.255.255.0 # server and remote endpoints ifconfig 10.8.0.1 10.8.0.2 # your local subnet push "route 192.168.1.0 255.255.255.0" # Set primary domain name server address to the SOHO Router # If your router does not do DNS, you can use Google DNS 22.214.171.124 push "dhcp-option DNS 192.168.1.1" # Override the Client default gateway by using 0.0.0.0/1 and # 126.96.36.199/1 rather than 0.0.0.0/0. This has the benefit of # overriding but not wiping out the original default gateway. push "redirect-gateway def1" client-to-client duplicate-cn keepalive 10 120 tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0 cipher AES-128-CBC comp-lzo user nobody group nogroup persist-key persist-tun status /var/log/openvpn-status.log 20 log /var/log/openvpn.log verb 1
Line 2: Some people prefer to use TCP. Don’t change it if you don’t know what you’re doing.
Line 3: I decided to not use the standard 1194 port, and went with an obscure port number here, 333333.
Line 5-6: Ensure that the filenames match what you used as the server name.
Line 7: If you changed the key strength to 2048, change the filename
Line 12: Swap the subnet (192.168.1.0) with the subnet your Pi is on.
Line 15: This should already match your router address, change if necessary.
Once done, give the server a restart and inspect the log for errors.
systemctl restart openvpn
Here’s the log file:
Now, we’ll need to instruct the Pi that it’s okay to forward Internet traffic. Normally, this is off by default, as you could probably imagine. We need to edit the file
/etc/sysctl.conf to allow the Pi to forward Internet traffic through our new network.
Uncomment the following line in the file:
Save, and run the following command to make our change take effect:
That’s still not enough for us to access our subnet through the VPN connection. We’ll also need to issue some commands to ensure that once you connect to your home network, you’ll be able to access your client machines. The following assumes that the default interface is named
eth0 (which is the case on the Pi if using the Ethernet port) and that the
tun0 (OpenVPN’s interface) if up. So first ensure that OpenVPN is started and running.
You can verify the interfaces on Linux by issuing the following command:
And here are the iptables commands used to help us do the routing via masquerade (take a look here for some info on masquerading.)
/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE /sbin/iptables -A FORWARD -i eth0 -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT /sbin/iptables -A FORWARD -i tun0 -o eth0 -j ACCEPT
And lastly, because the settings won’t persist across reboots, we’ll install an application that’ll do that for us.
apt-get install iptables-persistent
Hit “Yes”, when prompted to save the IPv4 rules and “No” for IPv6.
Phewww! Almost there. Let’s keep on, keepin’ on…
Now we can turn our attention to the client configuration. We’ll begin by creating a new file, call it
cd /etc/openvpn/easy-rsa/keys/ nano /Default.txt
And put the following into it:
client dev tun proto udp remote <YOUR PUBLIC IP ADDRESS HERE> 33333 resolv-retry infinite nobind persist-key persist-tun mute-replay-warnings ns-cert-type server key-direction 1 cipher AES-128-CBC comp-lzo verb 1 mute 20
Pay very close attention to line 4. You’ll need to insert your public IP address (i.e.: your modem’s address. ) This may very well need changing from time to time due the dynamic nature of the protocol (unless you’ve been assigned a static IP address from your provider.) I do suggest using a Dynamic DNS service for this – your homework assignment!
Next download this file and upload it to your Pi via whatever method you’re most comfortable with. Better yet, just run the following command from the directory
This script (not written by me), will spit out a
.ovpn file, which will serve as the client side configuration file for whatever device(s) you intend on using to connect to your VPN server. In other words, you’ll need to copy this file out of the Pi and import it to the device.
Let’s make the script executable:
chmod 700 ./MakeOpenVPN.sh
Finally, execute the script with:
The script will prompt you to input the names of the existing clients for whom you generated CA keys earlier. Example in my case: “user1.”
If all goes to plan, you should see this line appear:
Done! user1.ovpn Successfully Created.
Repeat this step for each existing client you’ll plan on connecting to your server. Remember to copy this file to the device you’ll use to connect with. You can use either WinSCP or SCP to copy the file out. If you’re unfamiliar with either, take a look at another one of my blog posts, where I discuss moving files out of the Pi.
Before configuring port forwarding on your router, it’ll be probably best to attempt to connect to your brand new VPN server from within your own network. In my case, I used an Ubuntu virtual machine to test. First and foremost, I copied the
user1.ovpn file to the virtual machine, installed OpenVPN there, and ran this command to start the client while inspecting the output:
openvpn --config ./user1.ovpn
At the same time, I also logged into the Pi, “tailing” the log file. Idea being: so I can catch any server errors. Use this command to tail the log file:
tail -f /var/log/openvpn.log
Since OpenVPN is available on almost every platform, including Android. Choose a client and begin testing. I used a virtual machine running Ubuntu, use whatever you’re most comfortable with.
Unfortunately this part could be tricky and you may run into issues for a number of various reasons. It’s largely a trial-and-error process at this point. Keep at it if it doesn’t work on the first shot, remember Google is your friend!
Hopefully though, it all goes well and you get a working VPN connection.
If the connection from within your internal network works, chances are you are in good shape. What remains is simply forwarding the port in question to your Pi. Of course, the steps will vary from router to router, but the concept remains the same. Here’s how my setup looks like:
Interface: WAN (our public interface).
Protocol: UDP (unless you changed this in the config files).
Source Address: * (Represents any).
Source Ports: * (Represents any).
Dest. Ports: 33333 (The incoming port I chose).
NAT IP: 192.168.1.11 (The IP address of the Pi).
NAT Ports: 33333 (The listening port of the OpenVPN service on the Pi).
Now test once more, this time from outside your network.
Wow, that was one ridiculously long post (at least it felt that way to me.) Apologies for the length of that one, I should have split the post in two parts, but well, it’s done. So I hope you’ve found it useful and hope you have a brand new connection that you can access, no matter where you are, and you are at peace with the thought that your data is safe from prying eyes!