Azure API Management — Multi-Region APIM with Front Door
Active-Active Gateway, Latency Routing, and Automatic Failover
Introduction
For global applications requiring high availability and low latency, deploying Azure API Management (APIM) across multiple regions is essential. Combined with Azure Front Door, you can create a globally distributed API gateway that automatically routes traffic to the nearest healthy instance.
This guide covers:
- Multi-region architecture — Design patterns for global APIM
- Front Door integration — Configure intelligent routing
- Latency-based routing — Route to closest region
- Failover strategies — Automatic disaster recovery
- Configuration examples — Complete deployment guide
Architecture Patterns
Active-Active Multi-Region
┌─────────────────────────────────────────────────────────────────────┐
│ ACTIVE-ACTIVE MULTI-REGION │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Client 1 │ │ Client 2 │ │ Client 3 │ │
│ │ (East US) │ │ (West Eur) │ │ (Asia) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Azure Front Door │ │
│ │ • Latency-based routing │ │
│ │ • Health probe & failover │ │
│ │ • SSL termination │ │
│ │ • WAF & DDoS protection │ │
│ └──────┬──────────────────┬──────────────────────┬───────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ APIM East │ │ APIM West │ │ APIM │ │
│ │ US │ │ Europe │ │ Southeast │ │
│ │ │ │ │ │ Asia │ │
│ │ Primary │ │ Secondary │ │ Asia │ │
│ │ 100% active│ │ 100% active│ │ 100% active│ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Backend │ │ Backend │ │ Backend │ │
│ │ (East US) │ │ (West Eur) │ │ (Asia) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Traffic Flow
- Client sends request to Front Door
- Front Door measures latency to each APIM
- Routes to lowest latency healthy APIM
- APIM processes request and forwards to backend
- Backend can be regional or centralized
Deploy APIM to Multiple Regions
Create APIM Instances
# Create APIM in East US (Primary)
az apim create \
--name apim-primary \
--resource-group my-rg \
--location eastus \
--sku Developer \
--publisher-name "My Company" \
--publisher-email "admin@company.com" \
--virtual-network new
# Create APIM in West Europe (Secondary)
az apim create \
--name apim-secondary \
--resource-group my-rg \
--location westeurope \
--sku Developer \
--publisher-name "My Company" \
--publisher-email "admin@company.com" \
--virtual-network new
# Create APIM in Southeast Asia (Tertiary)
az apim create \
--name apim-tertiary \
--resource-group my-rg \
--location southeastasia \
--sku Developer \
--publisher-name "My Company" \
--publisher-email "admin@company.com" \
--virtual-network new
Synchronize APIs Across Regions
# Export API from primary
az apim api export \
--resource-group my-rg \
--name apim-primary \
--api-id my-api \
--output-folder ./api-export
# Import to secondary
az apim api import \
--resource-group my-rg \
--name apim-secondary \
--specification-type OpenAPI \
--source-type File \
--path ./api-export/swagger.json
# Import to tertiary
az apim api import \
--resource-group my-rg \
--name apim-tertiary \
--specification-type OpenAPI \
--source-type File \
--path ./api-export/swagger.json
Automation Script
#!/bin/bash
# deploy-apim-regions.sh
REGIONS=("eastus" "westeurope" "southeastasia")
API_NAME="my-api"
for region in "${REGIONS[@]}"; do
echo "Deploying APIM to $region..."
# Create APIM
az apim create \
--name "apim-${region}" \
--resource-group my-rg \
--location "$region" \
--sku Premium \
--publisher-name "My Company" \
--publisher-email "admin@company.com"
# Import API
az apim api import \
--resource-group my-rg \
--name "apim-${region}" \
--specification-type OpenAPI \
--source-type Uri \
--value "https://raw.githubusercontent.com/myrepo/openapi.yaml"
# Apply policies
az apim api policy set \
--resource-group my-rg \
--api-id "$API_NAME" \
--policy-file @./policies/regional-policy.xml
done
Configure Azure Front Door
Create Front Door Profile
# Create Front Door Standard
az front-door create \
--name my-front-door \
--resource-group my-rg \
--backend-address "" \
--enforce-check-true
# Add backend pool
az front-door backend-pool create \
--front-door-name my-front-door \
--name apim-backends \
--resource-group my-rg \
--address apim-primary.azure-api.net \
--weight 100 \
--priority 1
# Add additional backends
az front-door backend-pool add-backend \
--front-door-name my-front-door \
--backend-pool-name apim-backends \
--resource-group my-rg \
--address apim-secondary.azure-api.net \
--weight 100 \
--priority 2
Complete Configuration JSON
{
"backendPools": [
{
"name": "APIMBackends",
"properties": {
"backends": [
{
"address": "apim-primary.azure-api.net",
"enabled": true,
"priority": 1,
"weight": 100,
"healthProbeSettings": {
"name": "apimHealthProbe"
}
},
{
"address": "apim-secondary.azure-api.net",
"enabled": true,
"priority": 2,
"weight": 100,
"healthProbeSettings": {
"name": "apimHealthProbe"
}
},
{
"address": "apim-tertiary.azure-api.net",
"enabled": true,
"priority": 3,
"weight": 100,
"healthProbeSettings": {
"name": "apimHealthProbe"
}
}
],
"loadBalancingSettings": {
"name": "loadBalancingSettings"
},
"healthProbeSettings": {
"name": "apimHealthProbe"
}
}
}
],
"routingRules": [
{
"name": "ApiRoutingRule",
"properties": {
"frontendEndpoints": ["apiFrontendEndpoint"],
"backendPool": {
"id": "/subscriptions/xxx/resourceGroups/my-rg/providers/Microsoft.Network/frontDoors/my-front-door/backendPools/APIMBackends"
},
"routeConfiguration": {
"@odata.type": "#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration",
"forwardingProtocol": "HttpsOnly",
"cacheConfiguration": {
"queryParameterStripDirective": "StripNone",
"cacheDuration": "01:00:00"
}
}
}
}
],
"loadBalancingSettings": [
{
"name": "loadBalancingSettings",
"properties": {
"sampleSize": 4,
"successfulSamplesRequired": 2
}
}
],
"healthProbeSettings": [
{
"name": "apimHealthProbe",
"properties": {
"path": "/status-012",
"intervalInSeconds": 30,
"timeoutInSeconds": 10,
"protocol": "Https",
"healthProbeMethod": "HEAD"
}
}
]
}
Latency-Based Routing
Configure Latency-Based Load Balancing
{
"loadBalancingSettings": [
{
"name": "latencyBasedRouting",
"properties": {
"sampleSize": 50,
"successfulSamplesRequired": 25,
"additionalLatencyMilliseconds": 50
}
}
]
}
Weighted Latency Routing
{
"backendPools": [
{
"name": "APIMWithWeights",
"properties": {
"backends": [
{
"address": "apim-eastus.azure-api.net",
"weight": 100,
"priority": 1
},
{
"address": "apim-weur.azure-api.net",
"weight": 80,
"priority": 2
},
{
"address": "apim-seasia.azure-api.net",
"weight": 50,
"priority": 3
}
],
"loadBalancingSettings": {
"name": "latencyWithWeights"
}
}
}
]
}
Health Probe Configuration
Health Endpoint in APIM
<!-- Add to APIM policies -->
<policies>
<inbound>
<base />
<choose>
<when condition="@(context.Request.Url.Path.StartsWith("/status-012"))">
<return-response>
<set-status code="200" reason="OK" />
<set-body>OK</set-body>
</return-response>
</when>
</choose>
</inbound>
</policies>
Health Probe Settings
{
"healthProbeSettings": [
{
"name": "apimHealthCheck",
"properties": {
"path": "/status-012",
"intervalInSeconds": 30,
"timeoutInSeconds": 10,
"protocol": "Https",
"healthProbeMethod": "HEAD",
"enabledState": "Enabled"
}
}
]
}
Probe Response Validation
{
"healthProbeSettings": [
{
"name": "apimDetailedHealth",
"properties": {
"path": "/health",
"intervalInSeconds": 30,
"timeoutInSeconds": 10,
"protocol": "Https",
"healthProbeMethod": "GET"
}
}
]
}
Failover Behavior
Automatic Failover Logic
| Scenario | Front Door Behavior |
|---|---|
| One region down | Routes to healthy regions by priority |
| All primary down | Routes to secondary regions |
| All down | Returns 503 Service Unavailable |
| Latency spike | Routes to lower latency region |
| Backend slow response | Tries next healthy backend |
Priority-Based Routing
{
"backends": [
{
"address": "apim-eastus.azure-api.net",
"priority": 1,
"weight": 100,
"enabled": true
},
{
"address": "apim-weur.azure-api.net",
"priority": 2,
"weight": 50,
"enabled": true
},
{
"address": "apim-backup.azure-api.net",
"priority": 3,
"weight": 100,
"enabled": true
}
]
}
Custom Domain and SSL
Add Custom Domain to Front Door
# Add custom domain
az network front-door custom-domain create \
--front-door-name my-front-door \
--name api.example.com \
--resource-group my-rg \
--host-name api.example.com
# Get validation token
az network front-door custom-domain show \
--front-door-name my-front-door \
--name api.example.com \
--resource-group my-rg \
--query "validationToken"
Configure SSL
{
"frontendEndpoints": [
{
"name": "apiFrontendEndpoint",
"properties": {
"hostName": "api.example.com",
"sessionAffinityEnabledState": "Disabled",
"webApplicationFirewallPolicyLink": {
"id": "/subscriptions/xxx/resourceGroups/my-rg/providers/Microsoft.Network/FrontDoorWebApplicationFirewallPolicies/waf-policy"
},
"sslCertificate": {
"name": "api-ssl-cert",
"properties": {
"certificateType": "Dedicated"
}
}
}
}
]
}
Use Azure Key Vault for SSL
# Create Key Vault with certificate
az keyvault certificate create \
--vault-name my-key-vault \
--name api-cert \
--policy @cert-policy.json
# Create Front Door with Key Vault cert
az network front-door frontend-endpoint create \
--front-door-name my-front-door \
--name api-frontend \
--resource-group my-rg \
--host-name api.example.com \
--custom-https-configuration-source "KeyVault" \
--custom-https-key-vault-secret-id "https://my-key-vault.vault.azure.net/secrets/api-cert"
Complete Multi-Region ARM Template
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "eastus"
}
},
"resources": [
{
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2021-08-01",
"name": "[concat('apim-', parameters('location'))]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"capacity": 1
},
"properties": {
"publisherEmail": "admin@company.com",
"publisherName": "My Company",
"virtualNetworkType": "Internal"
}
},
{
"type": "Microsoft.Network/frontDoors",
"apiVersion": "2020-05-01",
"name": "my-front-door",
"location": "global",
"properties": {
"enabledState": "Enabled",
"backendPools": [
{
"name": "APIMBackends",
"properties": {
"backends": [
{
"address": "apim-eastus.azure-api.net",
"enabled": true,
"priority": 1,
"weight": 100
},
{
"address": "apim-westeurope.azure-api.net",
"enabled": true,
"priority": 2,
"weight": 100
}
],
"loadBalancingSettings": {
"name": "defaultLoadBalancing"
},
"healthProbeSettings": {
"name": "defaultHealthProbe"
}
}
}
]
}
}
]
}
Best Practices
| Practice | Description |
|---|---|
| Enable health probes | Detect unhealthy backends quickly |
| Use priority routing | Control failover order |
| Configure timeouts | Set appropriate backend timeouts |
| Enable WAF | Protect APIs from attacks |
| Use custom domains | Branded URLs for APIs |
| Monitor metrics | Track latency and availability |
| Test failover | Regularly simulate failures |
Monitoring and Diagnostics
# Get Front Door metrics
az monitor metrics list \
--resource-group my-rg \
--resource-type Microsoft.Network/frontdoors \
--metric "BackendHealthPercentage"
# Get APIM metrics by region
az monitor metrics list \
--resource-group my-rg \
--resource-type Microsoft.ApiManagement/service \
--metric "Requests" \
--aggregation "Count"
Azure Integration Hub - Advanced Level