# How to create a VPN server with Microsoft Azure

## Introduction <a href="#introduction" id="introduction"></a>

[Microsoft Azure](https://azure.microsoft.com/en-us) is a cloud computing platform that provides a range of options for people looking to host their services on the cloud. Azure's extensive features and benefits make it a great choice to host a VPN server.

With Microsoft Azure, you can easily create and manage various virtual machines (VMs). Its global network of data centers ensures fast and reliable access to your services from anywhere in the world. Additionally, Azure has a flexible pricing model, offering a free subscription and allowing you to pay only for the resources you use once the free trial expires.

By using [Meshnet](https://nordvpn.com/meshnet/) in tandem with Azure, you can turn a simple VM into a secure VPN server without any advanced configuration.

This guide showcases how you can make a VPN server from a VM hosted by Microsoft Azure using Meshnet’s traffic routing feature.

{% hint style="info" %}
**Note**

Be aware that by setting up your own VPN server, you increase your online privacy but not to the same extent as when connecting to a regular VPN server provided by NordVPN, which follows a [strict no-logs policy](https://nordvpn.com/features/strict-no-logs-policy/).
{% endhint %}

## Before you begin <a href="#create-a-virtual-machine-on-microsoft-azure" id="create-a-virtual-machine-on-microsoft-azure"></a>

To follow this guide, you need an active Microsoft Azure account. You can sign up for free on the [Azure website](https://azure.microsoft.com/en-us/free/).

## Deploy a virtual machine on Microsoft Azure <a href="#create-a-virtual-machine-on-microsoft-azure" id="create-a-virtual-machine-on-microsoft-azure"></a>

First, you need to create a VM on Azure. While this guide focuses on setting up an Ubuntu VM, Azure allows you to create Windows VMs as well.

### Method 1: Creating a VM using Azure Portal

1. Log in to your [Azure account](https://portal.azure.com/).

2. From your Azure portal, click **Virtual machines**.

3. Click **Create** and select **Azure virtual machine**.

4. In the **Instance details** section, name your VM, select its region, and choose the operating system (for example, Ubuntu 22.04 LTS).<br>

   <figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FlMHrVY2iepiHcagiwPkR%2Fazure_instance_details.png?alt=media&#x26;token=27e1846a-2ac5-44b9-acaf-a7b9c03bd24a" alt="Creating the VM by entering its name, selecting the region, and the OS image."><figcaption></figcaption></figure>

5. Under **Administrator account**, select SSH public key authentication or create a password and choose the name of the administrator user of the VM.<br>

   <figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2F2rsI6Tbe5kDxEM6l22X2%2Fazure_admin_account.png?alt=media&#x26;token=aad536fb-896e-4fe9-b541-0e1d09372d94" alt="Selecting the SSH public key authentication type and the username for the administrator account."><figcaption></figcaption></figure>

6. Click **Review + create**.

7. Click **Create**.

{% hint style="info" %}
**Note**

If you chose the SSH key authentication type, you will receive a **Generate new key pair** message after clicking the **Create** button. Select the **Download private key and create resource** option to download the private key file.

![Clicking 'Download private key and create resource'.](https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2F16AWvoi2Bw9EGzKMamEm%2Fazure_ssh_keys.png?alt=media\&token=c1df2f47-aee1-4b9d-ab4f-f1690a58f59a)
{% endhint %}

### Method 2: Creating a VM using Azure CLI <a href="#access-the-virtual-machine" id="access-the-virtual-machine"></a>

Another method of managing Azure resources is the Azure Command-line interface (CLI). The Azure CLI allows you to create, deploy, and manage your Azure resources without using the internet browser. This method is highly beneficial for automation or server environments.

#### Install Azure CLI

To interact with Azure using CLI, you need to install the Azure CLI application on your device. Installation instructions for all compatible operating systems can be found on the [Azure CLI documentation page](https://learn.microsoft.com/en-us/cli/azure/).

* [Instructions for Windows](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli)
* [Instructions for macOS](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-macos)
* [Instructions for Linux](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt)

#### Log in to Azure

Upon installing Azure CLI, log in to your Azure account by taking these steps:

1. Open **PowerShell** (on Windows) or **Terminal** (on macOS and Linux).
2. Run the following command to start the login process:<br>

   ```
   az login
   ```

   &#x20;
3. Open the generated URL in an internet browser.
4. Log in to your Azure account.
5. Authenticate using the code provided in your CLI window.

#### Create your resource group

Azure uses resource groups to manage your VMs and their related resources. To create a resource group for your VPN server:

{% tabs %}
{% tab title="Windows" %}

1. Open **PowerShell**.

2. Define the environmental variables for your VM by running the following commands:<br>

   <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$env:RESOURCE_GROUP_NAME="&#x3C;groupName>"
   $env:LOCATION="&#x3C;region>"
   $env:VM_NAME="&#x3C;vmName>"
   $env:VM_IMAGE="&#x3C;imageName>"
   $env:ADMIN_USERNAME="&#x3C;username>"
   </code></pre>

   \
   Where:

   * `<groupName>` is a custom name for your resource group.
   * `<location>` is the region where your VM will be located.
     * You can check region names with the `az account list-locations -o table` command.
   * `<vmName>` is a custom name for your VM.
   * `<imageName>` is the name of the operating system image for your VM.
     * You can find image names for Ubuntu Server on the [Ubuntu documentation page](https://ubuntu.com/server/docs/find-ubuntu-images-on-azure).
   * `<username>` is the name of the user account for your VM.\
     \
     **Example**

     <figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FDImWjxR3apTpdBZeg5sG%2Fazure_win_env.png?alt=media&#x26;token=8117838e-2bd8-45af-b374-85bead7f4531" alt="Creating environmental variables for the virtual machine in PowerShell."><figcaption></figcaption></figure>

3. Create the resource group with this command:<br>

   <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">az group create --name $env:RESOURCE_GROUP_NAME --location $env:LOCATION
   </code></pre>

{% hint style="info" %}
**Note**

The environmental variables will be reset if you close the PowerShell window.
{% endhint %}
{% endtab %}

{% tab title="macOS and Linux" %}

1. Open **Terminal**.

2. Define the environmental variables for your VM by running the following commands:<br>

   ```bash
   export RESOURCE_GROUP_NAME=<groupName>
   export LOCATION=<region>
   export VM_NAME=<vmName>
   export VM_IMAGE=<imageName>
   export ADMIN_USERNAME=<user>
   ```

   Where:

   * `<groupName>` is a custom name for your resource group.
   * `<location>` is the region where your VM will be located.
     * You can check region names with the `az account list-locations -o table` command.
   * `<vmName>` is a custom name for your VM.
   * `<imageName>` is the name of the operating system image for your VM.
     * You can find image names for Ubuntu Server on the [Ubuntu documentation page](https://ubuntu.com/server/docs/find-ubuntu-images-on-azure).
   * `<username>` is the name of the user account for your VM.\
     \
     **Example**

     <figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FystB5WXNPWfJ3VzBD9rB%2Fazure_mac_env.png?alt=media&#x26;token=bb78111e-6bca-42c3-915e-0afa1249590e" alt="Creating environmental variables for the virtual machine in Terminal."><figcaption></figcaption></figure>

3. Create the resource group with this command:<br>

   ```bash
   az group create --name $RESOURCE_GROUP_NAME --location $LOCATION
   ```

   &#x20;

{% hint style="info" %}
**Note**

The environmental variables will be reset if you close the Terminal window.
{% endhint %}
{% endtab %}
{% endtabs %}

#### Deploy the VM

With the environment variables defined and the resource group created, you can deploy your VM in Azure.

{% tabs %}
{% tab title="Windows" %}
In **PowerShell**, execute the following command to create the virtual machine in Azure:

```powershell
az vm create `
  --resource-group $env:RESOURCE_GROUP_NAME `
  --name $env:VM_NAME `
  --image $env:VM_IMAGE `
  --admin-username $env:ADMIN_USERNAME `
  --generate-ssh-keys `
  --public-ip-sku Standard
```

This command automatically generates an SSH key pair for your VM and places it in the default SSH directory (`~/.ssh`). Once the VM is created, you will see an output of the VMs information.

<figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FcRAxy56g3wwJDyM1Xcky%2Fazure_win_deploy.png?alt=media&#x26;token=ca3a377b-e1be-44ea-b43e-48cb76e3d95c" alt="Information of the created virtual machine."><figcaption></figcaption></figure>
{% endtab %}

{% tab title="macOS and Linux" %}
In **Terminal**, execute the following command to create the virtual machine in Azure:

```bash
az vm create \
  --resource-group $RESOURCE_GROUP_NAME \
  --name $VM_NAME \
  --image $VM_IMAGE \
  --admin-username $ADMIN_USERNAME \
  --generate-ssh-keys \
  --public-ip-sku Standard
```

This command automatically generates an SSH key pair for your VM and places it in the default SSH directory (`~/.ssh`). Once the VM is created, you will see an output of the VMs information.

<figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2F3x5UhjgAJVxqEr3e5dur%2Fazure_mac_deploy.png?alt=media&#x26;token=fbf2c48e-d11d-41e2-ad97-d8f1436053ca" alt="Information of the created virtual machine."><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## Access the virtual machine <a href="#access-the-virtual-machine" id="access-the-virtual-machine"></a>

Once your VM is deployed, you can access it over SSH. The way to access the VM depends on which authentication method you chose while creating it.

{% tabs %}
{% tab title="SSH public key authentication" %}

### Changing permissions for the private key <a href="#changing-permissions-for-the-private-key" id="changing-permissions-for-the-private-key"></a>

To use the SSH key for authentication, you need to set the private key’s permissions to read-only.

#### Windows <a href="#windows" id="windows"></a>

1. Open **PowerShell**.
2. Run the following three commands to apply the permission change, substituting `</path/to/private/key>` with the path to the downloaded private key:<br>

   ```powershell
   icacls.exe </path/to/private/key> /reset
   icacls.exe </path/to/private/key> /grant:r "$($env:username):(r)"
   icacls.exe </path/to/private/key> /inheritance:r
   ```

   &#x20;

   **Example**

   <figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FqvzTwdmG78u3rp2CIcmj%2Fazure_win_chmod.png?alt=media&#x26;token=6d6fed84-ab63-49eb-843c-0a872ac3f0e3" alt="Running the given commands in PowerShell to change permissions for the SSH key file"><figcaption></figcaption></figure>

#### macOS and Linux <a href="#macos-and-linux" id="macos-and-linux"></a>

1. Open **Terminal**.
2. Run the following command to apply the permission change, substituting `</path/to/private/key>` with the path to the downloaded private key:<br>

   ```bash
   chmod 400 </path/to/private/key>
   ```

   &#x20;

   **Example**

   ```bash
   chmod 400 /Users/ventura/.ssh/UbuntuVPNServer_key.pem
   ```

### Connecting over SSH <a href="#connecting-over-ssh" id="connecting-over-ssh"></a>

1. Locate the public IP address of your VM.
   * You can find the public IP in the **Overview** section of the VM in your Azure Portal.\
     \
     ![Public IP address of the Azure VM.](https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FOolM35pArTwGlQELbBiW%2Fazure_public_ip.png?alt=media\&token=5fa9bff0-09a2-4110-8119-cfceacb22a24)

     &#x20;
   * If you created the VM using Azure CLI, you can run one of the following commands:\
     \
     For Windows in **PowerShell**:

     <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">az vm show -d -g $env:RESOURCE_GROUP_NAME -n $env:VM_NAME --query publicIps -o tsv
     </code></pre>

     \
     For macOS and Linux in **Terminal**:

     <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">az vm show -d -g $RESOURCE_GROUP_NAME -n $VM_NAME --query publicIps -o tsv
     </code></pre>

2. Run the `ssh -i </path/to/private/key> <username>@<server>` command in PowerShell or Terminal, where:
   * `</path/to/private/key>` is the location of the downloaded SSH private key.
   * `<username>` is the name of the administrator user of the VM.
   * `<server>` is the VM’s public IP address.<br>

     **Example**

     <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">ssh -i C:\Users\secretmeerkat\.ssh\UbuntuVPNServer_key.pem meerkat@20.82.123.153
     </code></pre>

     &#x20;

3. Type in `yes` and press **Enter** to confirm the connection.

You should now be connected to your Azure VM.
{% endtab %}

{% tab title="SSH password authentication" %}

1. Locate the public IP address of your VM. It can be found in the **Overview** section of the VM in your Azure Portal.\
   \
   ![Public IP address of the Azure VM.](https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FOolM35pArTwGlQELbBiW%2Fazure_public_ip.png?alt=media\&token=5fa9bff0-09a2-4110-8119-cfceacb22a24)

   &#x20;
2. Open **Terminal** (on Linux and macOS) or **Command Prompt** (on Windows).
3. Run the `ssh <username>@<server>` command, where:
   * `<username>` is the name of the administrator user of the VM.
   * `<server>` is the VM’s public IP address.\
     \
     **Example**

     ```bash
     ssh meerkat@20.82.123.153
     ```

     &#x20;
4. Enter your authentication password.
5. Type in `yes` and press **Enter** to confirm the connection.

You should now be connected to your Azure VM.
{% endtab %}
{% endtabs %}

## Install NordVPN on the virtual machine <a href="#install-nordvpn-on-the-virtual-machine" id="install-nordvpn-on-the-virtual-machine"></a>

Follow these steps to install NordVPN on your virtual server:

1. Download and install the NordVPN Linux client by running the command below.

   &#x20;

   <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">sh &#x3C;(wget -qO - https://downloads.nordcdn.com/apps/linux/install.sh)
   </code></pre>

2. Log in to your NordVPN account.

### Log in to NordVPN <a href="#log-in-to-nordvpn" id="log-in-to-nordvpn"></a>

You can log in to your NordVPN account without the use of a graphical user interface (GUI) in two ways:

* By running the `nordvpn login` command with the `--token` flag
* By running the `nordvpn login` command with the `--callback` flag

{% tabs %}
{% tab title="Log in using a token" %}

1. On any device, log in to your [Nord Account](https://my.ndaccount.com/) dashboard.&#x20;

2. Under **NordVPN Meshnet free**, select **View details**.<br>

   <div align="left"><figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2Fsn49VgeZ6NMI13J7Ki1N%2Ftoken_generate0.png?alt=media&#x26;token=a773ba2c-27a9-4e88-b7bf-c4fe60cd2d42" alt="Clicking the &#x27;View details&#x27; button under NordVPN Meshnet free." width="563"><figcaption></figcaption></figure></div>

3. Scroll down until you see **Access token**.

4. Select the **Generate new token** button.<br>

   <div align="left"><figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2F4PoIcgMGswTyRI8d8b0i%2Ftoken_generate.png?alt=media&#x26;token=c0502a41-fdea-4212-bb19-5e1eb19638ba" alt="Clicking &#x27;Generate new token&#x27;" width="563"><figcaption></figcaption></figure></div>

5. In the dialog that appears, choose either a token that expires in 30 days or one that never expires, and then select **Generate token**.<br>

   <div align="left"><figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2Fw2MaEvL5cIVshJPYkTbG%2Ftoken_generate2.png?alt=media&#x26;token=82907065-348b-4f0b-bee2-9ea49245a74a" alt="Selecting the token expiration date." width="563"><figcaption></figcaption></figure></div>

6. Select **Copy and close**.

7. On your VM, run the `nordvpn login --token <your_token>` command, replacing `<your_token>` with the copied token.\
   \
   **Example**

   <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">nordvpn login --token 3fe460cefb8dcf1478c92e45908cec9f9bdbadf7a456a6dfb35dc2c58ee39d5b
   </code></pre>

You should now see a welcome message.

{% hint style="success" %}
**Tip**

To preserve your token when logging out of the NordVPN app, use the `nordvpn logout --persist-token` command. Otherwise, your token will be revoked.&#x20;
{% endhint %}
{% endtab %}

{% tab title="Log in using a URL" %}

1. Run the following command:<br>

   ```
   nordvpn login
   ```

2. Open the provided link on any device in your browser.

3. Complete the login procedure.

4. Right-click the **Continue** button and select **Copy link address**.

5. Run the `nordvpn login --callback "<URL>"` command, replacing `<URL>` with the previously copied link address.\
   \
   **Example**

   <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">nordvpn login --callback "nordvpn://login?action=login&#x26;exchange_token=MGFlY2E1NmE4YjM2NDM4NjUzN2VjOWIzYWM3ZTU3ZDliNDdiNzRjZTMwMjE5YjkzZTNhNTI3ZWZlOTIwMGJlOQ%3D%3D&#x26;status=done"
   </code></pre>

You should now see a welcome message.
{% endtab %}
{% endtabs %}

## Enable Meshnet <a href="#enable-meshnet" id="enable-meshnet"></a>

Upon logging in, you can [enable Meshnet on Linux](https://meshnet.nordvpn.com/getting-started/how-to-start-using-meshnet/using-meshnet-on-linux#enable-meshnet-on-linux) by typing this command:

```bash
nordvpn set meshnet on
```

To check your server’s Nord name and the Meshnet IP address, enter the following command:

```bash
nordvpn meshnet peer list
```

**Example**

<figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FniP7M9kbf8WPm6WEwDVW%2Fazure_mesh_list.png?alt=media&#x26;token=fce51d34-5cd2-4507-b202-59c962468505" alt="Enabling Meshnet and checking the Nord name and Meshnet IP of the VM."><figcaption></figcaption></figure>

You will also see all of your Meshnet peer devices with their [corresponding permissions](https://meshnet.nordvpn.com/~/changes/otYJMg7qFzDy0nWn86iM/features/explaining-permissions).

## Connect to your VPN server <a href="#connect-to-your-vpn-server" id="connect-to-your-vpn-server"></a>

With Meshnet enabled, your peer devices should now be able to connect to the server. To connect, start routing traffic from a client device through the VM, which you can find in the list of your Meshnet peer devices.

<figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FsLtNmGa8OPzc9PSpst08%2Fazure_mesh_route.png?alt=media&#x26;token=7686174c-9e12-4b6d-add5-60a8cc11b0a9" alt="Clicking &#x27;Route all traffic&#x27;"><figcaption></figcaption></figure>

For specific instructions, see the [Routing traffic in Meshnet](https://meshnet.nordvpn.com/~/changes/otYJMg7qFzDy0nWn86iM/features/routing-traffic-in-meshnet#see-also) article.

[Your IP address](https://nordvpn.com/what-is-my-ip/) should now be the same as the virtual machine’s. This way, your real public IP address is protected, and the websites you visit will see the location of your VPN server instead of your actual device.

<figure><img src="https://3559400189-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0cTezbT2vN0lurEio8Z5%2Fuploads%2FgPbtEO2li6MtFPpoxSrU%2Fazure_check_ip.png?alt=media&#x26;token=db043e0d-6f52-474e-8004-2d3184b0ab2d" alt="Checking the new IP address after connecting to the VPN server."><figcaption></figcaption></figure>
