OpenVPN is a great tool to ensure traffic is not eavesdropped. You can use this to ensure a secure connection from your laptop to your DigitalOcean VPS (droplet) as well as between cloud servers. You can also have both done simultaneously.
This is not a foolproof, definitive, perfectly-secure, life-depends-on-it set of instructions. We will be taking three shortcuts here, which in my opinion are reasonable tradeoffs between ease of use and security, but I, nor DigitalOcean can be held responsible for security of your VPS, even if you follow these instructions.
To quote a cryptography rock-star, "You have to know what you are doing every step of the way, from conception through installation." — Bruce Schneier
This article is to help get you started on your way to setting up a Virtual Private Network. You have been warned. I'll point out the shortcuts taken and the general sequence to avoid making these shortcuts at Appendix 1.
If you only want to have two cloud servers to connect to each other, you may want to find a simpler (yet less secure) tutorial — though this is a good compromise between ease of setup and security.
Note: This tutorial covers IPv4 security. In Linux, IPv6 security is maintained separately from IPv4. For example, "iptables" only maintains firewall rules for IPv4 addresses but it has an IPv6 counterpart called "ip6tables", which can be used to maintain firewall rules for IPv6 network addresses.
If your VPS is configured for IPv6, please remember to secure both your IPv4 and IPv6 network interfaces with the appropriate tools. For more information about IPv6 tools, refer to this guide: How To Configure Tools to Use IPv6 on a Linux VPS
You'll need at least two droplets or VPS for this OpenVPN setup, and will work up to around 60 VPS without major modifications. So to get started, create two droplets. For the rest of this tutorial, I'll refer to them as Droplet 1 and Droplet 2.
• Create the droplet with Ubuntu 13.04 x32.
This should work without modification on any version of Ubuntu that DigitalOcean offers, but was only tested on 13.04.
Connect to the VPS via secure shell. We're going to update packages and install a few things.
aptitude update && aptitude dist-upgrade -y && aptitude install openvpn firehol -y && reboot
Note, if your shell goes purple during this, just choose "Install Package Maintainer's Version" twice.
• Create the droplet with Ubuntu 13.04 x32.
Again, this should work on any version of Ubuntu.
Connect to the VPS via secure shell. We're going to update packages in install a few things.
aptitude update && aptitude dist-upgrade -y && aptitude install openvpn -y && reboot
Again, if your shell goes purple during this, just choose "Install Package Maintainer's Version" twice.
The key generation is going to be done exclusively on Droplet 1. Type the following commands into the shell:
cd /etc/openvpn/ mkdir easy-rsa cd easy-rsa cp -r /usr/share/doc/openvpn/examples/easy-rsa/2.0/* .
Next, we're going to type in some presets which will vastly speed up the key generation process. Type the following command:
nano /etc/openvpn/easy-rsa/vars
Go ahead and edit the following values (you only need do to these, although there are several more present):
You may adjust the KEY_SIZE to 2048 or higher for added protection.
Save and exit with Control-O, Enter, and Control-X.
Next, type the following commands:
source vars ./clean-all ./build-ca
You should be able to hit Enter though all of the questions.
Note: if you ever have to go back and create more keys, you'll need to retype source vars but don't type ./clean-all or you'll erase your Certificate Authority, undermining your whole VPN setup.
Generate the server certificate and key with the following command:
./build-key-server server
You should be able to hit Enter on defaults, but make sure the Common Name of the certificate is "server".
It will ask you to add a pass phrase, but just hit Enter without typing one.
When it asks you "Sign the certificate?", type y and hit Enter.
When it says "1 out of 1 certificate requests certified, commit?", type y and hit Enter.
Next is generating the certificate and keys for the clients. For security purposes, each client will get its own certificate and key.
I'm naming the first client "client1", so if you change this, you'll have to adjust it several times later. So type in the following:
./build-key client1
As with the server key, when it asks you "Sign the certificate?", type y and hit Enter.
When it says "1 out of 1 certificate requests certified, commit?", type y and hit Enter.
Go ahead and repeat this for as many clients as you need to make. You can also come back to this later (though remember to "source var" again if you do so).
This is used after authentication, to determine the encryption parameters. Simply type the following line:
./build-dh
Next, we copy the various keys and certificates into place on the cloud server:
cd /etc/openvpn/easy-rsa/keys cp ca.crt dh1024.pem server.crt server.key /etc/openvpn
It's very important that keys are kept secure. Double check that only root has permission to read. So type:
ls -lah /etc/openvpn
What you're looking for is that server.key has -rw------- for permissions (read/write for owner, none for group, and none everyone). If you need to change it, use this command:
chmod 600 /etc/openvpn/server.key
The following table shows which files go onto which client.
client1 | client2 |
---|---|
ca.crt | ca.crt |
client1.crt | client2.crt |
client1.key (SECRET) | client2.key (SECRET) |
We'll securely copy the files to the second VPS using secure copy. (You could also cat, then copy and paste across SSH windows. But this is a nice technique to securely copy files.)
Generate SSH keys with the following command:
ssh-keygen -t rsa
It will choose a default filename and then ask you for a secure passphrase, which you should set. Find the SSH public key you just generated and type:
cat ~/.ssh/id_rsa.pub
Copy the results onto the clipboard. It's a few lines of letters and numbers looking like:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCo249TgbI1gYP42RbLcDhsNN28r/fNT6ljdFOZxhk+05UAPhxq8bASaqSXZI3K8EEI3wSpigaceNUu65pxLEsZWS8xTtjY4AVxZU2w8GIlnFDSQYr3M2A77ZAq5DqyhGmnnB3cPsIJi5Q6JQNaQ/Meg1v7mYR9prfEENJeXrDiXjxUqi41NlVdb5ZQnPL1EdKM+KN/EPjiTD5XY1q4ICmLJUB8RkffHwH2knEcBoSZW2cNADpMu/IqtxTZpFL0I1eIEtoCWg4mGIdIo8Dj/nzjheFjavDhiqvUEImt1vWFPxHEXt79Iap/VQp/yc80fhr2UqXmxOa0XS7oSGGfFuXz root@openvpn1
But USE YOUR OWN, not mine. Your id_rsa.pub doesn't need to be kept secure, but if you use the key above, that would allow me access to your VPS.
cd ~/.ssh
(If you get an error, create the folder with mkdir ~/.ssh
).
nano authorized_keys
Paste the public key that is in your clipboard onto a new line, then save and exit with Control-O, Enter, Control-X.
Next, we copy the appropriate keys onto the second server:
scp /etc/openvpn/easy-rsa/keys/ca.crt \ /etc/openvpn/easy-rsa/keys/client1.crt \ /etc/openvpn/easy-rsa/keys/client1.key \ root@droplet2ip:~/
It will ask you "Are you sure you want to continue connecting (yes/no)?", so type yes and hit Enter.
Then input the passphrase you've just created.
Next, we move the certificates and keys into their final location:
cd ~ mv ca.crt client1.crt client1.key /etc/openvpn ls -l /etc/openvpn
As the key must be kept secure, let's make sure client1.key has the correct permissions (-rw-------).
Again, if need be, the permissions can be reset with the following command:
chmod 600 /etc/openvpn/client1.key
Next comes the excitement that is networking on a VPN. You can use OpenVPN using routing or bridging. If you know what the difference is, you don't need my help choosing. For this tutorial, we'll use routing. We'll also use OpenVPN's default network range, which is 10.8.0.0/24. Unless you already use this network range somewhere, this will be fine. If you do need a different range, pick a private range and make sure you adjust all the later configuration steps accordingly.
On the OpenVPN server, we need to configure routing and setup a firewall as well. I use a tool called firehol to configure iptables, which makes it very simple to set up a complex firewall. So, type the following commands:
nano /etc/firehol/firehol.conf
While we could allow incoming OpenVPN connections from any address, we're going to limit these connections to the IP addresses of the computers you want to connect. Make this list of your IP addresses now.
Note: The following configuration only allows incoming SSH and OpenVPN connections. If you have other services that need to receive incoming connections, you'll need to modify the firewall to support these.
version 5 interface eth0 inet client all accept // allow all outgoing connections server ssh accept // allow all incoming SSH connections server openvpn accept src "1.2.3.4 2.3.4.5" // allow incoming OpenVPN connections // from these designated addresses // NOTE: EDIT THESE ADDRESSES interface tun0 vpn server all accept // allow all incoming connections on the VPN client all accept // allow all outgoing connections on the router inet2vpn inface eth0 outface tun0 route all accept // route freely to the VPN router vpn2inet inface tun0 outface eth0 masquerade // use NAT masquerading from the VPN route all accept // route freely to the VPN
Then, start the firewall with the following command:
firehol start
If you have an issue with your firewall, you can restart your VPS and the firewall configuration will be cleared. To make the firewall permanent, input the following:
nano /etc/default/firehol
Find the following line:
START_FIREHOL=NO
Now, change NO to YES. Save and exit with Control-O, Enter, Control-X.
The next step is to copy the example server configuration into place and edit it to our needs.
cd /etc/openvpn cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz . gunzip server.conf.gz nano /etc/openvpn/server.conf
The OpenVPN server will start as root, but we can set it to drop to lower privileges after startup, which is a good security measure. To configure this, find the following lines and uncomment them by removing the semicolons:
;user nobody ;group nogroup
If you have multiple servers that should communicate to each other, find the following line and remove the semicolon:
;client-to-client
If you increased the key size of your DH key, find the line:
dh dh1024.pem
and change 1024 to 2048 (or whatever number you selected).
We're going to assign the different clients static IP addresses from the OpenVPN server, so to do that, uncomment the following line:
;client-config-dir ccd
Save with Control-O, Enter, Control-X. Next, make the client configuration directory:
mkdir /etc/openvpn/ccd
and we'll add configuration for the first client here:
nano /etc/openvpn/ccd/client1
Type the following command, which assigns client1 to IP address, 10.8.0.5:
ifconfig-push 10.8.0.5 10.8.0.6
Save and exit with Control-O, Enter, Control-X.
For reasons that require an in-depth knowledge of networking to understand, use the following addresses for additional clients:
/etc/openvpn/ccd/client2 ifconfig-push 10.8.0.9 10.8.0.10
/etc/openvpn/ccd/client3: ifconfig-push 10.8.0.13 10.8.0.14
Simply, add 4 to each IP for each new set. A more technical explanation is at Appendix 2.
Now we can start the OpenVPN server with the following command:
service openvpn start
Give it a second, then type the following commands to ensure OpenVPN is running:
ifconfig
And among the network interfaces, you should see that the interface tun0 look like this:
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 inet addr:10.8.0.1 P-t-P:10.8.0.2 Mask:255.255.255.255 UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 RX packets:140 errors:0 dropped:0 overruns:0 frame:0 TX packets:149 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 RX bytes:13552 (13.5 KB) TX bytes:14668 (14.6 KB)
You can also type:
service openvpn status
and if OpenVPN is running, you'll see the following:
* VPN 'server' is running
If both of these are in order, then the server is up and running and we'll configure the client connection next.
First, let's copy the sample client configuration file to the proper locations:
cd /etc/openvpn cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf .
It’s mostly configured, but we have to “tell” the address of our OpenVPN server, Droplet 1:
nano /etc/openvpn/client.conf
Find the line that says:
remote my-server-1 1194
And change my-server-1 to the IP address of Droplet 1. Next, we have to ensure that the client key and the certificate matches the actual file names. Search for the following lines:
cert client.crt key client.key
and adjust them to the keys copied over (e.g. client1.crt and client1.key).
Save and exit with Control-O, Enter, Control-X.
And next, let's start up the VPN:
service openvpn start
Again, we can test it with the following commands:
service openvpn status
ifconfig
Now that both ends of the VPN are up, we should test the network. Use the following command:
ping 10.8.0.1
And if successful, you should see something like:
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data. 64 bytes from 10.8.0.1: icmp_req=1 ttl=64 time=0.102 ms 64 bytes from 10.8.0.1: icmp_req=2 ttl=64 time=0.056 ms
Any traffic you do not need encrypted, you can connect via the public-facing IP address. Any traffic between cloud servers you want encrypted, connect to the Internet network address, e.g. Droplet 1 connect to 10.8.0.1. Droplet 2 is 10.8.0.5, Droplet 3 is 10.8.0.9, and so on.
Encrypted traffic will be slower than unencrypted, especially if your cloud servers are in different datacenters, but either traffic methods are available simultaneously, so choose accordingly.
Also, now is a good time to learn more about OpenVPN and encryption in general. The OpenVPN website has some good resources for this.
There were three shortcuts used here which if security is of the utmost importance, you should not do.
Additionally, OpenVPN supports loads of other hardening features, beyond the scope of this tutorial. Reading up at openvpn.org should be done.
So the first client will use 10.8.0.6 as its IP address, and 10.8.0.5 is the VPN tunnel endpoint. The second address is only used to route traffic through the tunnel. This is because each client uses a CIDR /30 network, meaning 4 IP addresses are used per client computer.
So the VPN server will use the 10.8.0.0/30 network:
10.8.0.0 | Network |
10.8.0.1 | Server IP address |
10.8.0.2 | Tunnel Endpoint |
10.8.0.3 | Broadcast |
And the first client, client1, will use the 10.8.0.4/30 network:
10.8.0.4 | Network |
10.8.0.5 | Server IP address |
10.8.0.6 | Tunnel Endpoint |
10.8.0.7 | Broadcast |
And so on...
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
ubuntu 14.04 easy-rsa not installed as noted above
but then the files weren’t at /usr/share/doc/openvpn/examples/easy-rsa/2.0/* A README.Debian for easy-rsa was at /usr/share/doc/easy-rsa
Alberto, the author said: The effortless way to use it is calling “make-cadir DIRECTORY”, which will create a new directory with symlinks to the scripts and a copy of the configuration files so you can edit them to suit your needs.
i.e.
It sounds like that’s the vars I should copy and edit in /etc/openvpn/easy-rsa/vars I’ll try that. Yup. created a bunch of symlinks in that dir, and also the file called vars.
looks like I should copy all the symlinks too
because when I do
That’s in the my_ca dir
@travis: You can set the
local
directive to your OpenVPN server’s private IP address inserver.conf
so that OpenVPN listens on the private interface instead of the public one. Make sure you replaceeth0
witheth1
in the firewall config too.@Kamal: It looks like this example is only using eth0 (the public interface). It seems to me that people would want to use the private network to avoid bandwidth charges between their droplets. Any examples of using OpenVPN across DO’s shared private network?
Thanks!
Hi guys, struggling with the part where you have to copy over the files to the 2nd droplet via SSH.
i.e. “scp /etc/openvpn/easy-rsa/keys/ca.crt
/etc/openvpn/easy-rsa/keys/client1.crt
/etc/openvpn/easy-rsa/keys/client1.key
root@droplet2ip:~/”
I keep getting the error " Permission denied (publickey) " no matter what user I try to send the file with.
Is it something to do with root permissions (In both droplets I have disabled root login and both have 2 factor google authentication).
The above tutorial is also based on firehol, whereas I set both droplets up with ufw in line with the latest DO tutorials - so this also complicates following the tutorial above. Is there a more recent one which also includes configuration of ufw?
I’ve also tried using parts of this one: https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-16-04 but it’s not quite relevant, especially once you get to the step where you need to share the certificate/key with the 2nd droplet.
I’m using a Ubuntu 16.04 server.
Thanks for any help - much appreciated!
Does this tutorial accomplish:
Client OpenVPN on home PC/Router —>VPS running OpenVPN server & client ---->Another OpenVPN provider (not your own vps/vpn but a paid subscription provider)?
I want to run obfsproxy from my router to VPS but not VPS to another VPN provider. (If that makes sense)
I’m running and ubuntu lemp stack, version 14.04.1 lts. When running firehol during this tutorial,
firehol start
it cannot locate any kernel configuration as noted:A number of errors follow, upwards of 200 of them. Here are some examples:
These all seem to be resultant of the first warning. Upon listing out the errors, firehol fails and restores the old firewall successfully.
The directory in which they expect the config file doesn’t exist, instead I am finding a few version-specific directories.
I’ve looked for some resolutions elsewhere but I cannot find much.
Any help would be appreciated!
firehol didn’t seem to like the “//” for comments in the firehold.conf example.
I changed to “#” and it worked
Hello!
We have configured an OpenVPN server in AMS2 with internal networking activated and routing enabled. We are able to connect to the VPN server, but we can not connect to other internal servers. There is communication between all the internal servers.
We are thinking that DO are not allowing to reach internal private Ethernet servers when the requesting source IP is not in the internal private network
From our droplet VPN server (10.129.141.126 ), we see the IP packets being sent from the private eth1 interface but never reach the eth1 interface of server 10.129.134.225
16:57:48.314868 04:01:34:bb:b8:02 (oui Unknown) > 04:01:3c:63:81:02 (oui Unknown), ethertype IPv4 (0x0800), length 74: 10.8.0.4 > 10.129.134.225: ICMP echo request, id 768, seq 256, length 40
The only frames we see in the internal servers, are broadcast frames (for example ARP) and any other frame with source IP from the same network (10.129.0.0/16)
Does anybody have an idea of what is going on?
Thank you very much.
Best regards.
Joel
@Kamal: Update: to get the easy-rsa files on Ubuntu 14.04 you need to install it separately:
Cheers.
@Kamal: The openvpn install not longer has a /usr/share/doc/openvpn/examples/easy-rsa directory:
Which of these needs to be copied for the following instruction in the guide:
Thanks!