Manage traffic to App Service - Azure Application Gateway-2

rw-book-cover

In this article

  1. Prerequisites
  2. Configuring DNS
  3. Add App service as backend pool
  4. Edit HTTP settings for App Service
  5. Configure an HTTP listener
  6. Configure request routing rule
  7. Testing
  8. Restrict access

Application gateway allows you to have an App Service app or other multi-tenant service as a backend pool member. In this article, you learn to configure an App Service app with Application Gateway. The configuration for Application Gateway will differ depending on how App Service will be accessed:

This configuration is recommended for production-grade scenarios and meets the practice of not changing the host name in the request flow. You are required to have a custom domain (and associated certificate) available to avoid having to rely on the default ".azurewebsites" domain.

By associating the same domain name to both Application Gateway and App Service in the backend pool, the request flow doesn't need to override the host name. The backend web application will see the original host as was used by the client.

Scenario overview for Application Gateway to App Service using the same custom domain for both
This configuration is the easiest and doesn't require a custom domain. As such it allows for a quick convenient setup.

Warning

This configuration comes with limitations. We recommend to review the implications of using different host names between the client and Application Gateway and between Application and App Service in the backend. For more information, please review the article in Architecture Center: Preserve the original HTTP host name between a reverse proxy and its backend web application

When App Service doesn't have a custom domain associated with it, the host header on the incoming request on the web application will need to be set to the default domain, suffixed with ".azurewebsites.net" or else the platform won't be able to properly route the request.

The host header in the original request received by the Application Gateway will be different from the host name of the backend App Service.

Scenario overview for Application Gateway to App Service using the default App Service domain towards the backend
In this article you'll learn how to:

Prerequisites

Configuring DNS

In the context of this scenario, DNS is relevant in two places:

Route the user or client to Application Gateway using the custom domain. Set up DNS using a CNAME alias pointed to the DNS for Application Gateway. The Application Gateway DNS address is shown on the overview page of the associated Public IP address. Alternatively create an A record pointing to the IP address directly. (For Application Gateway V1 the VIP can change if you stop and start the service, which makes this option undesired.)

App Service should be configured so it accepts traffic from Application Gateway using the custom domain name as the incoming host. For more information on how to map a custom domain to the App Service, see Tutorial: Map an existing custom DNS name to Azure App Service To verify the domain, App Service only requires adding a TXT record. No change is required on CNAME or A-records. The DNS configuration for the custom domain will remain directed towards Application Gateway.

To accept connections to App Service over HTTPS, configure its TLS binding. For more information, see Secure a custom DNS name with a TLS/SSL binding in Azure App Service Configure App Service to pull the certificate for the custom domain from Azure Key Vault.

When no custom domain is available, the user or client can access Application Gateway using either the IP address of the gateway or its DNS address. The Application Gateway DNS address can be found on the overview page of the associated Public IP address. Not having a custom domain available implies that no publicly signed certificate will be available for TLS on Application Gateway. Clients are restricted to use HTTP or HTTPS with a self-signed certificate, both of which are undesired.

To connect to App Service, Application Gateway uses the default domain as provided by App Service (suffixed "azurewebsites.net").

Add App service as backend pool

  1. In the Azure portal, select your Application Gateway.
  2. Under Backend pools, select the backend pool.
  3. Under Target type, select App Services.
  4. Under Target select your App Service.

App service backend

Note

The dropdown only populates those app services which are in the same subscription as your Application Gateway. If you want to use an app service which is in a different subscription than the one in which the Application Gateway is, then instead of choosing App Services in the Targets dropdown, choose IP address or hostname option and enter the hostname (example.azurewebsites.net) of the app service.
5. Select Save.

PowerShell

# Fully qualified default domain name of the web app:
$webAppFQDN = "<nameofwebapp>.azurewebsite.net"

# For Application Gateway: both name, resource group and name for the backend pool to create:
$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"
$appGwBackendPoolNameForAppSvc = "<name for backend pool to be added>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Add a new Backend Pool with App Service in there:
Add-AzApplicationGatewayBackendAddressPool -Name $appGwBackendPoolNameForAppSvc -ApplicationGateway $gw -BackendFqdns $webAppFQDN

