Overview:
Documenting several common solutions for various Azure Front Door/App Gateway + App Service scenarios.
Why:
Proper configuration of any WAF or frontend proxy in front of App Service is an essential web infrastructure task for users. Even large organizations have trouble with this. Accurately understanding the scenario and possible solutions directly impacts the user’s ability to be successful using these Azure products.
Scenario:
This issue can surface in various ways. One of the most common issues is an unexpected redirect to and disclosure of the internal Azurewebsites.net hostname.
Client request passing through any frontend load balancer (AFD / AppGW / Cloudflare / WAF / etc) receives HTTP 301/302 redirect with Location response header revealing the backend Web App’s internal hostname (azurewebsites.net). This can commonly occur on trailing slash, post-auth redirect, or any URL the app code constructs based on request Host header.
Ex 1.
Ex 2.
Solutions:
Solutions #1 and #2 will fit most common scenarios.
#1 Preserve custom domain through to backend Web App and validate custom domain
Architecture: |
- Any layer 7 load balancer (including App Gateway or Front Door), Windows or Linux Web Apps
|
Issue: |
- Any 301/302 redirect that points the client back to the internal Azurewebsites.net URL
- Any internal app issue caused by the azurewebsites.net Host request header such as auth failure
- Broken ARRAffinity cookie causes session data stored in-app worker memory to be lost
|
Solution: |
|
Pros: |
- This is a nearly one-size-fits-all solution no matter the architecture, or backend Web App framework
- Documented best practice solution in all Azure architecture designs and can be achieved through automation
|
Cons: |
- This option depends entirely on the user’s ability to create a DNS TXT record to validate the custom domain as acceptable on the backend Web App
- There are many downsides, such as the maintenance overhead of validating every custom domain on every backend Web App
|
Comments: |
- This should always be the first option, but even though this is the documented best practice there are downsides and in some cases (like path-based routing) it is not possible to validate the custom domain
- For broken ARRAffinity, this is the only option, or run the Web App on only 1 instance, or rewrite app code to not store session data in-app memory
|
#2 Location response header overwrite
Architecture: |
- Application Gateway v2 or Azure Front Door, Windows or Linux Web Apps
|
Issue: |
- Any 301/302 redirect that points the client back to the internal Azurewebsites.net URL via HTTP response header Location value (see example images above)
|
Solution: |
- Use App Gateway header rewrite rules or Front Door rule engine features, to overwrite the Location response header value with a new value pointing at the original hostname + the updated redirect URL path, using regular expressions
- Front Door does not currently have any solution documented. Only the server variable definitions for rules: https://docs.microsoft.com/en-us/azure/frontdoor/rule-set-server-variables
- This rule should achieve the same goal as the App Gateway example. NOTE: I have not tested this rule extensively, it may need changes for certain situations, but I am providing it in the absence of any other documented example
{request_scheme}://{hostname}/{url_path}/
|
Pros: |
- The custom rule is relatively simple and quick to implement, as an alternative to solution #1, and can be automated
- Documented solution examples for App Gateway scenarios
|
Cons: |
- Requires configuring a custom rule for each site in the load balancer, adding complexity and maintenance overhead to the design
- No documented solution examples for Front Door scenarios
|
Comments: |
- This should usually be the second option, in all unexpected redirect scenarios
|
Solutions #3 – #7 are alternative options for certain specific situations.
#3 EasyAuth (Authentication) AAD issues
Architecture: |
- EasyAuth (Authentication) with AAD, any layer 7 load balancer (including App Gateway or Front Door), Windows or Linux Web Apps
|
Issue: |
- User successfully authenticates through AAD EasyAuth, but is redirected post-auth to azurewebsites.net, instead of the original hostname
|
Solution: |
|
Pros: |
- This is a well documented and relatively simple Web App configuration, which can be automated
|
Cons: |
- This solution only applies to EasyAuth auth scenarios
|
Comments: |
- If the only redirection occurs because of EasyAuth, this can be the best solution
- If the user is not using EasyAuth, but experiences an issue during auth because of azurewebsites.net, this can usually be handled in the site’s custom auth code or auth configurations. Custom auth implementations are more flexible and can be configured in ways that Web App EasyAuth cannot.
|
#4 App code redirects
Architecture: |
- Any layer 7 load balancer (including App Gateway or Front Door), Windows or Linux Web Apps
|
Issue: |
- Application code performs any 301/302 redirects which reveals azurewebsites.net in location response header, such as appending a trailing slash
|
Solution: |
- Change application code to send only the updated URL path back in the location response header, without updating the hostname
- Here is an example of my ASP.NET Core 3.1 C# code which achieves this trailing slash redirect in Startup.cs:
app.UseStaticFiles();
var options = new RewriteOptions()
.AddRedirect("(.*[^/])$", "$1/", 301);
app.UseRewriter(options);
|
Pros: |
- This is in my opinion the best possible option when the issue occurs only due to application code, and the developer has access to the code and is not doing anything overly complex
- Updating the redirect code behavior to return a relative path allows the application to work natively behind load balancers without any custom rules or maintenance
- This is the most portable, resilient, and permanent solution to issues that arise due to app code behavior
|
Cons: |
- This solution depends entirely on the user’s access to the app code, understanding of the code, and willingness to test implementing a code change
- Microsoft teams would not write the updated code or identify every line of code that needs updating, but could provide examples
|
Comments: |
- This is possible due to the June 2014 update to HTTP 1.1 (compatible with HTTP 2) protocol definitions in RFC 7231 for location response header: https://www.rfc-editor.org/rfc/rfc7231#section-7.1.2
- June 1999’s RFC 2616 required an absolute URI in the Location, but that standard has been replaced. It is now valid to return a relative URI in the redirect.
|
#5 Disable Windows IIS courtesy redirect for trailing slash via Web.config
Architecture: |
- Any layer 7 load balancer (including App Gateway or Front Door), Windows Web App
|
Issue: |
- Windows IIS default behavior is to take a request for www.contoso.com/dir, first attempt to return a matching file, next check if the path exists as a directory, and if so redirect with 302 appending the trailing slash
- This can cause the internal hostname azurewebsites.net/dir/ to be returned to the client via the Location response header
|
Solution: |
- Use a <rewrite> rule in the Web.config to rewrite the request as having included the trailing slash
- Here is a Web.config example I published: https://pastebin.com/tR5ywyx4
- This rule is only an example which is tested to work, it may not work for every scenario, and could be updated as needed
|
Pros: |
- On Windows sites this known scenario can be resolved with a simple rule in the web.config, which can be added to the projects
|
Cons: |
- This requires a permanent change to the user’s app files and testing, which they may be unwilling to do
- Only relevant for Windows Web Apps
|
Comments: |
- Solutions #1 and #2 both also solve this issue, but #5 provides an alternative for solving the issue at the webserver layer on Windows Web Apps
- Others have published various similar solutions online, although I would not recommend these directly but for education: https://github.com/Ekus/CourtesyRedirectOverride
|
#6 Overwrite ‘Host’ server variable on Windows IIS Web Apps, with applicationHost.xdt and Web.config
Architecture: |
- Any layer 7 load balancer (including App Gateway or Front Door), Windows Web App
|
Issue: |
- Any 301/302 redirect that points the client back to the internal Azurewebsites.net URL
- Any internal app issue caused by the azurewebsites.net Host request header such as auth failure
|
Solution: |
-
- Use an applicationhost.xdt & web.config to override the HOST header, this is a one-size fits all solution, no customization needed per app. It injects the X-ORIGINAL-HOST in place of HOST.
applicationHost.xdt to add the server variables
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<rewrite>
<allowedServerVariables xdt:Transform="Replace">
<add name="HTTP_HOST" xdt:Transform="InsertIfMissing" />
<add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="InsertIfMissing" />
</allowedServerVariables>
</rewrite>
</system.webServer>
</configuration>
Web.config to do the rewrite
<rewrite>
<rules>
<!-- CDN sets original host in X-Original-Host header -->
<rule name="forwardedHost" stopProcessing="false">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_X_ORIGINAL_HOST}" pattern="^$" negate="true" />
</conditions>
<serverVariables>
<set name="HTTP_HOST" value="{HTTP_X_ORIGINAL_HOST}"></set>
</serverVariables>
</rule>
</rules>
</rewrite>
- Note: X-ORIGINAL-HOST is used by App Gateway, X-FORWARDED-HOST is used by Front Door, other load balancers could use a different request header and the above configurations must be updated appropriately
|
Pros: |
- This is a mostly one-size-fits-all solution to common issues for Windows Web Apps
- Can be included in the projects and deployment pipelines
|
Cons: |
- This requires a permanent change to the user’s app files and testing, which they may be unwilling to do
- Only relevant for Windows Web Apps
|
Comments: |
|
#7 Fix Linux Web App running Apache/nginx server redirection issues with .htaccess or nginx.conf configuration
Architecture: |
- Any layer 7 load balancer (including App Gateway or Front Door), Linux Web App
|
Issue: |
- Apache/Nginx server itself causes a default 301/302 redirection that points the client back to the internal Azurewebsites.net URL
|
Solution: |
|
Pros: |
- Solve certain specific Linux Web App related issues with an app file change, which can be included with the project deployment
|
Cons: |
- This requires a permanent change to the user’s app files and testing, which they may be unwilling to do
- Only relevant for Linux Web Apps
|
Comments: |
- Other solutions are more preferable than solution #7, but it is a realistic option for certain Linux scenarios
|