Skip to content
Learni
View all tutorials
Azure

How to Deploy Azure Application Gateway in 2026

Lire en français

Introduction

Azure Application Gateway is a managed layer 7 (L7) load balancer from Microsoft Azure, perfect for intelligently routing HTTP/HTTPS traffic to multiple backends. Unlike Azure Load Balancer (L4), it handles URL paths, host headers, and natively integrates a Web Application Firewall (WAF) to block OWASP attacks. In 2026, with the rise of microservices and API gateways, it's essential for scalable architectures.

This intermediate tutorial guides you step by step to deploy a complete v2 Gateway using Azure CLI, including a dedicated subnet, multi-VM backend pools, HTTPS listeners with certificates, and URL-based rules. You'll learn to configure OWASP 3.2 WAF for proactive security. By the end, you'll have production-ready infrastructure testable in 30 minutes. Why it matters: It supports up to 100 Gbps, autoscaling, and zone redundancy for 99.99% SLA. Ideal for AKS, VMs, or App Services.

Prerequisites

  • Active Azure account with Contributor permissions.
  • Azure CLI 2.65+ installed (download).
  • 2-3 existing VMs or backend IPs for testing (e.g., in a separate VNet).
  • Basic knowledge of Azure networking (VNet, NSG) and CLI.

1. Create the Resource Group and Variables

01-setup-rg.sh
#!/bin/bash

# Global variables (adapt to your environment)
RG_NAME="appgw-rg-$RANDOM"
LOCATION="francecentral"
VNET_NAME="appgw-vnet"
SUBNET_NAME="appgw-subnet"
APPGW_NAME="myAppGateway"

# Login and select subscription (run az login first)
az account set --subscription "YourSubscriptionID"

# Create Resource Group
echo "Création du RG: $RG_NAME"
az group create \
  --name $RG_NAME \
  --location $LOCATION \
  --tags 'project=appgw-tutorial' 'env=dev'

echo "RG créé: $RG_NAME"

This script initializes variables and creates a dedicated Resource Group with tags for traceability. Use a valid subscription ID after az login. Avoid shared RGs to isolate costs; the $RANDOM suffix prevents conflicts.

2. Prepare the Virtual Network

Application Gateway requires a dedicated subnet (minimum /27 for v1, /26 for v2 with WAF). This subnet must be empty and tagged appGatewaySubnet. The main VNet can host other resources, but keep it separate for security.

2. Create VNet and Dedicated Subnet

02-vnet-subnet.sh
#!/bin/bash

# Variables (continuation from previous script)
ADDRESS_PREFIX_VNET="10.0.0.0/16"
ADDRESS_PREFIX_SUBNET="10.0.1.0/26"

# Create VNet
echo "Création VNet: $VNET_NAME"
az network vnet create \
  --resource-group $RG_NAME \
  --name $VNET_NAME \
  --address-prefixes $ADDRESS_PREFIX_VNET \
  --subnet-name default \
  --subnet-prefixes "10.0.0.0/24" \
  --location $LOCATION

# Create dedicated subnet for AppGw (/26 required for WAF/ZR)
echo "Création subnet: $SUBNET_NAME"
az network vnet subnet create \
  --resource-group $RG_NAME \
  --vnet-name $VNET_NAME \
  --name $SUBNET_NAME \
  --address-prefixes $ADDRESS_PREFIX_SUBNET \
  --delegations Microsoft.Network/applicationGateways

# Tag the subnet
echo "Taggage subnet"
az network vnet subnet update \
  --resource-group $RG_NAME \
  --vnet-name $VNET_NAME \
  --name $SUBNET_NAME \
  --tags 'purpose=appgw-subnet'

Creates a VNet with a default subnet and a dedicated subnet delegated to ApplicationGateway. The delegation prevents conflicts; /26 supports up to 64 instances. Verify with az network vnet subnet list.

3. Deploy Basic Application Gateway

03-appgw-create.sh
#!/bin/bash

# Fictional backend IPs (replace with your real VMs, e.g., 10.0.2.4 10.0.2.5)
BACKEND_IPS="10.0.2.4 10.0.2.5"

# Create AppGw v2 Standard (public, capacity 2, zone-redundant)
echo "Déploiement AppGw: $APPGW_NAME (5-10min)"
az network application-gateway create \
  --resource-group $RG_NAME \
  --name $APPGW_NAME \
  --location $LOCATION \
  --sku Standard_v2 \
  --public-ip-address myPublicIP \
  --vnet-name $VNET_NAME \
  --subnet $SUBNET_NAME \
  --priority 100 \
  --capacity 2 \
  --tags 'project=appgw' 'tier=standard_v2'

# Add backend pool
az network application-gateway backend-pool create \
  --resource-group $RG_NAME \
  --gateway-name $APPGW_NAME \
  --name backendPool1 \
  --servers $BACKEND_IPS

