Building a Production-Grade Web Application on Azure: Application Gateway + VM Scale Sets + Monitoring

In today’s cloud-first world, deploying a simple web application isn’t enough. Modern applications need to be secure, scalable, and resilient. In this hands-on guide, we’ll build a production-grade web infrastructure on Microsoft Azure that automatically scales with demand, distributes traffic intelligently, and provides complete visibility into your application’s health.

This project is the fifth of the ten in preparing for my AZ-104: Microsoft Azure Administrator certification and also to understand how enterprise-grade applications are deployed in the cloud.

What We’ll Build

By the end of this tutorial, we’ll have deployed:

  • Azure Application Gateway – A Layer 7 load balancer that distributes HTTPS traffic
  • Virtual Machine Scale Set (VMSS) – Auto-scaling web servers that grow and shrink based on demand
  • Azure Monitor – Complete observability into your application’s performance
  • Secure Networking – Properly segmented subnets with Network Security Groups

Prerequisites

Before starting, we’ll need:

  • An active Azure subscription (free trial works fine)
  • Basic understanding of networking concepts (IP addresses, subnets)
  • Familiarity with the Azure Portal
  • A terminal or command prompt for generating SSL certificates
  • OpenSSL installed on your machine

Estimated Time: 90-120 minutes
Cost: ~$5-10 if you delete resources after testing

Understanding the Architecture

Before diving into the implementation, let’s understand what we’re building and why each component matters.

The Big Picture

Imagine you’re running an e-commerce website. During normal hours, you might need just one or two servers. But during a flash sale, traffic could spike 10x. This architecture automatically handles those scenarios:

  1. Users connect to your application via HTTPS (secure)
  2. Application Gateway receives the traffic and terminates SSL (decrypts HTTPS)
  3. Traffic is distributed across multiple backend web servers
  4. VM Scale Set automatically adds more servers when CPU usage is high
  5. Azure Monitor tracks everything and alerts you to issues

Key Components Explained

Application Gateway (Layer 7 Load Balancer)
Think of this as your application’s intelligent front door. Unlike a basic load balancer that just distributes traffic, Application Gateway can make routing decisions based on URL paths, cookies, and more. It also handles SSL/TLS termination, meaning your backend servers don’t need to worry about encryption overhead.

Virtual Machine Scale Set (VMSS)
Instead of manually creating and managing individual VMs, a scale set lets you define a template and Azure automatically creates identical instances. When load increases, Azure spins up more VMs. When load decreases, it removes them. You pay only for what you use.

Network Segmentation
We’ll create separate subnets for frontend (Application Gateway) and backend (VMSS) components. This follows the security principle of “least privilege” – each component only has access to what it needs.

Azure Monitor & Log Analytics
Your application’s nervous system. It collects metrics, logs, and traces from all components, giving you visibility into performance, errors, and usage patterns.

Phase 1: Setting Up the Foundation

I have shown this part already in my other write ups, but I’ll add the steps here and add some little extra details

Step 1: Create Your Resource Group

Every Azure project starts with a resource group – a logical container for all related resources.

  1. Sign in to the Azure Portal
  2. Click “Create a resource” or search for “Resource groups”
  3. Click “+ Create”
  4. Configure:
    • Subscription: Select your subscription
    • Resource group name: Project5-RG
    • Region: Choose a region close to you (e.g., East US, West Europe)
  5. Click “Review + create” then “Create”

Why this matters: As earlier stated before, grouping resources makes management easier. When you’re done testing, you can delete the entire resource group to remove everything at once and stop charges.

Step 2: Create the Virtual Network

