Setting up your own VPN

Published 2018-11-02 on Yaroslav's weblog

There are many reasons why you would want to use a VPN, especially in this day and age. The major one would be to securely and more privately surf the web, but that is far from the only reason. I for one use it as well to be able to set up a remote network with my desktop PC while I'm away from home, so that I can access all of my files through SSH. There are a ton of other reasons as to why a VPN could be useful, but that is not the topic of this post, rather I will be writing here about to set up your own VPN (yes your own!) on a VPS, or any other kind of linux server for that matter, using OpenVPN.

I am in fact running my own VPN in the same server that I use to host this site and other projects of mine. However due to certain circumstances I need to migrate to another VPS, and so I decided to write this little guide to refresh my memory on how to set up OpenVPN.

Before we begin to set up our VPN, we need to install OpenVPN. I am using Debian Stretch, so your install process may differ depending on your distro.

# apt-get install openvpn easy-rsa

Configuring OpenVPN

After installing the necessary packages, we proceed to configure OpenVPN. First we need to extract the sample OpenVPN server configuration file to /etc/openvpn

# gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf

Next we proceed to edit it.

# vim /etc/openvpn/server.conf

Inside we will make changes to basically use higher-level encryption, forward web traffic to destination, prevent DNS leaking, and set up permissions.

First we make sure that we are using 2048 bit-length keys instead of 1024. In my case it was already set to 2048 bit by default, however, the first time that I set up OpenVPN the default was 1024, so find this line

dh dh2048.pem

If instead you see "dh1024.pem" change it so that it is like in this example.

Next we make sure to redirect all traffic to its proper destination. Find this line

push "redirect-gateway def1 bypass-dhcp"

If it has a semicolon (;) at the beginning, remove it so that it is uncommented.

Now we will tell OpenVPN to use OpenDNS for DNS resolution. This will help prevent DNS requests from leaking outside of the VPN connection.

Immediately after the previous setting, you will see a block of comments followed by two commented lines

push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"

As previously, just remove the semicolon character from the beginning of the line.

Next we should comment the next line with a # or ; character. It is supposed to be used as an extra security measure especially against DoS attacks, however, we don't really need it

tls-auth ta.key 0 # This file is secret

If you really want to leave that on, you will need to generate it

openvpn --genkey --secret ta.key

And last but not least in our server.conf file, we need to adjust permissions. Find and uncomment these lines

user nobody
group nogroup

This way OpenVPN doesn't run as the root user. And we don't want any random program wildly running as root, especially ones that are exposed to the interwebz, no sir we don't ( ͡° ͜ʖ ͡°).

After having made all the needed changes, just write them and close the editor.

Configuring network and firewall

We need to enable packet forwarding, otherwise our traffic will not leave the server.

So that we don't have to reboot our server (let's leave all that rebooting to windows systems), we can enable it on runtime by running the following command

# sysctl net.ipv4.ip_forward=1

However, we need to make this change permanent as well, so we open the following file

# vim /etc/sysctl.conf

And uncomment the following line by removing the hash character (#) at the beginning of the line

net.ipv4.ip_forward=1

Save your changes and close the editor.

Now we need to properly set up our firewall. Personally I use ufw as front-end to iptables, since it is pretty easy to set up and use (as its name suggests, uncomplicated firewall). If you don't have it installed yet, you can go ahead and run

# apt-get install ufw

By default ufw denies all incoming connections and allow all outgoing. Those defaults are fine for my case, some might prefer to deny all outgoing connections by default, some riskier guys (or gals) might prefer to allow all by default (however, you wouldn't have unprotected fun time with just any partner, now would you?( ͡° ͜ʖ ͡°)), however explaining all the details about ufw is out of the scope of this tutorial, but I invite you use your duckduckgo-fu if you're interested in learning more about ufw.

Now, as ufw denies all incoming connections by default, we need to configure it so that we don't get locked out of our server. If you use the standard ssh port, just run the following command

# ufw allow ssh

ufw comes with some presets for the most common services, so that in fact allows connections from port 22 over tcp. If you, like me, prefer to use another port for SSH, you need to specify the port and protocol manually, so, if say, you connect to SSH over port 3333, you would run

# ufw allow 3333/tcp

(Of course that is not the actual port I myself use for ssh, so don't even try (That is however not an open invitation to try and guess my SSH port and hack yourself into my server (seriously, please don't hack me ´༎ຶ ͜ʖ ༎ຶ ))).

In this tutorial we will be using OpenVPN on port 1194 over UDP, so we must allow it

# ufw allow 1194/udp

Next we need to set ufw's forwarding policy, so we open the primary configuration file

# vim /etc/default/ufw

Modify the following line

DEFAULT_FORWARD_POLICY="DROP"

So that it looks like this

DEFAULT_FORWARD_POLICY="ACCEPT"

Save and exit.

Open this file

# vim /etc/ufw/before.rules

And add the rules for OpenVPN somewhere after the first block of comments

# START OPENVPN RULES
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to eth0
-A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE
COMMIT
# END OPENVPN RULES

Once more, save and exit.

Now we can safely enable ufw

# ufw enable

It will say something about disrupting current SSH connections, however, since we just added the needed rules for SSH we can go ahead and answer y.

Configuring the Certificate Authority

Now we are going to setup our own CA. This is crucial since OpenVPN encrypts traffic (what use is a VPN that doesn't encrypt traffic?)

First we need to copy the RSA generation scripts

# cp -r /usr/share/easy-rsa/ /etc/openvpn

Next, we create a directory to house our keys

# mkdir /etc/openvpn/easy-rsa/keys

Now we open the variables files

# vim /etc/openvpn/easy-rsa/vars

And modify these lines according to our needs/preferences (they are not that really important)

# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
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"

Then, in the same file, we need to change the name of the key. For simplicity's sake we will use the name "server", since that's the name that OpenVPN uses to reference the .key and .crt files by default. If you decide to use a different name, you will need to modify the OpenVPN configuration files that reference the aformentioned files.

So change this

# X509 Subject Field
export KEY_NAME="EasyRSA"

Into this

# X509 Subject Field
export KEY_NAME="server"

Save and exit.

Next we will use OpenSSL to generate the Diffie-Helman parameters. Grab a cup of tea, take a seat, it might take some minutes

# openssl dhparam -out /etc/openvpn/dh2048.pem 2048

Now that our certificate is ready, it's time to generate a key. For that, we first switch into the easy-rsa folder

# cd /etc/openvpn/easy-rsa

Now we start setting up the CA. We first, need to initialize the Public Key Infrastructure (PKI). For that we need to source the vars file

# . ./var

If you get something like this in your output

  No /etc/openvpn/easy-rsa/openssl.cnf file could be found
  Further invocations will fail

Your .cnf might have a different name (due to differing versions of OpenSSL). Just copy it like this

# cp openssl-*.cnf openssl.cnf

And source the vars file one more time.

After sourcing the vars file, it will give us a warning about removing some files. Don't sweat it, it's fine, since right now that folder is empty. So we go ahead and clear any and all keys that might interfere with out setup

# ./clean-all

Finally, we can go ahead and build our CA using the following command

# ./build-ca

We can skip through each prompt since we set up that info previously inside the vars file. The CA is now ready to go.

Generating a certificate and key for our server

Now we can proceed to actually setting up and launching OpenVPN.

While still on the easy-rsa folder, we input this command

# ./build-key-server server

server is the name of the key that we set up earlier in the vars file. We can go ahead, and as earlier leave the defaults which we configured in the vars file.

Upon reaching these prompts

A challenge password []:
An optional company name []:

Just press enter for both. We won't be needing them for this setup.

The last two entries require a y answer

Sign the certificate? [y/n]
1 out of 1 certificate requests certified, commit? [y/n]

Now that our server certificate and key are ready, we need to copy them over to /etc/openvpn, since that the directory in which OpenVPN will be looking for them

# cp /etc/openvpn/easy-rsa/keys/{server.crt,server.key,ca.crt} /etc/openvpn

Now we can start OpenVPN

# systemctl start openvpn

You can check if it launched correctly by running

# systemctl status openvpn

It should say something like "Active: active (exited) since..." then, congratulations! OpenVPN is now running in your server. If it says otherwise, maybe something like "inactive (dead)...", you might to check the log file "/var/log/syslog" for errors.

If all is fine and dandy, you can enable the OpenVPN service so that it automatically starts on each reboot

# systemctl enable openvpn

Generating certificates keys for clients

Ideally each client that needs to connect to the VPN should have their own unique certificate and key. Actually, by default, OpenVPN doesn't allow simultaneous connections using the same certificate.

Because of that you will need to repeat the steps in this section for each device that you wish to allow to connect to your VPN, just changing the name "desktop" below, to something different like "laptop" or "phone". This way you can also later deactivate a specific device/client from accessing if needed be.

I will start by building the key and certificate for my desktop computer, so I will be using the "desktop" name as an example. We still should be in our easy-rsa directory

# ./build-key desktop

Once more, as with the server's cert and key, we will asked about some info which we set on the vars, so we should skip all that by pressing enter (including setting the passwords). Just press y both times at the end to confirm.

Now we need the sample profile to the keys folder. We need to change its extension to ovpn, since that will be the file that OpenVPN will use on each device to automatically set the profile to connect to our VPN server

# cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/easy-rsa/keys/client.ovpn

The name of this file doesn't need to be related to our client's cert and key filenames, we can actually name to something that will describe our VPN, since that will be the name that OpenVPN will be pick up by default in our client device for our profile. So you can name it "work.ovpn" or maybe something more rich like "muhfreedumbs.ovpn"

# mv keys/client.ovpn keys/muhfreedumbs.ovpn

After that we need to make some modifications to our ovpn file, so open it up

# vim keys/muhfreedumbs.ovpn

And edit the line starting with remote with your server's ip address

remote your.ip.address.here 1194

And if you chose to leave out the "ta.key" file protection option, don't forget to comment this line

tls-auth ta.key 0

Next we find these two lines and uncomment them (remove the ; character at the beginning of each line)

user nobody
group nogroup

That's it. All that's left is to copy the client key and certificate, and the ovpn file over to our device. First we need to copy them to another folder that is available to our standard (non-root) user on the server for reading, since it is not a good idea to have root login enabled on SSH. For example, we could create a "vpnkeys" folder in our user's home directory

$ mkdir /home/yaroslav/vpnkeys

And then copy the need files over to that folder

# cp /etc/openvpn/easy-rsa/keys/{desktop.key,desktop.crt,muhfreedumbs.ovpn} /home/yaroslav/vpnkeys/

There is one more file that we need to copy, the server's certificate

# cp /etc/openvpn/ca.crt /home/yaroslav/vpnkeys/

If you previously also left the secret "ta.key" file enabled and generated it, you should copy that too.

Note that the "ca.crt" and the ovpn files will be the same for all devices. If you wish to create a new key/cert pair for another device/client, you DO NOT need to create a new ovpn file, just run the "./build-key clientkeyname" command as before and copy the same old ovpn and ca.crt file along with client key and cert to your other device.

Now we need to actually copy the keys to our device. You can use rsync or scp for that. For example, I will be using scp to copy them to my Keys folder

$ scp -P portno -r yaroslav@ipaddressorurl:/home/yaroslav/vpnkeys ~/Keys/

If you need to use your VPN on your mobile device, just copy them first to your computer through SSH, and then transfer them over to your mobile device.

After transferring them to the device, you should delete the keys from the home directory.

Conclusion

Now that all is setup on the server side of things, you can go ahead and add your VPN profile on your device. This process will vary greatly from device to device.

On most Linux distros/DEs, for example, you would go to your network manager, and select "Configure VPN..." or something like that. Then, a window with a list of (VPN) connections will appear, and you should be able to add your profile by clicking on the plus (+) button. After another window like this should pop up

VPN dialog

You should select the option that says "Import a saved VPN configuration..."

Note that the "openvpn" and "networkmanager-openvpn" packages should be installed in your (client) system.

Once you have connected to your VPN, you can head over to https://dnsleaktest.com/ to check your connectivity.

Now you can more safely and securely browse the interwebz, and be sure that no third-party VPN company is logging your activity.

© 2018—2024 Yaroslav de la Peña Smirnov.