Deploys a public v2 Gateway with autoscaling (min 2 instances). Provides backend IPs; adapt to your VMs/scale sets. The Standard_v2 SKU includes optional WAF; wait 5-10min for Succeeded.

3. Configure Backend Settings and Health Probes

Backend HTTP settings define the port (80/443), probe path (/health), and timeouts. An HTTP health probe periodically checks backends for intelligent routing.

4. Add HTTP Settings and Health Probe

04-http-settings-probe.sh
#!/bin/bash

# Create health probe (checks /healthz every 30s, unhealthy after >2 failures)
az network application-gateway probe create \
  --resource-group $RG_NAME \
  --gateway-name $APPGW_NAME \
  --probe-name healthProbeBackend \
  --protocol Http \
  --host "127.0.0.1" \
  --path "/healthz" \
  --interval 30 \
  --timeout 120 \
  --threshold 3 \
  --pick-host-name-from-backend-http-settings

# Create backend HTTP settings (port 80, attached probe, cookie affinity)
az network application-gateway http-settings create \
  --resource-group $RG_NAME \
  --gateway-name $APPGW_NAME \
  --name httpSettingsBackend \
  --protocol Http \
  --port 80 \
  --probe healthProbeBackend \
  --cookie-based-affinity Enabled \
  --request-timeout 120

Configures a probe to detect healthy backends (imagine a /healthz endpoint on your servers). The settings attach this probe and enable session affinity via cookies. Test with curl after deployment.

5. Create HTTPS Listener and Routing Rule

05-listener-rule.sh
#!/bin/bash

# Retrieve public IP (for listener)
PUBLIC_IP=$(az network public-ip show --resource-group $RG_NAME --name myPublicIP --query ipAddress --output tsv)

# Create HTTPS listener (port 443, requires self-signed or PFX certificate)
az network application-gateway listener create \
  --resource-group $RG_NAME \
  --gateway-name $APPGW_NAME \
  --name listenerHttps \
  --frontend-ip public \
  --frontend-port 443 \
  --protocol Https \
  --ssl-certificate myCert  # Upload cert via portal/CLI first

# Create basic rule (multi-site or path-based)
az network application-gateway rule create \
  --resource-group $RG_NAME \
  --gateway-name $APPGW_NAME \
  --name rule1 \
  --listener listenerHttps \
  --rule-type Basic \
  --backend-pool backendPool1 \
  --backend-http-settings httpSettingsBackend

Adds an HTTPS listener (upload a PFX cert via az network application-gateway ssl-cert create first). The Basic rule routes all traffic to the pool. For path-based, use --rule-type PathBasedRouting with patterns like /api/*.

6. Enable WAF v2 and Test

06-waf-test.sh
#!/bin/bash

# Enable WAF Policy OWASP 3.2 (Detection/Prevention mode)
az network application-gateway waf-policy create \
  --resource-group $RG_NAME \
  --name wafPolicy1 \
  --location $LOCATION

az network application-gateway ssl-policy update \
  --resource-group $RG_NAME \
  --gateway-name $APPGW_NAME \
  --name AppGwSslPolicy1 \
  --policy-type Predefined \
  --policy-name AppGwSslPolicy2025

# Associate WAF with listener (update rule)
az network application-gateway rule update \
  --resource-group $RG_NAME \
  --gateway-name $APPGW_NAME \
  --name rule1 \
  --firewall-policy wafPolicy1

# Test (replace $PUBLIC_IP)
echo "Testez: curl -k https://$PUBLIC_IP/healthz"
az network application-gateway show --resource-group $RG_NAME --name $APPGW_NAME

Enables WAF to block SQLi/XSS (Prevention mode). Associates it with the rule. The 2025 SSL policy enforces TLS 1.2+. Test with curl; WAF logs via az monitor diagnostic-settings create. Avoid Prevention mode in dev without tuning.

Best Practices

  • Dedicated and delegated subnet: Always /26+ for WAF/ZR, with restrictive NSG (ports 65200-65535 for probes).
  • WAF in Prevention: Start with Detection, tune exclusions (e.g., --exclusion sql-injection=RequestArgNames|user-agent).
  • Zone redundancy: Add --zones 1 2 3 on create for HA.
  • Monitoring: Enable Application Insights and diagnostic logs to Log Analytics.
  • Scaling: Use autoscale min 10/max 100 based on CPU/connections.

Common Errors to Avoid

  • Subnet too small: /27 fails with WAF; use /26 minimum.
  • No health probe: Backends marked unhealthy → 502 errors; always have a valid /healthz.
  • Missing certificate: HTTPS listener fails; upload PFX/Key Vault ref.
  • Public IP not associated: No external access; check az network public-ip create if omitted.

Next Steps