# Update Application Gateway with the new added Backend Pool:
Set-AzApplicationGateway -ApplicationGateway $gw

Edit HTTP settings for App Service

An HTTP Setting is required that instructs Application Gateway to access the App Service backend using the custom domain name. The HTTP Setting will by default use the default health probe. While default health probes will forward requests with the hostname in which traffic is received, the health probes will utilize 127.0.0.1 as the hostname to the Backend Pool since no hostname has explicitly been defined. For this reason, we need to create a custom health probe that is configured with the correct custom domain name as its host name.

We will connect to the backend using HTTPS.

  1. Under HTTP Settings, select an existing HTTP setting or add a new one.
  2. When creating a new HTTP Setting, give it a name
  3. Select HTTPS as the desired backend protocol using port 443
  4. If the certificate is signed by a well known authority, select "Yes" for "User well known CA certificate". Alternatively Add authentication/trusted root certificates of backend servers
  5. Make sure to set "Override with new host name" to "No"
  6. Select the custom HTTPS health probe in the dropdown for "Custom probe".

Configure H T T P Settings to use custom domain towards App Service backend using No Override
An HTTP Setting is required that instructs Application Gateway to access the App Service backend using the default ("azurewebsites.net") domain name. To do so, the HTTP Setting will explicitly override the host name.

  1. Under HTTP Settings, select an existing HTTP setting or add a new one.
  2. When creating a new HTTP Setting, give it a name
  3. Select HTTPS as the desired backend protocol using port 443
  4. If the certificate is signed by a well known authority, select "Yes" for "User well known CA certificate". Alternatively Add authentication/trusted root certificates of backend servers
  5. Make sure to set "Override with new host name" to "Yes"
  6. Under "Host name override", select "Pick host name from backend target". This setting will cause the request towards App Service to use the "azurewebsites.net" host name, as is configured in the Backend Pool.

Configure H T T P Settings to use default domain towards App Service backend by setting Pick host name from backend target
PowerShell

# Configure Application Gateway to connect to App Service using the incoming hostname
$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"
$customProbeName = "<name for custom health probe>"
$customDomainName = "<FQDN for custom domain associated with App Service>"
$httpSettingsName = "<name for http settings to be created>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Add custom health probe using custom domain name:
Add-AzApplicationGatewayProbeConfig -Name $customProbeName -ApplicationGateway $gw -Protocol Https -HostName $customDomainName -Path "/" -Interval 30 -Timeout 120 -UnhealthyThreshold 3
$probe = Get-AzApplicationGatewayProbeConfig -Name $customProbeName -ApplicationGateway $gw

# Add HTTP Settings to use towards App Service:
Add-AzApplicationGatewayBackendHttpSettings -Name $httpSettingsName -ApplicationGateway $gw -Protocol Https -Port 443 -Probe $probe -CookieBasedAffinity Disabled -RequestTimeout 30

# Update Application Gateway with the new added HTTP settings and probe:
Set-AzApplicationGateway -ApplicationGateway $gw

PowerShell

# Configure Application Gateway to connect to backend using default App Service hostname
$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"
$httpSettingsName = "<name for http settings to be created>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Add HTTP Settings to use towards App Service:
Add-AzApplicationGatewayBackendHttpSettings -Name $httpSettingsName -ApplicationGateway $gw -Protocol Https -Port 443 -PickHostNameFromBackendAddress -CookieBasedAffinity Disabled -RequestTimeout 30

# Update Application Gateway with the new added HTTP settings and probe:
Set-AzApplicationGateway -ApplicationGateway $gw

Configure an HTTP listener

To accept traffic we need to configure a Listener. For more info on this see Application Gateway listener configuration.

  1. Open the "Listeners" section and choose "Add listener" or click an existing one to edit
  2. For a new listener: give it a name
  3. Under "Frontend IP", select the IP address to listen on
  4. Under "Port", select 443
  5. Under "Protocol", select "HTTPS"
  6. Under "Choose a certificate", select "Choose a certificate from Key Vault". For more information, see Using Key Vault where you find more information on how to assign a managed identity and provide it with rights to your Key Vault.
    1. Give the certificate a name
    2. Select the Managed Identity
    3. Select the Key Vault from where to get the certificate
    4. Select the certificate
  7. Under "Listener Type", select "Basic"
  8. Click "Add" to add the listener

