# Azure Virtual Machine

{% hint style="info" %}
**DEPRECATION WARNING:** On [August 31, 2024](https://learn.microsoft.com/en-us/azure/virtual-machines/av1-series-retirement), Azure will retire Basic and Standard A-series virtual machines (VMs). Before that date, migrate your workloads to Av2-series VMs, which provide more memory per vCPU and faster storage on solid-state drives (SSDs).
{% endhint %}

You will now setup the **API Server** by using the Azure Container Instances setup.

* An On-Premise Enterprise license is required to complete this installation
* In the left menu, click on the **Virtual Machines** menu item, and then press **+ Create** button.
* In the dropdown select **Azure Virtual machine**.
* Click the link that says **See all images** underneath the Image field.
* In the see all images, type the word **Docker**, and then click on the **Docker on Ubuntu Server**
* You will now need to select your Instance for your machine. **Please note** that Azure does not make all VM sizes available in every region so select region and VM size carefully. We recommend the following.&#x20;
  * **Test Environments** - A1\_v2 Standard
  * **Production Environments** - A6 Standard

<figure><img src="https://1673552148-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FnykhDiTLJ5YSMDHVPTWT%2FScreenshot%202022-12-29%20110055.png?alt=media&#x26;token=880bcf86-5842-4cb7-bde4-7368f6d49e98" alt=""><figcaption></figcaption></figure>

* Next, will we setup a root user account credentials for SSH access.

<figure><img src="https://1673552148-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FK4XdeVJQ4F50UURc3IWt%2Fssh.png?alt=media&#x26;token=216536f9-695b-4fea-9654-d7ba5f6ecb54" alt=""><figcaption></figcaption></figure>

* At the bottom left of the page there will be a **Review + create** button. Click on this button to launch the Virtual Machine.

### Add Inbound Port Rules

* You will now wait for this machine to be created, and once it is, we will need to open up the HTTP port 80 on this machine.
* To do this, you will click on this machine in the **Virtual Machines** section, and then click on **Endpoints** and then click **+ Add**
* We will now configure the following endpoint.
  * Name: HTTP
  * Protocol: TCP
  * Public Port: 80
  * Private Port: 80
  * Press **OK**
* Now that we have an HTTP port open on this machine, we can now SSH into the machine using your computers Terminal.

### Login into Azure VM via SSH

* To login to this machine, you will first need to get the **Public IP Address** by clicking on the **Overview** tab.
* You will then see the **Public IP Address**, which you will then need to copy.

<figure><img src="https://1673552148-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FFj2D17vZAjEciEmWfYme%2FImage%202022-12-29%2011.05.59.png?alt=media&#x26;token=88abcc27-67dc-44f4-80bf-95ce252a68d1" alt=""><figcaption></figcaption></figure>

* Next, you will open up a Terminal on your local computer and type the following.

  ```
  ssh [user]@[publicIpAddress]
  ```

  Make sure you replace `[user]` with the username that you used to create the virtual machine, and the `[publicIpAddress]` with the name you just copied.
* You will then be prompted to enter your password which you will enter the same password you provided when you created the virtual machine.

### Pull Docker Containers

* You should then see the console of the Ubuntu virtual machine. You will now download the Docker containers. While it is recommended to put the **API Server** and the **PDF Server** on separate Virtual machines, for this example, we will just download both of them on the same machine.
* ```
  docker pull formio/formio-enterprise:$IMAGE_VERSION
  docker pull formio/pdf-server:$IMAGE_VERSION
  ```

### Create Docker Network

* You will now need to create an “internal” network that you will use to connect all the internal docker containers together.

  ```
  docker network create formio
  ```

### Start API Server

* Next we will spin up our **API Server** using the following command.

  ```bash
  ## Start Form.io API Server
  docker run -d \
    -e "LICENSE_KEY=$YOURLICENSE" \
    -e "MONGO=mongodb://formio:[PASSWORD]@formio.documents.azure.com:10255/formio?ssl=true&replicaSet=globaldb" \
    -e "PORT=3000" \
    -e "PORTAL_ENABLED=true" \
    -e "ADMIN_EMAIL=admin@example.com" \
    -e "ADMIN_PASS=CHANGEME" \
    -e "DB_SECRET=CHANGEME" \
    -e "JWT_SECRET=CHANGEME" \
    -e "PDF_SERVER=http://pdf-server:4005" \
    --restart unless-stopped \
    --network formio \
    --link pdf-server:pdf-server \
    --name formio-server \
    -p 3000:3000 \
    formio/formio-enterprise:$IMAGE_VERSION
  ```

  You will need to make sure that you change out the values for ADMIN\_PASS, JWT\_SECRET, DB\_SECRET, MONGO to be the values that you saved in your editor during the setup process.
* After this runs for a minute, you should then be able to type the following to check on the status.

<figure><img src="https://help.form.io/assets/img/integrations/azure/api-server-running.png" alt=""><figcaption></figcaption></figure>

### Start PDF Server

* Next, we will deploy our **PDF server** to point to both the API server + Minio File Server.

  ```bash
  ## Start Form.io PDF Server
  docker run -itd \
    -e "LICENSE_KEY=$YOURLICENSE" \
    -e "MONGO=mongodb://formio:[PASSWORD]@formio.documents.azure.com:10255/formio?ssl=true&replicaSet=globaldb" \
    -e "FORMIO_AZURE_CONNECTION_STRING=$YOURCONNECTIONSTRING" \
    -e "FORMIO_AZURE_CONTAINER=pdfs" \
    --network formio \
    --restart unless-stopped \
    --name pdf-server \
    -p 4005:4005 \
    formio/pdf-server:$IMAGE_VERSION
  ```
* Once this is running, you should be able to type the following.

  ```
  docker logs pdf-server
  ```

  and then see the following.

<div align="center"><figure><img src="https://help.form.io/assets/img/integrations/azure/files-running.png" alt="" width="563"><figcaption></figcaption></figure></div>

* You should now have two public ports accessible on this machine.
  * API Server: Port 3000
  * PDF Server: Port 4005
* We can now make all of this fall under a single HTTP port by configuring an NGINX proxy on our server.

### NGINX Setup

In order to bring all of these locally hosted servers into a single HTTP interface, we can use NGINX to sit in front of these servers.

To setup this configuration, please go through the following steps.

* Install NGINX using the following command.

  ```
  sudo apt-get update
  sudo apt-get install nginx
  ```
* We can check to ensure that we have NGINX running with the following command.

  ```
  systemctl status nginx
  ```
* We now need to edit the nginx.conf file to redirect HTTP traffic to the internal servers.

  ```
  sudo nano /etc/nginx/sites-available/formio
  ```
* Put the following contents in that file.

  ```
  server {
    listen 80;
    server_name  ~^(www\.)?(.+)$;
    client_max_body_size 20M;
       
    ############# Use the following for SSL ################
    # listen               443 ssl;
    # ssl_certificate      /usr/local/etc/nginx/nginx.crt;
    # ssl_certificate_key  /usr/local/etc/nginx/nginx.key;
    ########################################################
       
    location / {
      proxy_set_header    Host $host;
      proxy_set_header    X-Real-IP $remote_addr;
      proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header    X-Forwarded-Proto $scheme;
      proxy_pass          http://localhost:3000;
      proxy_read_timeout  90;
      proxy_redirect      http://localhost:3000 https://$host;
    }
     
    location /pdf/ {
      rewrite ^/pdf/(.*)$ /$1 break;
      proxy_set_header    Host $host;
      proxy_set_header    X-Real-IP $remote_addr;
      proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header    X-Forwarded-Proto $scheme;
      proxy_pass          http://localhost:4005;
      proxy_read_timeout  90;
      proxy_redirect      http://localhost:4005 https://$host;
    }
  }
     
  server {
    listen 80;
    server_name  ~^minio.(.+)$;
    client_max_body_size 20M;
       
    ############# Use the following for SSL ################
    # listen               443 ssl;
    # ssl_certificate      /usr/local/etc/nginx/nginx.crt;
    # ssl_certificate_key  /usr/local/etc/nginx/nginx.key;
    ########################################################
       
    location / {
      proxy_buffering off;
      proxy_set_header Host $http_host;
      proxy_pass http://localhost:9000;
    }
  }
  ```

  Note, for this configuration to work with Minio, you will need to create a subdomain @ <http://minio.yourserver.com> that points to this server. Minio does not support being hosted outside of the root domain.
* Now save that file, and then switch this out for the `default` server

  ```
  sudo rm /etc/nginx/sites-enabled/default
  sudo ln -s /etc/nginx/sites-available/formio /etc/nginx/sites-enabled/default
  sudo systemctl restart nginx
  ```
* We can now test that we have both an API server and a PDF Server running by going to the following URLs in our Browser.
  * <http://formio-server-6ht0yqu8.cloudapp.net/status> (should show the API Server status)
  * <http://formio-server-6ht0yqu8.cloudapp.net/pdf/> (should show the PDF Server status)
