Guide: VPN Server with the Rapsberry Pi 24



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!

Overview

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 configuration changes, ease with the Linux command line, and good with a text editor like nano or vi.) You should also have a good understanding of basic networking and know how to make changes to your router. I’ll try to be as thorough as possible, but there’s a limit. Please brush up the aforementioned concepts prior to continuing.

Preface

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.

Requirements

  • 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)

What’s a VPN?

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!

Pre-Steps

 

Download Image

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.

Windows

For Windows we can use a tool called Win32DiskImager. Download this small executable and proceed with these instructions while writing the file 2017-04-10-raspbian-jessie-lite.img to the card.

Mac OS X

You’ll need to get to the command line and proceed as follows. To list the disks currently connected:

diskutil list

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

Linux

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

Static IP

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:

username: pi
password: raspberry

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

Enable SSH

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 /boot/ directory.

touch /boot/ssh

Change Password

A smart thing to do at this point would be to change the default password.

sudo passwd

Update Jessie

Finally, let’s to some housekeeping and update the Raspberry Pi.

sudo apt-get update
sudo apt-get upgrade

OpenVPN Server

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…

Installing OpenVPN

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
SSH: Installing OpenVPN

SSH: Installing OpenVPN

Key Generation

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.)

sudo -s

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 /etc/openvpn/easy-rsa/vars.

nano /etc/openvpn/easy-rsa/vars

And change line 15 to read:

export EASY_RSA="/etc/openvpn/easy-rsa"

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:

SSH: Alter Key Strength

SSH: Alter Key Strength

CA Certificate / Root CA certificate (Server Side)

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:

cd /etc/openvpn/easy-rsa

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?

SHH: Build CA

SHH: Build CA

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.

./build-key-server vpnserver

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.

SSH: Build CA Completed

SSH: Build CA Completed

Client Side Keys

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.

./build-key-pass user1

You’ll be prompted for a password to enter twice. Remember it!

SHH: PEM Passphrase

SHH: PEM Passphrase

The next prompts, you can enter as such:

A challenge password? Leave blank.

Sign the certificate? [y/n] Type “y.”

Now change directory:

cd keys

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.

SSH: OpenSSL

SSH: OpenSSL

Diffie-Hellman Key Exchange

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

HMAC key

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

Server Configuration

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.

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.

nano /etc/openvpn/server.conf 
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 8.8.8.8
push "dhcp-option DNS 192.168.1.1"
# Override the Client default gateway by using 0.0.0.0/1 and 
# 128.0.0.0/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 (wait, that’s one too many 3’s – I’m going mad…)

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 dh1024.pem accordingly.

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:

tail /var/log/openvpn.log

Post-Steps

 

Packet Forwarding

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.

nano /etc/sysctl.conf

Uncomment the following line in the file:

net.ipv4.ip_forward=1

Save, and run the following command to make our change take effect:

sysctl -p

IPTables

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 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:

ifconfig

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.

IPTables Persistent: Save

IPTables Persistent: Save

Client Configuration

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 Default.txt.

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 /etc/openvpn/easy-rsa/keys/:

wget https://gist.githubusercontent.com/bobbyromeo/c8d038bddbd2797fc01eecf6bcd82ce6/raw/a79cc97155ce10767b64bff96278896205f3be51/MakeOpenVPN.sh

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:

./MakeOpenVPN.sh

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.

Testing

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. This is so I can catch any server errors as they occur immediately. 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.

Port Forwarding

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:

Firewall: NAT Port Forwarding

Firewall: NAT Port Forwarding

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.

Conclusion

Wow, that was one ridiculously long post (at least it felt that way to me.) Apologies for the length of that one. Perhaps I should have split the post in two parts, but oh well, it’s done. So I dp 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!

Good luck and happy networking!


Leave a comment

Your email address will not be published. Required fields are marked *

24 thoughts on “Guide: VPN Server with the Rapsberry Pi

      • Lifeisfun

        While working the HMAC key I’m getting this erro:
        root@raspberrypi:/home/pi# openvpn –-genkey –-secret keys/ta.key
        Options error: I’m trying to parse “–-genkey” as an –option parameter but I don’t see a leading ‘–‘
        Use –help for more information.
        Any idea what I’m doing wrong?
        Thanks

        • bobby Post author

          Perhaps try manually typing the command instead of copying it? Perhaps it’s adding some weird control characters or something. Also, I notice that you’re not in the right directory while issuing the command. You should be in the working directory: cd /etc/openvpn/easy-rsa prior to running the command.

          • Lifeisfun

            That did it, I was in the wrong directory – amateur 🙂
            Sadly I’m stuck again, how do I edit those server configuration file?
            What file is that?
            Thanks for your patience!

          • bobby Post author

            Use the nano text editor. It’s not terribly difficult to use. Type nano to run the editor.

          • bobby Post author

            You’re quite right! The file is /etc/openvpn/server.conf. I updated the post. Thanks!

  • Lifeisfun

    I noticed that your pi ip is 192.168.1.11 and you wrote down on Line 12 in the server config subnet 192.168.1.0
    My existing pi ip has permanent reserved dhcp 192.168.1.118 what subnet do I use ?
    Thanks

  • crumb

    Hi Bobby,

    Thanks for the instructions… I’ve managed to generate the .ovpn files but whenever I try them out on my Android phone, it keep saying it’s unable to parse the IPv4 address. Any ideas as to how I could resolve this?

      • crumb

        No, I don’t think so?
        I’ve also tried the .ovpn files on my Macbook using Tunnelblick and it keeps saying “Tunnelblick could not find a ‘tun’ or ‘tap’ option in the OpenVPN configuration file” which is odd because Default.txt explicitly says “dev tun”.

  • StefanMe

    Hi Bobby! Thanks for your great Blog!

    I tried to install the VPN-Server on an existing Pi i use for Homebridge and Ambilight. (Based on Noobs)

    Everything worked fine until i ll run the VPN-Server with “systemctl restart openvpn”. It just happen nothing. Also “root@RPI3TV:/var/log# tail /var/log/openvpn.log” doesnt work:
    tail: cannot open ‘/var/log/openvpn.log’ for reading: No such file or directory

    What did i wrong?

  • Dinko

    Dude, you are awesome. So well written manual. I would like to shake your hand, since I cannot – please give me your paypal so I could at least buy you beer! Thank you!

  • Jeramey

    I am able to connect to my pi remotely using these instructions…thanks!

    However I still can’t get to my dafang camera.

    Is there anything special that I have to do to make that work? So far my camera is vanilla as the fang hacks aren’t working on the dafang model.

    Any help would be appreciated

    • Dennis

      I had OpenVPN already installed for a while and today I wanted to access my Xiaomi camera after applying the hack using your tutorial (thanks!).

      My problem was that I had some wrong iptables rules installed. Maybe that’s your problem here as well…?