NashTech Blog

A Complete GuidEline Configure Azure App Service as a Reverse Proxy

Table of Contents

As cloud architectures become increasingly complex, the need for flexible routing and traffic management grows. Azure App Service, primarily known for hosting web applications, can also function as a powerful reverse proxy. This guide explores multiple approaches to configure Azure App Service as a reverse proxy, complete with practical examples and best practices.

Understanding Reverse Proxy in Azure App Service

A reverse proxy sits between clients and backend servers, forwarding client requests to appropriate backends and returning responses. In Azure App Service, this capability enables you to:

  • Route traffic to multiple backend services from a single endpoint
  • Implement API gateway patterns
  • Add a layer of abstraction and security
  • Handle legacy system integration
  • Implement custom routing logic

Method 1: IIS Application Request Routing (Windows App Service)

Azure App Service on Windows runs on IIS, which includes Application Request Routing (ARR). While pre-installed, ARR is disabled by default and requires manual configuration.

Step 1: Enable ARR via XDT Transform

Access your App Service through Kudu Console (Advanced Tools) and create a file named applicationHost.xdt in the site directory:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <proxy xdt:Transform="InsertIfMissing" 
           enabled="true" 
           preserveHostHeader="false" 
           reverseRewriteHostInResponseHeaders="false" />
  </system.webServer>
</configuration>

Key Parameters:

  • enabled="true": Activates ARR proxy functionality
  • preserveHostHeader="false": Forwards the backend’s hostname (set to true if backend validates Host header)
  • reverseRewriteHostInResponseHeaders="false": Controls header rewriting in responses

Step 2: Configure URL Rewrite Rules

Create or update web.config in your application root:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <!-- Proxy API requests to backend service -->
        <rule name="ProxyApiRequests" stopProcessing="true">
          <match url="^api/(.*)$" />
          <action type="Rewrite" 
                  url="https://backend-api.azurewebsites.net/{R:1}" 
                  logRewrittenUrl="true" />
        </rule>
        
        <!-- Proxy specific path to different backend -->
        <rule name="ProxyAuthService" stopProcessing="true">
          <match url="^auth/(.*)$" />
          <action type="Rewrite" 
                  url="https://auth-service.example.com/{R:1}" />
        </rule>
        
        <!-- Default catch-all rule -->
        <rule name="ProxyDefault" stopProcessing="true">
          <match url="^(.*)$" />
          <conditions>
            <add input="{REQUEST_URI}" pattern="^/(api|auth)" negate="true" />
          </conditions>
          <action type="Rewrite" 
                  url="https://default-backend.azurewebsites.net/{R:1}" />
        </rule>
      </rules>
      
      <!-- Optional: Outbound rules for response headers -->
      <outboundRules>
        <rule name="AddCorsHeader">
          <match serverVariable="RESPONSE_Access-Control-Allow-Origin" pattern=".*" />
          <action type="Rewrite" value="*" />
        </rule>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>

Step 3: Deploy and Restart

  1. Deploy both configuration files to your App Service
  2. Restart the App Service to apply XDT transforms
  3. Test your proxy endpoints

Common Scenarios and Solutions

Handling Authentication/Sessions: If your backend uses cookie-based authentication, preserve the original host header:

<proxy xdt:Transform="InsertIfMissing" 
       enabled="true" 
       preserveHostHeader="true" />

Query String Preservation: URL rewrite automatically preserves query strings. To modify this behavior:

<action type="Rewrite" 
        url="https://backend.com/{R:1}" 
        appendQueryString="false" />

Method 2: NGINX Reverse Proxy (Linux App Service)

For Linux-based App Services or containerized workloads, NGINX provides a robust reverse proxy solution.

Step 1: Create Custom NGINX Configuration

Create an nginx.conf file:

worker_processes 1;

events {
    worker_connections 1024;
}

