Installing and setting up OpenVPN on a Raspberry Pi

OpenVPN on a Raspberry Pi

A nice chap that I've been working with for the past year was curious about setting up a Raspberry Pi at home and gaining access to it externally.  He was very concerned about those nasty hacker (script kiddy) people and didn't just want loads of ports opened up and left open on his home router.

I talked him into getting a Pi, which he did, but I don't think he got much further than that (AP, let me know if you did!)

Then a week or so ago, an ex-work friend asked a similar question (albeit not Pi related).

My wife (yes, she is real....) told me off for having my streaming music just set to an open port on our home router that redirects to one of the Pis.  It wasn't secure, it wasn't username/password protected, anyone with a web-browser could just point to my URL and port and start streaming music across the internet.  Albeit it would be my fixed playlist, but she feared that as it was commercial music that we'd bought legally and now had the potential for other people to access, we would be getting a visit from the "you can't do that" police and I'd get a huge fine or something.

As is the law of necessity, I then set about making my Pi more secure and setting up a VPN.  I thought I would detail it here, incase I need to do it again for any reason, but also in case you want to follow along and set it up too.  It's not too tricky, but as usual, there are some websites that give you documentation that just don't quite work or you need three sites to make one set of instructions.

So, I made a plan of action:
Step 1. Go on a Google mission for finding instructions that other people had done.
Step 2. Follow said instructions and it will all work perfectly, first time.
Step 3. I'll be all done in 10 minutes.

Step 1 breached the 10 minute threshold, so my project plan was way out the window already.

Eventually, I found a couple of decent online resources that I'll share here.  Now, you can just follow them, but then you don't get my extra commentary :-)

If you skim through those last two articles then you'll pretty much have all the info that you need to know, but they themselves are based on the second article, which is a bit dry...

Pi Setup
I have Pi:1 and Pi:2 humming away on the shelf in my home/office.
Pi:1 is running a Web Server, NodeJS and is plugged into a Robot arm, PiCamera and has a nifty 2.8" screen soldered to the front of it.  It's my main play-thing.
Pi:2 is mainly just setup for streaming music from an external USB drive plugged into it.

Here's the original page describing the install / setup:

I chose to use Pi:2 (or rasppi as it's named) to install the openvpn software onto.

First things first, open up a web-browser and log-in to your main home router.  It'll be something like and admin/admin (you did change the default password, didn't you?...).
You need to locate the 'Port Forwarding' section.  If you were like me, you'll have a nice long list of about 20 ports that you were using, half of which you'd forgotten about and were still open - a bit like still leaving the kitchen window open during autumn as you had it open during summer.  It's not quite cold enough to notice and it's not doing any harm, is it?... not until an opportunist burglar notices it.

So, you'll need to delete all of those previous entries.  And replace them with just one. 1194.
That port is changeable, it's just the one used by the openvpn software by default.  If you fancy having it as 6666, feel free to, but remember it later when you are fiddling with the config file setup.

Right, back to the Pi.  As we already have the Pi up and running, we can skip all the initial steps and dive right in.

Install OpenVPN
>sudo apt-get install openvpn

once it's done it's thing, we're ready to go.  First step is to do all of this as root, (as we're going to create keys and the Pi needs you to be root to do this):

>sudo -s
>cp –r /usr/share/doc/openvpn/examples/easy-rsa/2.0 /etc/openvpn/easy-rsa
>cd /etc/openvpn/easy-rsa

We now need to change the following config file, so open it up using nano:
>nano vars

locate the following line near the top of the file and replace it with this value:
#export EASY_RSA="`pwd`"

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

and whilst you're in there, you might want to make this change too (totally optional):

# Increase this to 2048 if you
# are paranoid.  This will slow
# down TLS negotiation performance
# as well as the one-time DH parms
# generation process.
#export KEY_SIZE=1024

export KEY_SIZE=2048

Now it's time to build the Certificates
You should already be here, but just incase you've wandered off, get back here:

>cd /etc/openvpn/easy-rsa

>source ./vars

You'll now be prompted to fill in things like Country, State, Name, etc... "Common Name" is the only real field of value, change it to be anything you want, but remember it for later.  Unlike 99% of the rest of the world, I didn't use "server" but chose "rasppi".  Once that is done, we need to build the server-key.

>./build-key-server rasppi

You'll then be prompted with the same fields to fill in that you just did, but this time "Common Name" should be defaulted to "server" (or whatever you typed).  You will be asked the question:

>A challenge password?

Apparently this MUST be left blank.  Now, I've searched for about 3 minutes (attention span of todays society equals "if it cannot be googled and an answer known in less than 3 minutes, then seeking the guidance of an elder or mystical one is obviously required") and I could not find an answer as to why this must be left blank or what/where it is used.  All I could find was that it MUST be blank.  If that is the genuine case then why prompt and ask? why not just set it as blank by default and not ask me?  But, because it exists, it will niggle me for days to come, until I find out why...

You'll then be asked if you want to sign the certificate.  The default is for 10 years.  I reckon that just might be long enough and probably longer than the shelf-life of the Pi?  Then you commit the certificate.

So, that was pretty simple.  The server-side is all setup now.

We now build some keys for usage on the client devices, but we create them on the server (Pi). I decided that I would make 3 client device keys, 1 for my Mac, 1 for my Android Tablet and 1 for "spare"... I will keep it handy to put onto another device, possibly my OpenPandora?...

To build a key we type the following:

>./build-key-pass device1

You'll be asked to enter a PEM pass phrase.  This is the pass phrase you'll get asked to use when you eventually connect from a client device, so make it something you'll remember and a bit more secure than 'p@ssw0rd'.

Again, we get asked for "A challenge password?" and we leave it blank again.  Then we sign the certificate (for 10 years).

Now, you'll need to perform the following for every client device that you want to set up. So, before we do that we'll repeat the last step again for device2 and device3.  Then we'll move on:

> cd keys

>openssl rsa -in device1.key -des3 -out device1.3des.key
>openssl rsa -in device2.key -des3 -out device2.3des.key
>openssl rsa -in device3.key -des3 -out device3.3des.key

You'll be asked to enter the pass phrase for deviceX, I just used the same as before.  You're asked it 3 times, you don't get too adventurous.

We should be good to go now with the keys, so we'll step back up a folder:

> cd ..

Now that we have the server-side keys setup and we've just created the client-device keys setup, we need to generate the key exchange. This is the main bit that makes it all tick.
To perform this you type the following, although be warned, if, like me, you selected 2048 bit in the config earlier, you now need to find something that will occupy you for the next 1-2 hours:


During this the time that this was running, I managed to dig a 6ftx8ftx6ft hole in my garden as the start of my "underground greenhouse project", okay, I only got 3ft down, but I made a good start... I'll post an article in the future on the progress and how I'm going to hook it up to the "Internet of Things" and do some wonderful things with Arduino's, relays, motors, sensors and hopefully grow some veggies all year round using the heat of the earths core.... I digress.

Once you've dug a large hole or you've just watched hours of dots and plus signs being output to you screen, there is one last step.  It's not essential, but whilst we're here we might as well do it.  The following just helps to prevent DoS attack protection:

>openvpn --genkey --secret keys/ta.key

Blimey, that 10 minute deadline was "way" off the mark.  If you've got this far, you're probably 1/2 a day into this so far and we've not actually configured openvpn itself yet?!  The astute of you would be asking (probably whilst watching the .........+..........+........+.........'s "so when do we tell it all about IP addresses and what have you?"... that'll be about now.

Putting it all together
To tell openvpn how to work, we need to give it a config file, so we'll make one:

>nano /etc/openvpn/server.conf