Add a listener for H T T P S traffic
Assuming there's no custom domain available or associated certificate, we'll configure Application Gateway to listen for HTTP traffic on port 80. Alternatively, see the instructions on how to Create a self-signed certificate

  1. Open the "Listeners" section and choose "Add listener" or click an existing one to edit
  2. For a new listener: give it a name
  3. Under "Frontend IP", select the IP address to listen on
  4. Under "Port", select 80
  5. Under "Protocol", select "HTTP"

Add a listener for H T T P traffic
PowerShell

# This script assumes that:
# - a certificate was imported in Azure Key Vault already
# - a managed identity was assigned to Application Gateway with access to the certificate
# - there is no HTTP listener defined yet for HTTPS on port 443

$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"
$appGwSSLCertificateName = "<name for ssl cert to be created within Application Gateway"
$appGwSSLCertificateKeyVaultSecretId = "<key vault secret id for the SSL certificate to use>"
$httpListenerName = "<name for the listener to add>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Create SSL certificate object for Application Gateway:
Add-AzApplicationGatewaySslCertificate -Name $appGwSSLCertificateName -ApplicationGateway $gw -KeyVaultSecretId $appGwSSLCertificateKeyVaultSecretId
$sslCert = Get-AzApplicationGatewaySslCertificate -Name $appGwSSLCertificateName -ApplicationGateway $gw

# Fetch public ip associated with Application Gateway:
$ipAddressResourceId = $gw.FrontendIPConfigurations.PublicIPAddress.Id
$ipAddressResource = Get-AzResource -ResourceId $ipAddressResourceId
$publicIp = Get-AzPublicIpAddress -ResourceGroupName $ipAddressResource.ResourceGroupName -Name $ipAddressResource.Name

$frontendIpConfig = $gw.FrontendIpConfigurations | Where-Object {$_.PublicIpAddress -ne $null}

$port = New-AzApplicationGatewayFrontendPort -Name "port_443" -Port 443
Add-AzApplicationGatewayFrontendPort -Name "port_443" -ApplicationGateway $gw -Port 443
Add-AzApplicationGatewayHttpListener -Name $httpListenerName -ApplicationGateway $gw -Protocol Https -FrontendIPConfiguration $frontendIpConfig -FrontendPort $port -SslCertificate $sslCert

# Update Application Gateway with the new HTTPS listener:
Set-AzApplicationGateway -ApplicationGateway $gw

In many cases a public listener for HTTP on port 80 will already exist. The below script will create one if that is not yet the case.

PowerShell

$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"
$httpListenerName = "<name for the listener to add if not exists yet>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Check if HTTP listener on port 80 already exists:
$port = $gw.FrontendPorts | Where-Object {$_.Port -eq 80}
$listener = $gw.HttpListeners | Where-Object {$_.Protocol.ToString().ToLower() -eq "http" -and $_.FrontendPort.Id -eq $port.Id}

if ($listener -eq $null){
    $frontendIpConfig = $gw.FrontendIpConfigurations | Where-Object {$_.PublicIpAddress -ne $null}
    Add-AzApplicationGatewayHttpListener -Name $httpListenerName -ApplicationGateway $gw -Protocol Http -FrontendIPConfiguration $frontendIpConfig -FrontendPort $port

    # Update Application Gateway with the new HTTPS listener:
    Set-AzApplicationGateway -ApplicationGateway $gw
}

Configure request routing rule

Using the earlier configured Backend Pool and the HTTP Settings, the request routing rule can be set up to take traffic from a listener and route it to the Backend Pool using the HTTP Settings. For this, make sure you have an HTTP or HTTPS listener available that is not already bound to an existing routing rule.

  1. Under "Rules", click to add a new "Request routing rule"
  2. Provide the rule with a name
  3. Select an HTTP or HTTPS listener that is not bound yet to an existing routing rule
  4. Under "Backend targets", choose the Backend Pool in which App Service has been configured
  5. Configure the HTTP settings with which Application Gateway should connect to the App Service backend
  6. Select "Add" to save this configuration

Add a new Routing rule from the listener to the App Service Backend Pool using the configured H T T P Settings
PowerShell

