In this blog post, I describe how to set up an OpenVPN server on an Ubuntu 14.04 VM running on Azure. This blog post is an adaptation of "How To Set Up an OpenVPN Server on Ubuntu 14.04"[1] originally posted on the Digital Ocean blog.

By the end of this blog post, you'll have an OpenVPN server (available with two client configurations) that can be connected to securely.

We'll use Azure CLI 2.0[2] to set this up. If you haven't installed it yet, install using the install instructions available here.

Once installed, we can log in to our Azure subscription.

$ az login
To sign in, use a web browser to open the page and enter the code A11AAAAAA to authenticate.

Now, we create a resource group for our resources.
For this demo, we use southeastasia.
You can also opt to reuse a resource group you may already have if you wish.

$ az group create -n my-vpn-rg -l southeastasia
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-vpn-rg",
  "location": "southeastasia",
  "managedBy": null,
  "name": "my-vpn-rg",
  "properties": {
    "provisioningState": "Succeeded"
  "tags": null

Soon we'll create our VM but first, below is a cloud-init[3] script that we'll use to install OpenVPN on the VM and get things set up for us.

This script is a modification of another OpenVPN cloud-init script[4]. The modifications I made: allow the script to get the IP address of the VM; change the OpenVPN cipher from BF-CBC to AES-256-CBC[5], output two OpenVPN client configurations.

apt_update: true
  - openvpn
  - easy-rsa
  - IPADDR=$(dig +short
  - gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf
  - sed -i -e 's/;cipher DES-EDE3-CBC  \# Triple-DES/;cipher DES-EDE3-CBC  \# Triple-DES\ncipher AES-256-CBC/' /etc/openvpn/server.conf
  - sed -i -e 's/dh dh1024.pem/dh dh2048.pem/' /etc/openvpn/server.conf
  - sed -i -e 's/;push "redirect-gateway def1 bypass-dhcp"/push "redirect-gateway def1 bypass-dhcp"/' /etc/openvpn/server.conf
  - sed -i -e 's/;push "dhcp-option DNS"/push "dhcp-option DNS"/' /etc/openvpn/server.conf
  - sed -i -e 's/;push "dhcp-option DNS"/push "dhcp-option DNS"/' /etc/openvpn/server.conf
  - sed -i -e 's/;user nobody/user nobody/' /etc/openvpn/server.conf
  - sed -i -e 's/;group nogroup/group nogroup/' /etc/openvpn/server.conf
  - echo 1 > /proc/sys/net/ipv4/ip_forward
  - sed -i -e 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
  - ufw allow ssh
  - ufw allow 1194/udp
  - sed -i "1i# START OPENVPN RULES\n# NAT table rules\n*nat\n:POSTROUTING ACCEPT [0:0]\n# Allow traffic from OpenVPN client to eth0\n\n-A POSTROUTING -s -o eth0 -j MASQUERADE\nCOMMIT\n# END OPENVPN RULES\n" /etc/ufw/before.rules
  - ufw --force enable

  - cp -r /usr/share/easy-rsa/ /etc/openvpn
  - mkdir /etc/openvpn/easy-rsa/keys
  - sed -i -e 's/KEY_NAME="EasyRSA"/KEY_NAME="server"/' /etc/openvpn/easy-rsa/vars
  - openssl dhparam -out /etc/openvpn/dh2048.pem 2048
  - cd /etc/openvpn/easy-rsa && . ./vars
  # Optionally set indentity information for certificates:
  # - export KEY_COUNTRY="<%COUNTRY%>" # 2-char country code
  # - export KEY_PROVINCE="<%PROVINCE%>" # 2-char state/province code
  # - export KEY_CITY="<%CITY%>" # City name
  # - export KEY_ORG="<%ORG%>" # Org/company name
  # - export KEY_EMAIL="<%EMAIL%>" # Email address
  # - export KEY_OU="<%ORG_UNIT%>" # Orgizational unit / department
  - cd /etc/openvpn/easy-rsa && ./clean-all
  - cd /etc/openvpn/easy-rsa && ./build-ca --batch
  - cd /etc/openvpn/easy-rsa && ./build-key-server --batch server
  - cp /etc/openvpn/easy-rsa/keys/server.crt /etc/openvpn
  - cp /etc/openvpn/easy-rsa/keys/server.key /etc/openvpn
  - cp /etc/openvpn/easy-rsa/keys/ca.crt /etc/openvpn
  - service openvpn start

  - cd /etc/openvpn/easy-rsa && ./build-key --batch client1
  - cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/easy-rsa/keys/client1.ovpn
  - sed -i -e "s/;cipher x/cipher AES-256-CBC/" /etc/openvpn/easy-rsa/keys/client1.ovpn
  - sed -i -e "s/my-server-1/$IPADDR/" /etc/openvpn/easy-rsa/keys/client1.ovpn
  - sed -i -e 's/;user nobody/user nobody/' /etc/openvpn/easy-rsa/keys/client1.ovpn
  - sed -i -e 's/;group nogroup/group nogroup/' /etc/openvpn/easy-rsa/keys/client1.ovpn
  - sed -i -e 's/ca ca.crt//' /etc/openvpn/easy-rsa/keys/client1.ovpn
  - sed -i -e 's/cert client.crt//' /etc/openvpn/easy-rsa/keys/client1.ovpn
  - sed -i -e 's/key client.key//' /etc/openvpn/easy-rsa/keys/client1.ovpn
  - echo "<ca>" >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - cat /etc/openvpn/ca.crt >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - echo "</ca>" >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - echo "<cert>" >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - openssl x509 -outform PEM -in /etc/openvpn/easy-rsa/keys/client1.crt >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - echo "</cert>" >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - echo "<key>" >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - cat /etc/openvpn/easy-rsa/keys/client1.key >> /etc/openvpn/easy-rsa/keys/client1.ovpn
  - echo "</key>" >> /etc/openvpn/easy-rsa/keys/client1.ovpn

  - cd /etc/openvpn/easy-rsa && ./build-key --batch client2
  - cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/easy-rsa/keys/client2.ovpn
  - sed -i -e 's/;cipher x/cipher AES-256-CBC/' /etc/openvpn/easy-rsa/keys/client2.ovpn
  - sed -i -e "s/my-server-1/$IPADDR/" /etc/openvpn/easy-rsa/keys/client2.ovpn
  - sed -i -e 's/;user nobody/user nobody/' /etc/openvpn/easy-rsa/keys/client2.ovpn
  - sed -i -e 's/;group nogroup/group nogroup/' /etc/openvpn/easy-rsa/keys/client2.ovpn
  - sed -i -e 's/ca ca.crt//' /etc/openvpn/easy-rsa/keys/client2.ovpn
  - sed -i -e 's/cert client.crt//' /etc/openvpn/easy-rsa/keys/client2.ovpn
  - sed -i -e 's/key client.key//' /etc/openvpn/easy-rsa/keys/client2.ovpn
  - echo "<ca>" >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - cat /etc/openvpn/ca.crt >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - echo "</ca>" >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - echo "<cert>" >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - openssl x509 -outform PEM -in /etc/openvpn/easy-rsa/keys/client1.crt >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - echo "</cert>" >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - echo "<key>" >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - cat /etc/openvpn/easy-rsa/keys/client1.key >> /etc/openvpn/easy-rsa/keys/client2.ovpn
  - echo "</key>" >> /etc/openvpn/easy-rsa/keys/client2.ovpn

  - mkdir /home/openvpn
  - cp /etc/openvpn/easy-rsa/keys/client1.ovpn /home/openvpn
  - cp /etc/openvpn/easy-rsa/keys/client2.ovpn /home/openvpn
  - chmod +r /home/openvpn/client1.ovpn
  - chmod +r /home/openvpn/client2.ovpn

Now, we can create a VM in the region we desire and include the cloud-init script that will run when the VM gets created.

$ az vm create -g my-vpn-rg --image Canonical:UbuntuServer:14.04.4-LTS:latest -n openvpn1 --location southeastasia --size Basic_A0 --storage-sku Standard_LRS --custom-data ~/Dev/open-vpn-init.yml
  "fqdns": "",
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-vpn-rg/providers/Microsoft.Compute/virtualMachines/openvpn1",
  "location": "southeastasia",
  "macAddress": "00-0D-3A-A0-09-EC",
  "powerState": "VM running",
  "privateIpAddress": "",
  "publicIpAddress": "",
  "resourceGroup": "my-vpn-rg"

Once the script is created, in the background, the script will be run on the VM. Whilst this is happening, we should open the port required by OpenVPN.

$ az vm open-port --port 1194 -g my-vpn-rg -n openvpn1

Finally, we can download the client configurations.
It can take ~5 minutes for the files to be available as the cloud-init script may not yet be complete.

$ scp <IP_ADDRESS>:/home/openvpn/client1.ovpn ~/Downloads/southeastasia1.ovpn
$ scp <IP_ADDRESS>:/home/openvpn/client2.ovpn ~/Downloads/southeastasia2.ovpn

Now you can import your .ovpn file into the OpenVPN client of your choice.

  1. How To Set Up an OpenVPN Server on Ubuntu 14.04 - ↩︎

  2. Azure CLI 2.0 - ↩︎

  3. Cloud-init - ↩︎

  4. Digital Ocean open-vpn.yml script - ↩︎

  5. OpenVPN and SWEET32 - ↩︎