Configure a self-hosted VPN Server using OpenVPN Access Server and Azure VM

Creating and configurating the Virtual Machine

First you must create an Azure VM. If you intend to use it only for you I suggest using a very low power VM running Ubuntu.

You can check hardware requirements for an Access Server installation on the official OpenVPN documentation: https://openvpn.net/as-docs/system-requirements.html#hardware-requirements

For memory requirements it says that you should start with at least 1GB of RAM and add 1GB for every 150 connected devices. For hard disk it says that typically, 16GB of disk space is sufficient, as it only needs to store connection logs, program logs, user certificates and settings.

For this example we will be using a Standard_B1s, which has 1 vcpu, 1GiB of RAM and 4GiB of local storage. Remember that in the creation of the disks you can use a different sized disk, the default should be a 30 GiB disk, so we will be using that. Also a Standard SSD LRS is enough for our use, you do not need the Premium SSD. You can use a larger disk if you feel it would not be enough, but in my case it has been enough so far.

For networking we will be creating a new Public IP to assign it to the VM. This public IP will be the one that will be connecting from when connected to the VPN, so all our connections are made from this IP.

We will be using the latest Ubuntu Server LTS available, at the time of writing this the latest version is 24.04 LTS

Once our VM is created and ready, I suggest configuring the following Inbound port rules inside the Network Settings on the Virtual machine resource:

Priority Name Port Protocol Source Destination Action
Default (300) SSH 22 TCP Your IP Any Allow
Default (320) HTTPS 443 TCP Any Any Allow
Default (330) OpenVPN 1194 UDP Any Any Allow
Default (340) OpenVPNAdmin 943 TCP Your IP Any Allow

I will briefly explain each rule and its configuration:

  • SSH: This is for connecting through SSH so you can configure your VM. I recommend using your IP in the Source field, and even change it from Allow to Deny once you have completely configured the VM to reduce the attack surface. Remember that this VM is going to be exposed to the internet.
  • HTTPS: Used only for downloading user profiles from the OpenVPN Connect client. Once you have the profile downloaded on all your devices, you could change this rule to Deny to reduce the attack surface.
  • OpenVPN: This UDP port is what we will use to establish the VPN connection. Leave Source as Any to be able to connect from anywhere, otherwise if you are on a network that has a static IP you could set this field to that IP to reduce the attack surface.
  • OpenVPNAdmin: Port used to connect to the web panel. Set the source to your IP or either Deny any connection after all the set up is done.

Installing and configuring OpenVPN Access Server

Open an elevated terminal using sudo su - and run the following command:

