Automating Deploying a Personal VPN Server with Cloud-Init on Your Provider

Joseph D. Marhee
Jan 29, 2017 · 5 min read

Note: If you came here from VPN Deployer (, you do not need to complete these steps; this process is entirely automated if you deploy using the site. For those users, this piece is purely informational.

Using untrusted networks is a very simple mistake to make, and it’s, seemingly, easy to avoid doing so, but it is also trivially simple for users to secure their connections to some degree. One common method is to make use of a VPN to secure said connection.

This, of course, is not a magic-bullet solution, but it can be where you begin to use the Internet more defensively (of, not only, your privacy, but also your data’s security). This guide will detail a baseline method for approaching your usage of the Internet through a more secure (remember, there is no totally secure method, so I recommend using this as a jumping off point to more and deeper ways to secure your data, but for the casual user, this may suffice as a quotidian means of browsing securely) channel.

I recommend, for more security, and a managed solution, a commercial VPN like:


What you’ll need

  1. A DigitalOcean Account. (Note: I do not recommend using this provider going forward; this user-data script will function on any system that can use bash as a start-up script — providers like AWS and OpenStack support cloud-init in this manner)
  2. A copy of this script (you’ll be copy and pasting the contents later into the DigitalOcean UI):

3. An OpenVPN client. If you use OS X:

or the openvpn CLI utility.

If you are on Windows:

If you are on Linux, you can use NetworkManager provided tools, but my preferred method is to use the openvpn CLI utility:

How It Works

Inspired by another project, I took a Docker-based approach to deploying the software, and distributing (temporarily) the client configs.

When DigitalOcean’s provisioner runs the above script (which I will cover in a moment), it runs docker-compose to deploy the OpenVPN server, a single-use image to provide the config (exposed only to the web UI for a single request before killing the image), and a web UI that generates a one-time access to the config. If your config is unavailable, for example, it means that someone has accessed it before you, and thus you should recreate the server. This workflow ensures that only a single copy of the config can be downloaded.


Navigate to the Create Droplet form:

The above URL specifies (change as you desire on the Create page itself):

  1. You are deploying a 512 MB droplet .
  2. In AMS3 (if you wish to use a location closer to yourself, this can be changed on the form as well)
  3. Using the Docker One-Click Image (Required, for this to function as expected).

Before you move on, scroll down to the check box for “User Data”, and check it:

Copy and Paste the script data from this URL into the box:

so it should look like this:

and scroll down and click “Create”.

Getting Your Client Configuration

Once the droplet is created, you can find the IP Address on the Droplets page.

Note: Please allow a few minutes for the provisioning script to finish running before moving on to the next step.

You can, then, navigate to: http://your_ip_address:10889 where you’ll see a page like this:

Click to download the config. It should provide a file called client.ovpn

Consult your OpenVPN client documentation for loading your configuration. For most OS X and Windows based clients, you will usually, for example, be able to double-click the file to open it in the client, and begin connecting.

Testing it Out

A personal favorite IP checker of mine is which can provide you with output like:

if you check before you connect, and then after, if you receive different results (a different IP, hostname, or geographic location, for example), then it will indicate your connection to the VPN server was successful.

Notes & Acknowledgements

All of the Dockerfiles, scripts, etc. used in this post can be found here:

I, obviously, was influenced by, and updated much of what existed in this project. To enumerate these changes:

  1. Uses DNSWatch’s DNS resolver rather than Google’s DNS resolvers:

2. Uses docker-compose to deploy the VPN container, and facilitates deploying the UI to receive the one-time configuration.

3. I updated the dockvpn image used in my compose file to a more recent Ubuntu version (14.04, or the ubuntu:trusty Docker image)

4. The serveconfig command was modified to serve the config only one, before terminating that container entirely (meaning the web UI cannot pull the config more than once).

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store