How to setup a secure VPN server on Raspberry Pi or DigitalOcean

Today we will talk about setting up your own VPN server. Don’t these tutorials already exist? Possibly yes, but they are kinda blurry, and I will try to address all the issues you might run into.

What is a VPN and why should I care?

I think most people reading my blog or googling the topic have a fairly good understanding of what it is, but for those of you who doesn’t, here’s a quick recap:

VPN stands for Virtual Private Network and its’ function is to protect your traffic from prying eyes (and government agencies for that matter), while traveling over insecure networks. It will hide your true IP by letting you browse through another computer’s internet connection, and your own connection to that machine is further encrypted while doing so.

How VPN works


It works not only with websites, but any traffic will work through a VPN including games, Skype and so on. It can also be used to connect to another local network (LAN) through the internet, so you can use the printer at home, see your IP Cameras and access your NAS server without setting up port forwarding for each specific service, all while your traffic is securely encrypted.

But that’s not the primary reason to use a VPN for me. I use it because I want to stay secure on public networks and sometimes because I want to masquerade my IP address to another country (goodbye regional streaming DRM). When I’m away from home I have a specific VPS at DigitalOcean which acts as both my testing server and VPN provider. But I’m also just about to setup a secondary VPN server on my home network using a Raspberry Pi Model B (version 1), which is what this tutorial will be based upon

What is needed?

If you don’t have any Linux skills you are probably better of just Googling “VPN Provider” as this quickly becomes quite hairy. The first time took me quite some time.

If you decide to continue, you should really know: “there be dragons”.

You’ll need the following:

  • Any Debian based distro. I like Debian, and this tutorial is for Debian.
  • Some basic/mediocre Linux skills. It can get messy.
  • A system you are willing to risk messing up. This kind of thing can always go wrong, especially the first time around.
  • Either a Raspberry Pi or $5 Debian 7 VPS on DigitalOcean will be fine (The VPS will be fastest though).
  • We will use OpenVPN for the server. Any OpenVPN client on your device will do. I like Tunnelblick for Mac. OpenVPN connect works on Android.
  • I use UFW as firewall because it’s a lot easier to manage than IPTables. If you use IPTables, Google around.

I like to use Minibian for my Raspberry Pi. I used Raspbian previously, but it has become way to bloated for server installs. I don’t need a GUI or Python pre-installed. Minibian boots up into an idle RAM usage of around 40 MB, so there’s LOTS of headroom.

How to setup OpenVPN

You start off by SSH’ing into your machine. If you log straight into your root account, you don’t need all these “sudo” statements and can just use the commands behind them. I don’t recommend that at all, but some people do live dangerously.

As always, make sure your system is up to date:

If you got a lot of stuff upgraded there, always reboot your server as it might cause problems down the road otherwise. Trust me. It’s a good idea, it really is. TUN and network interfaces, combined with possible system upgrades SUCK because they give errors that are impossible to track down. Just reboot if you see anything installed above or haven’t rebooted in a while.

The first thing you’ll need is the OpenVPN package:

When this finishes, you need to copy the config files into place:

And CD into the “easy-rsa” directory. Please note we are using 2.0 not the 1.0 subfolder.

You will need to make your own Certificate Authority (CA), generate a server-key and some client-keys. Let’s start by setting up our easy-rsa tools. “Easy-RSA” is like the name suggest, some OpenVPN tools that makes this process as easy as possible. Cryptography is hard and you might easily mess up if you try to generate them yourself using OpenSSL.

Now for the setup. You can use your favorite editor for file editing (vim, emacs) but I prefer nano. Yes, just call me evil things now, but I like its’ simplicity. If I need anything more, I usually SSH in via Transmit and edit the file using Sublime Text on my Mac anyway.

You need to find the following lines, and change them (they don’t stand right next to each other).

Now source those variables so you are ready.

Only do this step if you want to start over or it’s your first time. This will DELETE all your keys and start fresh. 

Now you are ready to make your Certificate Authority (CA):

Most of the settings you are presented with should be OK as you’ve set them in your ./vars file. Change what you want. It might take some time if it’s an 2048 bit key, especially on the Pi.

We can proceed with the creation of your server certificate.

Just default through the settings (or change what you want). Leave out the challenge passwords. When asked to sign the certificate, press y (for yes) and then again to commit.

Now you are going to make a Diffie-Hellman file for OpenVPN. This file serves as added security, so an adversary can’t spy on your traffic and steal your keys at a later point to decrypt the traffic afterwards.

As the script says: It will take a long time, especially on a Pi. On DigitalOcean it’s bearable. Wait until it finishes before you proceed.

It’s time to build each key for every client that will use the server. Don’t worry, you can always make more later, but be sure to have a key for every device you use. Both because you can track the bandwidth used pr. client (more about this in a future post), but also because it let’s you revoke each key individually, should it ever become compromised.

It will ask you to sign (press y) and commit (press y) again. This is expected.

You have now finished key generation and are ready to setup your server. But first you need to copy each key into it’s final destination.

Change directory to the /etc/openvpn directory as all our work will be done in here for the next steps:

We haven’t got our server.conf yet. Let’s do that now.

Let’s do the same for the client config while we are at it. We need that later.

Open up server.conf in your favorite editor:

You will need to find the following lines and edit them:

And save the file. That should be it.

If OpenVPN fails to restart, you probably didn’t listen to me earlier. Reboot the server and check if it’s running after that. Only begin debugging after having done so. Trust me, it’s 90% of the causes I’ve seen. For all the people searching around, it might look something like this:

But the fix is simple. Reboot and check the OpenVPN status. If correctly configured it should be running.

If you are still getting errors, check your configuration one more time for errors.

Important note about DigitalOcean.

If you have had your server for a long time, you might have upgraded some part of your system, but your kernel isn’t up to date in the Control Panel on DigitalOcean. This DOES NOT update automatically, so this WILL cause problems with OpenVPN as the TUN device might be defunct. As of this writing I’m running “Debian 7.0 x64 vmlinuz-3.2.0-4-amd64 (3.2.68-1+deb7u1)” on a fully upgraded Debian 7 x64 system fine, but try and mess around with the kernel setting in there in the future if you cannot get TUN to work. This took me 3 hours to figure out.

Your VPN server is now ready. Congratulations.

At least the server part is. You cannot quite use it for anything yet as you still haven’t set up the required firewall rules and changed your system configuration. Your server needs to be ready to FORWARD all those IP packets coming its way, so let’s do that now.

Start by editing sysctl.conf to allow IPv4 forwarding.

Now we need to setup our firewall. I assume you use UFW because these steps also apply to Ubuntu (which is based on Debian), and UFW is very popular there. Otherwise just google “OpenVPN IPtables forward”. There are MANY more tutorials for that, than for UFW, so I’m gonna write about UFW.

I assume you have already been running UFW and setup your own rules. Otherwise remember this or you won’t be able to SSH into your server again.

Now run this:

You need to edit the defaults of UFW, so do the following.

We do this because we need to allow forwarding our VPN traffic onto the internet.

After this we need to make sure we allow forwarding to our eth0 interface (most often your primary internet connection). Default on most VPS providers and Raspberry Pi, but if you are using any other network interface you should know if you need to change this value:

Now enable UFW and remember to run “ufw allow ssh” if unsure or you will be locked out. This is your last warning. Btw. run enable again even if you already used UFW, as it seems to help reloading the config files.

Press “y” when asked to proceed with the operation.

That’s it. You now have all the routing you need and your server is running.

How to setup clients

It’s finally time to test it all out. First of all you need to download the relevant keys and the ca.crt file. In my case I named my laptop “hsp-laptop” and that’s what I’m working from, so I will download the following files onto my machine:

You can download these like you would normally transfer files from your server, but if you don’t have any good idea about how, open a new terminal window on your local machine (if using Linux or Mac). This will download them into the current directory:

Remember the “.” after your key names because that tells SCP to download to the current working directory on your local machine.

Grab your example client config too, while you are at it.

We will need to edit this file to match our server, so we can finally connect. Don’t be fooled by the fancy extension. Like many Linux things, this file is just a raw textfile underneath.

Open client.ovpn up in your normal editor on your computer (not the server). You need to edit the following lines:

If you have the ca.crt and both .key and .crt file in the same directory as the above .ovpn file, you should be able to import and test your VPN straight away. If using Tunnelblick on Mac you can just double-click it. For other clients, there should be an “import configuration” somewhere.

If succesfull you should be able to connect and surf the internet like usual. You can go to any site that shows your IP to verify it has changed like:

My Raspberry Pi Model B V.1 gives me the following speed, which should be adequate for most simple uses.

Raspberry Pi Speed test

Want more? Make a unified configuration file for your clients

Is it a little much passing ZIP files with all the keys around and remembering not to move them separately? Indeed it is. Let’s rectify that issue.

You can comment out the following lines in your client.ovpn config file:

And then add the following at the bottom:

Yup. The certificates are textfiles themselves, so just open them up in your favorite text editor and copy the correct files into those placeholders.

They will have lines like these:

Be sure to copy those with them. Regarding the your-client-name.crt you will see some extra stuff in there before the BEGIN CERTIFICATE line. It’s all right to just copy it all into those placeholders.

When done, save the file and enjoy. You can now ignore the other files and even delete them as you will only need your client.ovpn file from now on (you can rename this too if you like). Just be sure to test this new unified file out before actually deleting anything.

HELP! I need to block a certificate from accessing my server.

Legitimate users turn malicious. Sometimes you lose your client files. It happens. My first word of advice if you are seeing abuse from your VPN server: Shut it down, if at all possible! At least until you’ve fixed the issue.

When people are using your VPN server it’s like using your car: If they drive around shooting people, it’s your license plates that the police will search for. It’s the same thing about your VPN server and its IP address, so be careful about who you allow access, or the police might end up tackling you at your doorstep for some very nasty stuff.

Back to the revocation procedure. Because we used easy-rsa it’s actually really easy (like the name implies). Just log into your server and go to:

If you’ve logged out since last time, you might need to do the following again:

Now run this where “unwanted-key-name” is the name of the client key you want to revoke. Now you see why I recommend different keys for each device?Look at /etc/openvpn/easy-rsa/2.0/keys/index.txt if unsure about the client names.

If it gives an error at the final line like this, you are golden:

This error is actually a success message, but shown as an error because it tested if it could lookup the newly revoked certificate, and it can’t which it shouldn’t be able to, now that we’ve revoked it. That was a little confusing, but everything is fine!

But you are not done just yet. The above command will create a file at the following path.

This is the revocation file and will include all revoked certificates. Each time you revoke a certificate, you need to copy this into /etc/openvpn like this:

If this is the first time revoking a certificate you need to tell OpenVPN about this revocation list. We didn’t define it earlier because it didn’t exists yet, so there were no need for one and OpenVPN refuses to accept clients if the one specified doesn’t exists (probably for security purposes).

Now restart OpenVPN to enforce the changes.

And that should be it. You can always see which clients are allowed and which are revoked by looking at the following file:

The ones with a “V” on the left is in use. The one with an “R” is revoked.

Final words

That was one hell of a tutorial and I’m glad you made it down here. You’ve just learned how to setup your own VPN server both on DigitalOcean and on a Raspberry Pi at the same time. You’ve learned how to generate keys for this server. You’ve learned how to revoke those keys. And you’ve learned how to make a unified client file that can easily be sent to your phone etc.

In the next part of what will probably be a series, I will look at some monitoring by hooking into the scripting capabilities of OpenVPN server.

I might also look at proxying requests on the server-side and may even try injecting malicious code just for the kicks.

Thank you for your time and stay tuned for updates.