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

  1. Client sends request to Front Door
  2. Front Door measures latency to each APIM
  3. Routes to lowest latency healthy APIM
  4. APIM processes request and forwards to backend
  5. 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

ScenarioFront Door Behavior
One region downRoutes to healthy regions by priority
All primary downRoutes to secondary regions
All downReturns 503 Service Unavailable
Latency spikeRoutes to lower latency region
Backend slow responseTries 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

PracticeDescription
Enable health probesDetect unhealthy backends quickly
Use priority routingControl failover order
Configure timeoutsSet appropriate backend timeouts
Enable WAFProtect APIs from attacks
Use custom domainsBranded URLs for APIs
Monitor metricsTrack latency and availability
Test failoverRegularly 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