$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"
$httpListenerName = "<name for existing http listener (without rule) to route traffic from>"
$httpSettingsName = "<name for http settings to use>"
$appGwBackendPoolNameForAppSvc = "<name for backend pool to route to>"
$reqRoutingRuleName = "<name for request routing rule to be added>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Get HTTP Settings:
$httpListener = Get-AzApplicationGatewayHttpListener -Name $httpListenerName -ApplicationGateway $gw
$httpSettings = Get-AzApplicationGatewayBackendHttpSettings -Name $httpSettingsName -ApplicationGateway $gw
$backendPool = Get-AzApplicationGatewayBackendAddressPool -Name $appGwBackendPoolNameForAppSvc -ApplicationGateway $gw

# Add routing rule:
Add-AzApplicationGatewayRequestRoutingRule -Name $reqRoutingRuleName -ApplicationGateway $gw -RuleType Basic -BackendHttpSettings $httpSettings -HttpListener $httpListener -BackendAddressPool $backendPool

# Update Application Gateway with the new routing rule:
Set-AzApplicationGateway -ApplicationGateway $gw

Testing

Before we do so, make sure that the backend health shows as healthy:

Open the "Backend health" section and ensure the "Status" column indicates the combination for HTTP Setting and Backend Pool shows as "Healthy".

Check backend health in Azure portal
Now browse to the web application using either the Application Gateway IP Address or the associated DNS name for the IP Address. Both can be found on the Application Gateway "Overview" page as a property under "Essentials". Alternatively the Public IP Address resource also shows the IP address and associated DNS name.

Pay attention to the following non-exhaustive list of potential symptoms when testing the application:

The above conditions (explained in more detail in Architecture Center) would indicate that your web application doesn't deal well with rewriting the host name. This is commonly seen. The recommended way to deal with this is to follow the instructions for configuration Application Gateway with App Service using a custom domain. Also see: Troubleshoot App Service issues in Application Gateway.

Open the "Backend health" section and ensure the "Status" column indicates the combination for HTTP Setting and Backend Pool shows as "Healthy".

Check backend health in Azure portal
Now browse to the web application using the custom domain which you associated with both Application Gateway and the App Service in the backend.

Check if the backend health for the backend and HTTP Settings shows as "Healthy":

PowerShell

$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Check health:
Get-AzApplicationGatewayBackendHealth -ResourceGroupName $rgName -Name $appGwName

To test the configuration, we'll request content from the App Service through Application Gateway using the custom domain:

PowerShell

$customDomainName = "<FQDN for custom domain pointing to Application Gateway>"
Invoke-WebRequest $customDomainName

Check if the backend health for the backend and HTTP Settings shows as "Healthy":

PowerShell

$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Check health:
Get-AzApplicationGatewayBackendHealth -ResourceGroupName $rgName -Name $appGwName

To test the configuration, we'll request content from the App Service through Application Gateway using the IP address:

PowerShell

$rgName = "<name of resource group for App Gateway>"
$appGwName = "<name of the App Gateway>"

# Get existing Application Gateway:
$gw = Get-AzApplicationGateway -Name $appGwName -ResourceGroupName $rgName

# Get ip address:
$ipAddressResourceId = $gw.FrontendIPConfigurations.PublicIPAddress.Id
$ipAddressResource = Get-AzResource -ResourceId $ipAddressResourceId
$publicIp = Get-AzPublicIpAddress -ResourceGroupName $ipAddressResource.ResourceGroupName -Name $ipAddressResource.Name
Write-Host "Public ip address for Application Gateway is $($publicIp.IpAddress)"
Invoke-WebRequest "http://$($publicIp.IpAddress)"

Pay attention to the following non-exhaustive list of potential symptoms when testing the application:

The above conditions (explained in more detail in Architecture Center) would indicate that your web application doesn't deal well with rewriting the host name. This is commonly seen. The recommended way to deal with this is to follow the instructions for configuration Application Gateway with App Service using a custom domain. Also see: Troubleshoot App Service issues in Application Gateway.

Restrict access

The web apps deployed in these examples use public IP addresses that can be accessed directly from the Internet. This helps with troubleshooting when you're learning about a new feature and trying new things. But if you intend to deploy a feature into production, you'll want to add more restrictions. Consider the following options: