A few weeks ago here at Hone, we decided to spin a new server cluster in DigitalOcean’s NYC3 data center. DigitalOcean introduced ‘private’ networking just over a year ago. However, it turns out that DigitalOcean actually refers to this as Shared Private Networking—and many of the comments under their announcement point out that their private networking isn’t really too private.
We decided to use OpenVPN to layer a secure network on top of DigitalOcean’s shared private networking.
What we wanted to accomplish:
- Install an OpenVPN server on our load balancer
- Install an OpenVPN client on all of our other machines
- Drop any traffic other than OpenVPN on
eth1(DO’s shared private network)
- Allow all traffic over
tun0(our secured private network)
With traffic passing through the
tun0 interface between machines, we gain the ability to more quickly and easily spin up new machines and add them to our infrastructure.
Here’s how to setup a virtual private network on DigitalOcean (or whichever provider you might be using):
Setup / Configure Your OpenVPN Server
Update your packages and install OpenVPN and Easy RSA:
Copy some Easy RSA files over to a more permanent location so that you can upgrade OpenVPN in the future without losing your configuration settings:
/etc/openvpn/easy-rsa/vars and change the various exports for default certificate values.
At the very least, you’ll want to change the following keys in the
vars file to suit your needs:
vars configured, you can now generate a master Certificate Authority (CA) Certificate and Key for your server:
Generate a certificate and private key for the server:
Generate some Diffie–Hellman–Merkle parameters for the OpenVPN server (This will take a minute or two):
Copy the keys, certs, and the Diffie–Hellman–Merkle params that you generated from
/etc/openvpn/easy-rsa/keys into your OpenVPN directory,
Generate Certificates For VPN Client(s)
You’ll need to generate a certificate and key for each VPN client:
Securely copy these the following files to the client machine (via
After you’ve copied these keys and certs to your client machine(s), delete them from the VPN server. They’re no longer needed on that machine and keeping them there poses a security risk if unauthorized access is gained.
Edit Your OpenVPN Server Config
Copy over and unpack the provided example server config—
/etc/openvpn/server.conf to ensure it contains the settings that make sense for your intended setup.
You’ll want to make sure it points to the correct location of your certs, keys, and
dh2048.pem file (Diffie–Hellman–Merkle parameters) that you generated earlier.
Here’s an example of some lines you should configure (or uncomment) in
client-to-client will enable your VPN clients to communicate with one another directly. By default, VPN clients will only see the VPN server.
Start OpenVPN on your server
Check That it Works
After you start your openvpn service, you should see
tun0 interface details when you run:
If you’ve set up your server correctly, you should see some output like this:
If you run the
ifconfig tun0 command above and see the error
ifconfig: interface tun0 does not exist, then you’ll need to check your OpenVPN server.conf again and make sure to reconfigure it.
Setup / Configure Your OpenVPN Client(s)
Update your packages and install OpenVPN:
Copy the example
client.conf file over to
If you haven’t already done so: Make sure that you’ve generated and then securely transferred (or manually copied over)
<vpn_client_name>.key to your new VPN client.
(For the purposes of this tutorial, I’ve copied them into
/etc/openvpn/client.conf and make sure everything points to correct certs and keys. You should also make sure to specify the IP address corresponding to your OpenVPN server’s
eth1 interface (DO’s shared private network):
Having finished editing
client.conf, you can restart the OpenVPN service on your VPN client machine:
Check to see that you’ve got a
tun0 interface (and that it has the correct IP):
Ping Your VPN Server (From Client Machine)
If you’d like to sanity-check your connection to your VPN server, try pinging the OpenVPN server directly:
In this example, I’m pinging
10.8.0.1, which is set by OpenVPN default server config. You may have selected something different, in which case you should find the IP corresponding to your OpenVPN server’s
You can grab this IP quickly by running (on the OpenVPN server itself):
If you can’t ping the OpenVPN server, then something is wrong with your config. Consider re-reading all of the above.
Assign Static IPs to VPN Clients
You may desire to assign static IP addresses to some or all of your client machines. (Hat-tip to Michael Albert for a great post which helped here.)
On your OpenVPN server, create a folder in which to save the information of your static clients.
In this example, we’ll name our folder
Make sure to uncomment and edit this line in
Previously, when you generated a cert and key for your new VPN client, recall the
common_name that you chose.
Create a file—naming it whatever you chose for the
/etc/openvpn/static_clients/ with the following content:
(Note that in this example, we’d like this VPN client’s
tun0 interface to be assigned the IP
OpenVPN will need to read these files after it drops privileges. You can do that do that with the following:
If you want to further secure your VPN, you should edit your VPN client machine’s
iptables. With your OpenVPN server and clients set up correctly and pingable (in both directions) via their
tun0 interfaces, you can begin restricting traffic over your
eth1 (DO’s shared private network interface) to accept only traffic over port
1194 (OpenVPN’s default port) on that interface.
For example, if you’re routing traffic through a load balancer, you may want to lock down VPN client boxes as such:
- Restrict access on
eth0interface (public) to port 22 only
- Restrict access on
eth1interface (DO’s shared private network) to udp/tcp traffic over port 1194 only
- Unrestricted access on
tun0interface (OpenVPN tunnel interface).
Here’s an example
iptables config that would restrict traffic in the way I mention above:
Hone is Hiring!
Credit Where Credit Is Due
While figuring out how to do everything above—and while I was writing this tutorial—I was reading and consulting with the following sources: