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
🧱 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
Each region gets its own compute plan.
🌐 Step 3: Create Web Apps
Check available Node runtimes:
az webapp list-runtimes --os-type linux
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"
📝 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);
});
Create package.json
{
"name": "regional-app",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2"
}
}
⚠️ 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
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
Repeat for second app (with modified message).
🔍 Validate Deployment
Check logs:
az webapp log tail \
--resource-group $RG \
--name $APP1
You should see:
Running 'npm install'
Server running on port 8080
🧪 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
Run:
bash validate.sh
🔎 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'
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)