DEV Community

iapilgrim
iapilgrim

Posted on

Phase 1 - Building a Multi-Region Backend on Azure (Before Azure Front Door)

When designing global applications, the first step isn’t configuring global routing.

It’s building healthy, regionally distributed backends.

In this tutorial, we’ll deploy:

  • Two Azure App Services
  • In two different regions
  • With region-specific responses
  • Fully validated and tested

This sets the foundation for later integrating Azure Front Door.


🏗 Architecture Overview

We will deploy:

  • Resource Group: rg-afd-lab
  • Region 1: East US 2
  • Region 2: Southeast Asia
  • Linux App Service Plans (B1)
  • Node.js web apps returning region-specific messages

Architecture Diagram (PlantUML)

At this stage, traffic hits each regional app directly via *.azurewebsites.net.


🚀 Step 1: Create Resource Group

RG="rg-afd-lab"
LOCATION1="eastus2"
LOCATION2="southeastasia"

az group create \
  --name $RG \
  --location $LOCATION1
Enter fullscreen mode Exit fullscreen mode

🧱 Step 2: Create App Service Plans

SUFFIX=$RANDOM

PLAN1="plan-eastus2-$SUFFIX"
PLAN2="plan-sea-$SUFFIX"

az appservice plan create \
  --name $PLAN1 \
  --resource-group $RG \
  --location $LOCATION1 \
  --sku B1 \
  --is-linux

az appservice plan create \
  --name $PLAN2 \
  --resource-group $RG \
  --location $LOCATION2 \
  --sku B1 \
  --is-linux
Enter fullscreen mode Exit fullscreen mode

Each region gets its own compute plan.


🌐 Step 3: Create Web Apps

Check available Node runtimes:

az webapp list-runtimes --os-type linux
Enter fullscreen mode Exit fullscreen mode

Then create apps:

APP1="app-eastus2-$SUFFIX"
APP2="app-sea-$SUFFIX"

az webapp create \
  --name $APP1 \
  --resource-group $RG \
  --plan $PLAN1 \
  --runtime "NODE|20-lts"

az webapp create \
  --name $APP2 \
  --resource-group $RG \
  --plan $PLAN2 \
  --runtime "NODE|20-lts"
Enter fullscreen mode Exit fullscreen mode

📝 Step 4: Deploy Node.js App (Correctly)

Here’s the important part most tutorials skip.

Create server.js

const express = require('express');
const app = express();
const port = process.env.PORT || 8080;

app.get('/', (req, res) => {
  res.send('Hello from East US 2 🚀');
});

app.listen(port, () => {
  console.log('Server running on port', port);
});
Enter fullscreen mode Exit fullscreen mode

Create package.json

{
  "name": "regional-app",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}
Enter fullscreen mode Exit fullscreen mode

⚠️ Critical Step: Enable Build During Deployment

If you skip this, Azure won’t run npm install.

az webapp config appsettings set \
  --resource-group $RG \
  --name $APP1 \
  --settings SCM_DO_BUILD_DURING_DEPLOYMENT=true
Enter fullscreen mode Exit fullscreen mode

Repeat for the second app.


📦 Zip Deploy

zip -r app.zip .

az webapp deploy \
  --resource-group $RG \
  --name $APP1 \
  --src-path app.zip \
  --type zip
Enter fullscreen mode Exit fullscreen mode

Repeat for second app (with modified message).


🔍 Validate Deployment

Check logs:

az webapp log tail \
  --resource-group $RG \
  --name $APP1
Enter fullscreen mode Exit fullscreen mode

You should see:

Running 'npm install'
Server running on port 8080
Enter fullscreen mode Exit fullscreen mode

🧪 Testing & Validation Script

Create validate.sh:

#!/bin/bash

RG="rg-afd-lab"
APPS=$(az webapp list --resource-group $RG --query "[].name" -o tsv)

for APP in $APPS
do
  URL="https://$APP.azurewebsites.net"
  echo "Testing $URL"
  curl -s -o /dev/null -w "HTTP %{http_code} - %{time_total}s\n" $URL
done
Enter fullscreen mode Exit fullscreen mode

Run:

bash validate.sh
Enter fullscreen mode Exit fullscreen mode

🔎 What We Learned

This phase uncovered an important Azure behavior:

  • Zip deploy does NOT automatically install dependencies
  • You must enable SCM_DO_BUILD_DURING_DEPLOYMENT
  • Without it → app crashes with:
  Error: Cannot find module 'express'
Enter fullscreen mode Exit fullscreen mode

Understanding this prevents misdiagnosing issues later when integrating Azure Front Door.


🧠 Why Phase 1 Matters

Before adding global routing, ensure:

  • Each origin is independently healthy
  • Correct content is served
  • Latency baseline is measured
  • Logs are working
  • Health endpoints are functional

Skipping origin validation is the #1 cause of global load balancing failures.


🏁 What’s Next?

In Phase 2, we’ll:

  • Deploy Azure Front Door
  • Configure origin groups
  • Enable health probes
  • Test failover between regions
  • Add WAF protection

We’re moving from regional compute → to global edge architecture.

Top comments (0)