github twitter linkedin email
Running OpenVPN in a Docker Container on Ubuntu 16.04.1 (and Debian 8.0)
Aug 3, 2016
4 minutes read


This tutorial will guide you into getting a docker container running on your Ubuntu/Debian host.

I originally followed this tutorial but with the introduction of systemd it is slightly out of date, so I have outlined exactly what to do in here.

I have also added instructions on how to add UPnP support which I needed as I have a permanent VPN connection at home via my RaspberryPi - guide here.

Initial Server Setup

If you’re on most VPS providers, you’re probably starting out with root. This is bad for a number of reasons.

Please follow these instructions, and at a minimum create your own user with sudo and disable root login.

Step 1 - Install and Configure Docker

Add the upstream Docker repository as the Ubuntu one can’t really keep up with the pace of change.

curl -L | sudo apt-key add -
echo deb docker main | sudo tee /etc/apt/sources.list.d/docker.list

Update packages and install Docker:

sudo apt-get update && sudo apt-get install -y lxc-docker

Add your user that you created earlier to the docker group.

sudo usermod -aG docker demo

Log out and log back in, running the id command should show the docker group present:

uid=1001(test0) gid=1001(test0) groups=1001(test0),27(sudo),999(docker)

Step 2 - Set Up the EasyRSA PKI Certificate Store

This step is usually a headache for those familiar with OpenVPN or any services utilizing PKI. Luckily, Docker and the scripts in the Docker image simplify this step by generating configuration files and all the necessary certificate files for us.

Create a volume container. This tutorial will use the $OVPN_DATA environmental variable to make it copy-paste friendly. Set this to anything you like. The default ovpn-data value is recommended for single OpenVPN Docker container servers. Setting the variable in the shell leverages string substitution to save the user from manually replacing it for each step in the tutorial:


Create an empty docker volume with a busybox image:

docker run --name $OVPN_DATA -v /etc/openvpn busybox

We’ll now init the OVPN_DATA container that will hold all of our config and certificates.

Make sure you replace with your intended FQDN, or use the IP if you are sure you won’t need to change it in the future. If you do need to change it, you would need to update every client file.

docker run --volumes-from $OVPN_DATA --rm kylemanna/openvpn ovpn_genconfig -u udp://

Generate PKI authority. Make sure you pick a good password and REMEMBER it!

docker run --volumes-from $OVPN_DATA --rm -it kylemanna/openvpn ovpn_initpki

Note, the security of the $OVPN_DATA container is important. It contains all the private keys to impersonate the server and all the client certificates. Keep this in mind and control access as appropriate. The default OpenVPN scripts use a passphrase for the CA key to increase security and prevent issuing bogus certificates.

Step 3 - Run OpenVPN Container

To autostart your OpenVPN Docker container, you’ll need to create a docker-openvpn.service file for systemd.

sudo vim /lib/systemd/system/docker-openvpn.service

Paste contents:

Description=Dockerized OpenVPN Service


ExecStart=/usr/bin/docker run --volumes-from ovpn-data --rm -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn
ExecStop=/usr/bin/docker stop kylemanna/openvpn



Enable the service on boot

sudo systemctl enable docker-openvpn.service

Start the systemd service:

sudo systemctl start docker-openvpn.service

Check the status:

sudo systemctl status docker-openvpn.service


sean@vpn2:~$ sudo systemctl status docker-openvpn.service
● docker-openvpn.service - Dockerized OpenVPN Service
   Loaded: loaded (/lib/systemd/system/docker-openvpn.service; disabled; vendor preset: enabled)
   Active: active (running) since Tue 2016-07-26 11:02:43 BST; 1 weeks 1 days ago
 Main PID: 4448 (docker)
    Tasks: 6
   Memory: 6.3M
      CPU: 1min 5.150s
   CGroup: /system.slice/docker-openvpn.service
           └─4448 /usr/bin/docker run --volumes-from ovpn-data --rm -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openv

You can also verify it is running via docker ps:

sean@vpn2:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
d1f61e8bd561        kylemanna/openvpn   "ovpn_run"          8 days ago          Up 8 days >1194/udp   big_snyder

Step 4 - Generate Client Cerificates and Config

Make sure you replace clientname in the following commands with your actual client name. For example, I used vpn2-xyz just to prefix the config files so I knew which server I was connecting to in Tunnelblick.

Create certificates with helpful scripts:

docker run --volumes-from $OVPN_DATA --rm -it kylemanna/openvpn easyrsa build-client-full CLIENTNAME nopass

Generate client config which is just one file to download via scp:

docker run --volumes-from $OVPN_DATA --rm kylemanna/openvpn ovpn_getclient CLIENTNAME > CLIENTNAME.ovpn

The CLIENTNAME.ovpn is self-contained and contains the certificates too, so download it now to your client and you will be ready to go!

Step 5 - UPnP Support

I noticed this was lacking when trying to stream a show on the Plex mobile app. I was unable to get a direct connection because my home now had a permanent VPN connection as discussed.

Back to posts

comments powered by Disqus