A Virtual Network (VNet) is your private network in Azure. We’ll create one with two subnets.

  1. In the Azure Portal, search for “Virtual networks”
  2. Click “+ Create”
  3. Basics tab:
    • Resource group: Select Project5-RG
    • Name: Project5-VNet
    • Region: Same as your resource group
  4. Click “Next: IP Addresses”
  5. IP Addresses tab:
    • Ensure the address space is 10.0.0.0/16 (this gives you 65,536 IP addresses)
    • Delete the default subnet if present
    • Click “+ Add subnet”
      • Subnet name: frontend-subnet
      • Subnet address range: 10.0.1.0/24 (256 addresses)
      • Click “Add”
    • Click “+ Add subnet” again
      • Subnet name: backend-subnet
      • Subnet address range: 10.0.2.0/24
      • Click “Add”
  6. Click “Review + create” then “Create”

Understanding IP Addresses:

  • 10.0.0.0/16 means the first 16 bits are fixed (10.0), leaving 16 bits for your use
  • 10.0.1.0/24 means the first 24 bits are fixed (10.0.1), leaving 8 bits (256 addresses)
  • Azure reserves 5 addresses in each subnet for internal use

Phase 2: Deploying the Virtual Machine Scale Set

The scale set will host your web application across multiple identical VMs.

Step 3: Create the VM Scale Set

  1. Search for “Virtual machine scale sets” in the Azure Portal
  2. Click “+ Create”
  3. Basics tab:
    • Resource group: Project5-RG
    • Scale set name: WebApp-VMSS
    • Availabilty zone: check all the Az boxes
    • Region: Same as before
    • Orchestration mode: Select “Uniform” (for simplified management)
    • Image: Select “Ubuntu Server 22.04 LTS”
    • Size: Select “Standard_B2s” (2 vCPUs, 4GB RAM – economical for testing)
    • Authentication:
      • Choose “Password” for simplicity
      • Username: azureuser
      • Password: Create a strong password and save it securely

4. Scaling tab: select Autoscaling: Scaling based on a CPU metric, on any schedule.

  • Click “Configure”
  • Add a scaling condition
  • Default instance count : 2
  • Minimum number of VMs: 2
  • Maximum number of VMs: 4
  • Under “Scale out”:
    • CPU threshold: 60%
    • Duration: 10 minutes
    • Increase instance count by: 1
  • Under “Scale in”:
    • CPU threshold: 20%
    • Duration: 10 minutes
    • Decrease instance count by: 1

Spot tab: This session can be turned on to save money, it givesAzure capacity at a discounted rate with Azure Spot, it’s great for workloads that can tolerate interruptions and downtime when capacity is needed elsewhere.

5. Disks tab:

  • Leave defaults (Standard SSD)

6. Networking tab:

  • Virtual network: Select Project5-VNet
  • Subnet: Select backend-subnet
  • Public IP address: Select “Disabled” (Application Gateway will be public-facing)
  • NIC network security group: Select “Basic”
  • Click “Create new” for the NSG
    • Name: VMSS-NSG
    • Add an inbound rule:
      • Source: 10.0.1.0/24 (frontend subnet)
      • Source port ranges: *
      • Destination: Any
      • Destination port ranges: 80
      • Protocol: TCP
      • Action: Allow
      • Priority: 100
      • Name: AllowHTTPFromAppGateway
    • Click “OK”

7. Management tab:

  • Enable application health monitoring: Check this box
  • Automatic repair policy: Enable it
  • Leave other defaults

8 . Advanced tab:

  • Scroll down to “Custom data” section
  • Paste this script (it installs Nginx and creates a simple webpage):
#!/bin/bash
sudo apt update -y
sudo apt install nginx -y
echo "<html><body><h1>Hello from VMSS Instance: $(hostname)</h1><p>Server: $(hostname -I)</p></body></html>" > /var/www/html/index.html
systemctl restart nginx
systemctl enable nginx
  1. Click “Review + create” then “Create”

What we just did:

  • Azure is creating a template for your VMs
  • It will launch 2 identical instances immediately
  • Each instance will automatically run the bash script, installing Nginx and creating a custom homepage
  • The scale set will monitor CPU usage and add/remove instances automatically