bash <(curl -fsS https://packages.openvpn.net/as/install.sh) --yes

You can check if the service is running by executing systemctl status openvpnas.service

You will need to create a user using the OpenVPN Admin web panel. The default port (and the one we exposed on the network settings of the VM) is 943, so you would access the web panel by accesing to https://{your-vm-public-ip}:943

You will need to retrieve the auto generated password which is set when OpenVPN initializes. You can get it by executing cat /usr/local/openvpn_as/init.log

At the end of the file you should see something like this:

To login please use the "openvpn" account with "{REDACTED}" password.

openvpn is the default admin user, your randomly generated password should be in place of {REDACTED}

Enter to the OpenVPN web admin and create a new user that you will be using for connecting to the VPN. Also make sure to change the openvpn user password to something more secure.

Installing OpenVPN Connect

If you are on a desktop computer download the OpenVPN Connect client from the official website: https://openvpn.net/client/

You can also get the client either for Android or iOS from their respective app stores by searching OpenVPN Connect, make sure the developer is either OpenVPN or OpenVPN Inc.

Configuration and connection procedures are the same on all platforms, Windows, macOS, Android and iOS, as they all share the same UI. Linux is the exception as it uses a command line tool, you can refer to the documentation on the link provided earlier in this section.

Configuring a profile and connecting to the VPN

Open OpenVPN Connect and you will be asked right away to insert a "Server Address or Cloud ID". We will write the virtual machine public IP address where we installed OpenVPN Access Server.

At this point is important to have configured the HTTPS port and is accessible from our current network IP. If it is, most probably you will be greeted with a certificate error, you can choose to accept it because we have not configured any SSL certificate and is using a self signed certificate. You can check the Common name under Issued by to ensure the hsotname of your VM matches with this.

Then we will be asked for a username, password, profile name and port. Use the username and password you created previously on the OpenVPN web admin panel. You can choose to give it a name to identify it easily. For the port, you can leave it blank as it will use the default 1194 UDP.

Before connecting, press the pencil icon at the right of the profile. You will see an empty field named "Server Override (optional)". I'm not sure if it is a bug or is something which is misconfigured and I'm not yet aware, but if you do not configure this field you will receive a timeout and never reach the VPN server. In this field write the virtual machine public IP as we did when configuring the profile. Server Hostname and Server Override must match.

While at it, you can also check "Save password" if you want to avoid writing the password everytime you want to connect to the VPN, make sure to write the password on the field that just appeared when you pressed on the checkbox.

Press Save at the top right and you will returned to the main screen. With all this in you should be able to connect to your VPN, press on the slider on your VPN profile and you should connect to the VPN right away. You should see a graph indicating bytes in and bytes out, along other information.

Make VM safer using fail2ban

As I said previously, after configuring users and profiles you can deny access to most of these ports except the OpenVPN port which corresponds to UDP 1194

Either way, if you want to make your VM even stronger against attacks, specifically brute force attacks, you can install fail2ban. This is not necessary for OpenVPN but is presented here for completeness. Notice that you can also configure a "block account" setting on the OpenVPN admin web panel which disables an account if too many failed login were attempted, which is similar to what fail2ban does, except fail2ban bans the IP from which these requests were done, and for much time as wanted. This in fact deny access to the source IP to the VPN server, where it doesn't even have an opportunity to connect to the server.

Installing fail2ban

You can install fail2ban by running the following command:

sudo apt install fail2ban

You can check if the service is properly running by executing systemctl status fail2ban.service

Configuring OpenVPN Access Server filter and jail

Configuring a jail and its filters is an involved procedure that takes some time as, at least in this case, we must check failed login attempts looking at the log files that OpenVPN Access Server writes, while also retrieve the IP from which these requests are being made.

You can use command fail2ban-regex to test your regex for parsing the log files, this is an example I was using against the OpenVPN Access Server logs:

fail2ban-regex -v --print-all-matched /var/log/openvpnas.log "^(.*)\"<HOST>\"\s\-\s\-.*\"GET.*HTTP.*401\s177.*" "127\.0\.0\.1"

Hard to understand at first sight, but it basically does some regex operations, while also adding an exception for the 127.0.0.1 IP, which I don't want to block. I added this just in case because I have seen some requests made from that IP, which is basically the loopback address localhost, you might not want to block that. I also want to make sure to count for when the error is an authentication error, 401 in this case.

Once you have a working regex, you can create the filters. I will be using two different jails and filters in this case. One is for failed attempts at the OpenVPN web panel, and the other from the client.

I will create first the OpenVPN Connect filter by running sudo vi /etc/fail2ban/filter.d/openvpnas.conf and the following content:

[Definition]
failregex = :[0-9]+\sSENT\sCONTROL\s.*?AUTH_FAILED.*
ignoreregex =

The second filter is for the OpenVPN web panel, the same as before, create another filter at /etc/fail2ban/filter.d/openvpnas-https.conf

[Definition]
failregex = ^(.*)\"\"\s\-\s\-.*\"GET.*HTTP.*401\s177.*
ignoreregex = 127\.0\.0\.1

Now proceed to create the jails. I will create two jails inside a single file at /etc/fail2ban/jail.d/openvpnas.conf

[openvpnas]
enabled = true
filter = openvpnas
logpath = /var/log/openvpnas.log
backend = polling
maxretry = 6
bantime = 86400  # 1 day
findtime = 600   # 10 minutes

[openvpnas-https]
enabled = true
filter = openvpnas-https
logpath = /var/log/openvpnas.log
backend = polling
maxretry = 3
bantime = 86400  # 1 day
findtime = 600   # 10 minutes

You can check what these values do by searching up the fail2ban manuals and documentation, but most of these are easy to understand at first sight.

Once these files are in place, restart the fail2ban service by executing sudo systemctl restart fail2ban

If jails are properly configured you should see them by running the command sudo fail2ban-client status, this is my output:

Status
|- Number of jail:      3
`- Jail list:   openvpnas, openvpnas-https, sshd

You can further see if there is any banned IP on each jail by running the same command plus the name of the jail you want to check, for example sudo fail2ban-client status openvpnas-https, my output is the following:

Status for the jail: openvpnas-https
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/openvpnas.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

With all this, you should have two jails working, one for the OpenVPN Connect client and another for web access. You can try this by doing some failed login attempts, just make sure to do it from a network where you have a dynamic IP and it can be changed easily, otherwise you will be banned by as much time you specified on the bantime settings, which in the example above it is 1 day.