(you are still root, aren't you?...if not do a >sudo -s and repeat the above)

Oh, it's blank.  Well, you can have my one, or you can click here and download a default one and replace the values with one's that makes sense to you.

dev tun 
proto udp #Some people prefer to use tcp. Don't change it if you don't know.
port 1194 
ca /etc/openvpn/easy-rsa/keys/ca.crt 
cert /etc/openvpn/easy-rsa/keys/rasppi.crt
key /etc/openvpn/easy-rsa/keys/rasppi.key
dh /etc/openvpn/easy-rsa/keys/dh2048.pem
# server and remote endpoints 
# Add route to Client routing table for the OpenVPN Server 
push "route" 
# Add route to Client routing table for the OpenVPN Subnet 
push "route" 
# your local subnet 
push "route"
# Set primary domain name server address to the SOHO Router 
# If your router does not do DNS, you can use Google DNS 
#push "dhcp-option DNS"
#I originally set this as above, but it meant DNS did not work
#changing it to the following and it works fine
push "dhcp-option DNS"
# Override the Client default gateway by using and 
# rather than This has the benefit of 
# overriding but not wiping out the original default gateway. 
push "redirect-gateway def1" 
keepalive 10 120 
tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0 
cipher AES-128-CBC 
user nobody 
group nogroup 
status /var/log/openvpn-status.log 20 
log /var/log/openvpn.log 

verb 1

Once that is edited and saved, we need to edit one other config file:

>nano /etc/sysctl.conf

We need to modify this file so that the Raspberry Pi will allow network traffic forwarding.  What does that mean?  Well, if you VPN into the Pi from an external location, if we do NOT change this setting, all we will be able to "see" are the machines connected to the internal home network.  Okay, but what does that really mean?  It means you can now longer access the internet.  Ah!!!  Okay, so making this change might be a good thing.  Although, if you are wanting to shut out the rest of the world and only tunnel from your machine to you home network machines then you now know how to set that up.

In the config file locate the following and change it:

# Uncomment the next line to enable packet forwarding for IPv4


Okay, so now you've setup the Pi to have permission to act as a relay, so it will send and receive packets on the network. Yay!

We can now tell the Pi to apply that change with the following command:

>sysctl -p

We're nearly there! Just that pesky built-in firewall that needs setting up...
Raspbian has a nice built-in firewall that is there to protect you from incoming baddies.  Oh, but we now want to connect to the Pi from outside.  It'll think we're a baddy.  Let's change the config to allow "us" through but keep the baddies out.

>nano /etc/

This creates an empty file that we can populate with something like this:


iptables -t nat -A POSTROUTING -s -o eth0 -j SNAT --to-source

You'll change the IP addresses to match the one's you are going to use.

Using one of the previous articles, this is the text that appeared in relation to this task:
"Let’s break this down: is the default address for Raspberry Pi for clients that are connected to the VPN. "eth0" stands for ethernet port. Switch this to "wlan0" if you’re on a wireless connection, which is not recommended. "

Naturally, I did not have an ethernet cable plugged into the Pi, just a Wireless card.  So, I assumed I could just swap out eth0 with wlan0 and all would be good.  I was intrigued by the above comment about it not being recommended, but I thought, pfhh! I'll do it anyway.  To cut a long story short, when it came to tweaking the /interfaces file my Pi refused to bring up the wlan0 interface and therefore was a bit useless.  Now, this might have just been an error on my part (yes, it does happen), but after the obligatory 3 minutes, I gave up, located an RJ45 cable, plugged it into the Pi and used the eth0 settings everywhere.  The good news is, it worked fine.

Now we have to make the .sh file executable, so we do either a 700 or a +x, it's up to you and we change the owner from pi to root:

>chmod +x /etc/
>chown root /etc/

Now, we need to tell the network eth0 device that when it is starting up it needs apply those firewall rules.  We do that by adding an extra line (apparently the indent is needed):

>nano /etc/network/interfaces

auto lo
iface lo inet loopback
iface eth0 inet static
        pre-up /etc/

iface defaut inet dhcp

As you can see my Pi is set up to have a static IP, you don't have to have this setup like this.

Right.  Now, you should be all done!

>sudo reboot

If you've got your Pi plugged into a monitor as it's booting you should see that the last output before asking for login details will be your IP addresses:

This is a good sign!  If you don't get this (that is what happened when I was trying to use wlan0 instead of eth0 earlier), then you know openvpn is not running and it's time to go read the log files in /var/log/

Wow, okay, so maybe you should have set aside an entire weekend afternoon as that took a bit longer than expected.  But, it is done now and you won't have to do it again (because you will backup your SD Card, won't you?!)

Now, for the connecting of the client devices (the whole point of this exercise!)
If you recall, the main mission was to be able to securely connect from an external location, such as a hotel wifi or even from a mobile phone device tethered to a tablet, to the home network to be able to stream my personal music and to make rude gestures with my robot arm from many miles away...

In order to do that we need to install an OpenVPN client, give it some configuration details, connect to the openvpn Pi server and then test access to the internal servers.

Ah, before we get carried away, if you recall we made some deviceX keys on the server in the /keys folder.  Well, we now need to generate some OPVN files that will allow our Mac, Android tablet, etc.. to connect.  To generate those files we need to create a file and populate it like so:

>sudo -s
>nano /etc/openvpn/easy-rsa/keys/Default.txt

dev tun
proto udp
remote <insert your external DNS hostname here> 1194
resolv-retry infinite
ns-cert-type server
key-direction 1
cipher AES-128-CBC
verb 1

mute 20

I'd suggest you go to a service like or dynDNS or similar and create an account.  Setup a name that points to your home routers IP address (this service is handy if you do not have a fixed IP address).  Then replace the <insert your external DNS hostname here> above with your hostname - do not include the http:// part.

Now that we have the config file setup we now need the script file that will generate our OPVN files.

>nano /etc/openvpn/easy-rsa/keys/


# Default Variable Declarations 

#Ask for a Client name 
echo "Please enter an existing Client Name:"
read NAME 

#1st Verify that clients Public Key Exists 
if [ ! -f $NAME$CRT ]; then 
 echo "[ERROR]: Client Public Key Certificate not found: $NAME$CRT" 
echo "Clients cert found: $NAME$CR" 

#Then, verify that there is a private key for that client 
if [ ! -f $NAME$KEY ]; then 
 echo "[ERROR]: Client 3des Private Key not found: $NAME$KEY" 
echo "Clients Private Key found: $NAME$KEY"

#Confirm the CA public key exists 
if [ ! -f $CA ]; then 
 echo "[ERROR]: CA Public Key not found: $CA" 
echo "CA public Key found: $CA" 

#Confirm the tls-auth ta key file exists 
if [ ! -f $TA ]; then 
 echo "[ERROR]: tls-auth Key not found: $TA" 
echo "tls-auth Private Key found: $TA" 

#Ready to make a new .opvn file - Start by populating with the default file 

#Now, append the CA Public Cert 
echo "<ca>" >> $NAME$FILEEXT 
echo "</ca>" >> $NAME$FILEEXT

#Next append the client Public Cert 
echo "<cert>" >> $NAME$FILEEXT 
echo "</cert>" >> $NAME$FILEEXT 

#Then, append the client Private Key 
echo "<key>" >> $NAME$FILEEXT 
echo "</key>" >> $NAME$FILEEXT 

#Finally, append the TA Private Key 
echo "<tls-auth>" >> $NAME$FILEEXT 
echo "</tls-auth>" >> $NAME$FILEEXT 

echo "Done! $NAME$FILEEXT Successfully Created."

I had several links to this online, but they all had issues when pasting and gave errors, so I've just pasted my final and working file from my Pi.

As we want to execute this file, we either do the chmod 700 or +x to the file:

>chmod 700

and then we execute it.


You'll be asked for the client name.  You recall those from before?  I used device1, device2 and device3.  We'll do this three times to create the .opvn files for each one.

You'll get the "Done! deviceX Successfully Created." message after each one, but then we need to be able to get those .opvn files off the Pi and onto our client-devices.

I installed CyberDuck on my Mac and use SFTP to access the file system, files copied off of Pi and onto Mac for safe keeping.

Setting up the client device access
For the Mac, I downloaded and installed TunnelBlick - this was a pretty painless exercise and worked well.  When asked I pointed it at the device1.opvn file and it picked up the connection details as you can see here:

Now, to test it though you need to NOT be connected to the home wifi where the Pi is connected to.  Otherwise your router will just route you directly to the Pi rather than emulating the realistic scenario.  Therefore, I used my Mobile Phone as a wifi hotspot, connected the Mac to that hotspot and then selected 'Connect device1'.
You are prompted for the pass phrase, you do remember that from earlier don't you?  You had to enter it three times, after all.

You'll then see that you are assigned a 10.8.0.x IP address and you're good to go!  You can now access all of your internal/home IP addresses as if you were physically at home.

For instance, I no longer need to expose my web server to the outside world, if I wish to control my Robot Arm and see if my cat is in my home/office I can use the same URL as I would at home, albeit I'm now tunnelling through the VPN:

Not only have I now limited the number of open ports in my router, I've also reduced the risk that someone could compromise my web server and do all those nasty things you hear about on the news.

I can also now stream my online music in a nice and secure manner, without it being available to all and sundry.  Finally keeping my missus happy that the "music police" are not going to be knocking on the door anytime soon.

I can also SSH onto the Pis via this method without opening up ports 21/22 on the main router.  Which is a great relief.

For the Android Tablet, I visited the Play Store, downloaded the official OpenVPN client, used the file device2.opvn and superb, I was able to access the VPN (again via my wifi hotspot) and stream music to the Tablet and also access all my personal files that I keep at home rather than on my physical devices.

Looking forward
Upon inspecting the /var/log/auth.log file on the Pi, I noticed a huge drop in the attempts from those nasty script kiddies from China attempting to login to the Pi (1000's of entries and now, none).
So, at least I feel a bit more secure without having random windows/ports being left open now.

It'd be great if I could get TOR into the equation too... but that might raise more eyebrows from GCHQ, NSA, etc..etc...  I'll save that for Easter :-D

No comments:

Post a Comment