Wait for 5-10 minutes for deployment to complete.

Phase 3: Creating the SSL Certificate

Application Gateway requires an SSL certificate for HTTPS. We’ll create a self-signed certificate for testing.

Step 4: Generate SSL Certificate

On Windows (using Git Bash or WSL):

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout myCert.key -out myCert.crt -subj "//CN=myappgatewaydemo.local"

Because we plan to use this certificate for Azure Application Gateway, we will have to convert it to PFX format with:

openssl pkcs12 -export -out myCert.pfx -inkey myCert.key -in myCert.crt -password pass:YourStrongPassword123!

Replace YourStrongPassword123! with your password

On Mac/Linux:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout myCert.key -out myCert.crt \
-subj "/CN=myappgatewaydemo.local"

Then combine the key and certificate into a .pfx file:

openssl pkcs12 -export -out myCert.pfx -inkey myCert.key -in myCert.crt

You’ll be prompted for a password – create one and remember it (you’ll need it in the next step).

What these commands do:

  • req -x509 creates a self-signed certificate
  • -nodes means no password on the private key file
  • -days 365 makes it valid for one year
  • -newkey rsa:2048 generates a 2048-bit RSA key
  • pkcs12 -export combines key and certificate into a single .pfx file

Important: For production, you’d use a certificate from a trusted Certificate Authority (CA) like Let’s Encrypt, DigiCert, or Azure’s own certificate service.

Phase 4: Deploying Application Gateway

Now we’ll create the Application Gateway that sits in front of our VMs.

Step 5: Create Application Gateway

  1. Search for “Application gateways” in the Azure Portal
  2. Click “+ Create”
  3. Basics tab:
    • Resource group: Project5-RG
    • Application gateway name: Project5-AppGW
    • Region: Same as before
    • Tier: Select “Standard V2”
    • Autoscaling: Enable it
      • Minimum scale units: 1
      • Maximum scale units: 3
    • Virtual network: Select Project5-VNet
    • Subnet: Select frontend-subnet
  4. Frontends tab:
    • Frontend IP address type: Public
    • Public IP address: Click “Add new”
      • Name: AppGW-PublicIP
      • SKU: Standard
      • Click “OK”

NB: Here I used the backend subnet because I used the frontend subnet for the VMMS: realised this late, but you can go ahead with what you have.

5. Backends tab:

  • Click “+ Add a backend pool”
    • Name: VMSS-BackendPool
    • Target type: Select “Virtual machine scale set”
    • Target: Select your WebApp-VMSS
    • Click “Add”
  1. Configuration tab:
    • Click “+ Add a routing rule”Rule name: HTTPSRule
    Listener tab:
    • Listener name: HTTPS-Listener
    • Frontend IP: Public
    • Protocol: HTTPS
    • Port: 443
    • Listener type: Basic
    • Certificate: Click “Upload a certificate”
      • Cert name: SelfSignedCert
      • PFX certificate file: Upload your myCert.pfx
      • Password: Enter the password you created earlier
      Error page url: Leave default
    Backend targets tab:
    • Target type: Backend pool
    • Backend target: Select VMSS-BackendPool
    • Backend settings: Click “Add new”
      • Backend settings name: HTTP-BackendSettings
      • Backend protocol: HTTP
      • Backend port: 80
      • Cookie-based affinity: Disable
      • Request time-out: 20 seconds
      • Click “Add”
    • Click “Add” to save the routing rule
  2. Tags tab: (Optional) Add tags like Environment: Testing
  3. Click “Review + create” then “Create”

Wait for about 10-15 minutes. Application Gateway deployment takes longer because it’s provisioning load balancer infrastructure.

Phase 5: Monitoring and Logging

Step 6: Create Log Analytics Workspace

  1. Search for “Log Analytics workspaces”
  2. Click “+ Create”
  3. Configure:
    • Resource group: Project5-RG
    • Name: Project5-Workspace
    • Region: Same as before
  4. Click “Review + create” then “Create”

Step 7: Enable Diagnostics for Application Gateway

  1. Navigate to your Application Gateway (Project5-AppGW)
  2. In the left menu, under Monitoring, click “Diagnostic settings”
  3. Click “+ Add diagnostic setting”
  4. Configure:
    • Diagnostic setting name: AppGW-Diagnostics
    • Logs: Check all categories
      • ApplicationGatewayAccessLog
      • ApplicationGatewayPerformanceLog
      • ApplicationGatewayFirewallLog
    • Metrics: Check AllMetrics
    • Destination details: Check “Send to Log Analytics workspace”
    • Select your Project5-Workspace
  5. Click “Save”

Phase 6: Testing Your Deployment

Step 9: Access Your Application

  1. Navigate to your Application Gateway
  2. On the Overview page, copy the Frontend public IP address
  3. Open a web browser
  4. Navigate to: https://<your-public-ip>

You’ll see a security warning because we’re using a self-signed certificate. This is expected for testing. Click “Advanced” and “Proceed” (exact wording varies by browser).

What you should see:
A webpage displaying: Hello from VMSS Instance: WebApp-VMSS_X with the instance name and IP address.

Refresh the page multiple times. You should see the hostname change, showing that Application Gateway is distributing traffic across different VM instances.

If you observe, the browser shows “Not secure” because we created our own SSL certificate, and browsers only trust certificates issued by official organizations called Certificate Authorities. The connection is still encrypted and working perfectly – it’s just that the browser is being cautious because it can’t verify who issued the certificate. You can Learn more about Certificate Authority Here

Trobleshooting

If you see a 502 error, it most likely will result from the NSG rules, but if you follow the steps from above, you should not have a problem with security rules , but one error I faced is with the instances showing “LatestModelApplied: False“, meaning the Nginx installation script didn’t run completely as expected and the script below fixes that on you azure cli or Azure Cloudshell.

az vmss update-instances \ --resource-group <ResourceGroup> \ --name WebApp-VMSS \ --instance-ids "*"

Change <ResourceGroup> to the name of your resource group.

Step 10: Test Auto-Scaling

To see auto-scaling in action, we need to generate load:

  1. SSH into one of your VMSS instances (you’ll need to set up a bastion host or add a temporary NSG rule allowing SSH)
  2. Or use Serial Console and run:
# Install Apache Bench
sudo apt install apache2-utils -y

# Generate load - 10,000 requests with 100 concurrent connections
ab -n 10000 -c 100 https://<your-public-ip>/
  1. Navigate to VM Scale Set → Instances
  2. After a few minutes, you should see the instance count increase from 2 to 3 as CPU usage exceeds 60%

Step 11: Monitor Performance

  1. Go to Azure Monitor from the home page
  2. Click “Metrics”
  3. Select your resource group: Project5-RG
  4. Select Application Gateway
  5. Add metrics:
    • Total Requests
    • Backend Response Status
    • Healthy/Unhealthy Host Count

We’ll see real-time graphs of your application’s performance.

Conclusion

We’ve built a production-grade, auto-scaling web infrastructure on Azure. This isn’t just a learning exercise, this is the same architectural pattern used by companies running mission-critical applications.

We’ve learned how to:

  • Design secure network topologies with proper segmentation
  • Deploy highly available applications using VM Scale Sets
  • Implement Layer 7 load balancing with SSL termination
  • Configure auto-scaling based on performance metrics
  • Set up comprehensive monitoring and logging

These skills are directly applicable to real-world Azure administration and will serve well in the AZ-104 exam and beyond.

Leave a comment

I’m Adedeji

I am a Microsoft MVP. Welcome to my blog. On this blog, I will be sharing my knowledge, experience and career journey. I hope you enjoy.

Let’s connect