http {
    upstream backend_api {
        server backend-api.azurewebsites.net:443;
    }
    
    upstream auth_service {
        server auth-service.example.com:443;
    }

    server {
        listen 80;
        listen 8080;
        
        server_name _;

        # API proxy
        location /api/ {
            proxy_pass https://backend_api/;
            proxy_ssl_server_name on;
            proxy_set_header Host backend-api.azurewebsites.net;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Host $host;
            
            # Timeouts
            proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }

        # Auth service proxy
        location /auth/ {
            proxy_pass https://auth_service/;
            proxy_ssl_server_name on;
            proxy_set_header Host auth-service.example.com;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            # Handle redirects
            proxy_redirect off;
        }

        # Health check endpoint
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }

        # Default location
        location / {
            proxy_pass https://default-backend.azurewebsites.net/;
            proxy_ssl_server_name on;
            proxy_set_header Host default-backend.azurewebsites.net;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Step 2: Create Dockerfile

FROM nginx:alpine

# Copy custom nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf

# Expose ports
EXPOSE 80 8080

# Start nginx
CMD ["nginx", "-g", "daemon off;"]

Step 3: Deploy to Azure App Service

# Build and push to Azure Container Registry
az acr build --registry <your-acr-name> \
             --image reverse-proxy:latest \
             --file Dockerfile .

# Configure App Service to use the container
az webapp config container set \
    --name <app-service-name> \
    --resource-group <resource-group> \
    --docker-custom-image-name <your-acr-name>.azurecr.io/reverse-proxy:latest \
    --docker-registry-server-url https://<your-acr-name>.azurecr.io

Method 3: Azure Application Gateway (Enterprise Solution)

For production environments requiring advanced features, Azure Application Gateway provides enterprise-grade reverse proxy capabilities:

Key Features:

  • Layer 7 Load Balancing: Content-based routing
  • SSL Termination: Offload SSL/TLS processing
  • Web Application Firewall (WAF): Built-in security
  • URL Path-Based Routing: Route based on URL patterns
  • Multi-site Hosting: Host multiple sites behind one gateway

Configuration Example:

# Create Application Gateway with path-based routing
az network application-gateway create \
    --name MyAppGateway \
    --resource-group MyResourceGroup \
    --location eastus \
    --sku WAF_v2 \
    --capacity 2 \
    --vnet-name MyVNet \
    --subnet MySubnet \
    --public-ip-address MyPublicIP

# Add backend pool for API
az network application-gateway address-pool create \
    --gateway-name MyAppGateway \
    --resource-group MyResourceGroup \
    --name ApiBackendPool \
    --servers backend-api.azurewebsites.net

# Add path-based rule
az network application-gateway url-path-map create \
    --gateway-name MyAppGateway \
    --resource-group MyResourceGroup \
    --name PathMap \
    --paths /api/* \
    --address-pool ApiBackendPool \
    --default-address-pool DefaultBackendPool

Comparison Matrix

MethodPlatformComplexityCostBest ForPerformance
IIS ARRWindowsMediumLow (App Service only)Simple routing, small-medium appsGood
NGINX ContainerLinux/ContainerMediumLow-Medium (App Service + ACR)Complex routing, custom logicExcellent
Application GatewayPlatform-agnosticLow-MediumHigh (dedicated resource)Enterprise, WAF, multi-siteExcellent

Best Practices

1. Security Considerations

<!-- Restrict backend access to App Service only -->
<rule name="SecureProxy">
  <match url=".*" />
  <action type="Rewrite" url="https://backend.azurewebsites.net/{R:0}" />
  <serverVariables>
    <set name="HTTP_X_SECRET_KEY" value="{YOUR_SHARED_SECRET}" />
  </serverVariables>
</rule>

2. Health Checks

Always implement health check endpoints:

location /health {
    access_log off;
    return 200 "healthy\n";
}

3. Logging and Monitoring

Enable Application Insights for comprehensive monitoring:

az webapp config appsettings set \
    --name <app-service-name> \
    --resource-group <resource-group> \
    --settings APPINSIGHTS_INSTRUMENTATIONKEY=<key>

4. Performance Optimization

  • Enable HTTP/2: Improves connection multiplexing
  • Use Connection Pooling: Reuse backend connections
  • Implement Caching: Cache static responses
  • Set Appropriate Timeouts: Prevent hanging connections
# NGINX optimization
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering on;
proxy_cache_valid 200 10m;

5. CORS Handling

For cross-origin requests, configure CORS headers:

<outboundRules>
  <rule name="CorsSupport">
    <match serverVariable="RESPONSE_Access-Control-Allow-Origin" pattern=".*" />
    <action type="Rewrite" value="*" />
  </rule>
  <rule name="CorsMethods">
    <match serverVariable="RESPONSE_Access-Control-Allow-Methods" pattern=".*" />
    <action type="Rewrite" value="GET, POST, PUT, DELETE, OPTIONS" />
  </rule>
</outboundRules>

References

  1. How to Enable Application Request Routing on Azure App Service
  2. Azure App Service and IIS based reverse proxy
  3. How to Add Reverse Proxy to Your Azure Web App
  4. Introducing the ‘Session Affinity Proxy’ setting in App Service Configuration

Picture of Thinh Tran Hoang Quoc

Thinh Tran Hoang Quoc

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top