Introduction to IIS Reverse Proxy on Windows Server 2019
A reverse proxy sits in front of backend servers and forwards incoming client requests to those servers, returning the responses to clients as if the proxy itself generated them. On Windows Server 2019, IIS combined with the Application Request Routing (ARR) module and URL Rewrite provides a fully-featured reverse proxy capable of load balancing, SSL offloading, health monitoring, session affinity (sticky sessions), and path-based routing. This is commonly used to publish internal web applications to the internet, consolidate multiple backend services behind a single hostname, or offload SSL processing from application servers.
Install Required Modules
IIS reverse proxy functionality requires two Microsoft extensions: URL Rewrite 2.1 and Application Request Routing (ARR) 3.0:
# Install IIS web server role
Install-WindowsFeature -Name Web-Server -IncludeManagementTools
# Download and install URL Rewrite 2.1
# msiexec /i rewrite_amd64_en-US.msi /quiet
# Download and install ARR 3.0
# msiexec /i ARRv3_setup_x64.EXE /quiet
# Verify both modules are loaded
Get-WebConfiguration -Filter "system.webServer/globalModules/add" |
Where-Object { $_.name -match "RewriteModule|ApplicationRequestRouting" } |
Select-Object name
# Enable the ARR proxy functionality
Set-WebConfigurationProperty `
-PSPath "IIS:" `
-Filter "system.webServer/proxy" `
-Name "enabled" -Value $true
# Verify proxy is enabled
Get-WebConfigurationProperty -PSPath "IIS:" -Filter "system.webServer/proxy" -Name "enabled"
Simple Reverse Proxy — Forward All Traffic to One Backend
The simplest reverse proxy configuration forwards all requests from the IIS site to a single backend server:
# Add reverse proxy rule to a site via web.config
# The URL Rewrite rule rewrites the request URL to the backend server
# This web.config rule goes in C:inetpubwwwrootweb.config:
$reverseProxyWebConfig = @'
'@
Set-Content -Path "C:inetpubwwwrootweb.config" -Value $reverseProxyWebConfig
Configure Server Farm for Load Balancing
ARR’s Server Farm feature provides load balancing across multiple backend servers with health monitoring and session affinity:
# Create a server farm using ARR PowerShell cmdlets
# Note: ARR module adds cmdlets when installed; use appcmd as fallback
# Using appcmd.exe to create server farm
cd "C:WindowsSystem32inetsrv"
# Create the server farm
.appcmd.exe set config -section:webFarms `
/+"[name='BackendFarm']"
# Add backend servers to the farm
.appcmd.exe set config -section:webFarms `
/+"[name='BackendFarm'].servers.[address='10.1.1.10',httpPort='80']"
.appcmd.exe set config -section:webFarms `
/+"[name='BackendFarm'].servers.[address='10.1.1.11',httpPort='80']"
.appcmd.exe set config -section:webFarms `
/+"[name='BackendFarm'].servers.[address='10.1.1.12',httpPort='80']"
# Configure load balancing algorithm (WeightedRoundRobin, LeastRequests, etc.)
.appcmd.exe set config -section:webFarms `
/[name='BackendFarm'].applicationRequestRouting.loadBalancing.algorithm:WeightedRoundRobin
# Configure health monitoring — check /health endpoint every 30 seconds
.appcmd.exe set config -section:webFarms `
/[name='BackendFarm'].applicationRequestRouting.healthCheck.url:"http://backend/health"
.appcmd.exe set config -section:webFarms `
/[name='BackendFarm'].applicationRequestRouting.healthCheck.interval:00:00:30
.appcmd.exe set config -section:webFarms `
/[name='BackendFarm'].applicationRequestRouting.healthCheck.timeout:00:00:05
Route Requests to the Server Farm
# Create a URL Rewrite rule to send traffic to the server farm
# Add to web.config or applicationHost.config:
$farmProxyRule = @'
'@
# Insert inside in web.config
Configure Session Affinity (Sticky Sessions)
Session affinity ensures requests from the same client are always routed to the same backend server. ARR uses a cookie to track affinity:
# Enable session affinity on the server farm
.appcmd.exe set config -section:webFarms `
/[name='BackendFarm'].applicationRequestRouting.affinity.useCookie:true
.appcmd.exe set config -section:webFarms `
/[name='BackendFarm'].applicationRequestRouting.affinity.cookieName:"ARRAffinity"
# Set affinity cookie lifetime in seconds (0 = session cookie)
.appcmd.exe set config -section:webFarms `
/[name='BackendFarm'].applicationRequestRouting.affinity.cookieLifeTime:0
SSL Offloading
With SSL offloading, the IIS reverse proxy terminates the TLS connection from clients and forwards unencrypted HTTP to backend servers. Backend servers are relieved of the CPU cost of TLS handshakes. The proxy passes the original client IP and protocol to backends via custom headers:
# Enable preserving client IP and original protocol headers
Set-WebConfigurationProperty `
-PSPath "IIS:" `
-Filter "system.webServer/proxy" `
-Name "preserveHostHeader" -Value $true
# ARR automatically adds X-Forwarded-For and X-Forwarded-Proto headers
# Verify these are being set by checking a backend server's request log
# Backend receives:
# X-Forwarded-For:
# X-Forwarded-Proto: https
# X-ARR-ClientCert:
Path-Based Routing
Route different URL paths to different backend servers from the same hostname:
# Route /api/* to API backend, /* to web frontend
# Add these rules to web.config:
# Rule 1: API requests to API backend
$apiRule = @'
'@
# Rule 2: All other requests to web frontend
$webRule = @'
'@
# Rules are evaluated in order — API rule must come first
Monitor ARR with Performance Counters
# ARR performance counters show requests routed to each backend
Get-Counter -ListSet "Application Request Routing" |
Select-Object -ExpandProperty Counter
Get-Counter "Application Request RoutingRequests per second" -SampleInterval 5 -MaxSamples 3
Get-Counter "Application Request RoutingActive Requests" -SampleInterval 5 -MaxSamples 3
Security Considerations
# Disable access to the proxy admin interface from outside
Set-WebConfigurationProperty `
-PSPath "IIS:SitesDefault Web Site" `
-Filter "system.webServer/security/ipSecurity" `
-Name "allowUnlisted" -Value $false
# Add internal management IP
Add-WebConfigurationProperty `
-PSPath "IIS:SitesDefault Web Site" `
-Filter "system.webServer/security/ipSecurity" `
-Name "." `
-Value @{ipAddress="192.168.1.0"; subnetMask="255.255.255.0"; allowed="True"}
# Remove Server header (stop disclosing IIS version to clients)
Set-WebConfigurationProperty `
-PSPath "IIS:" `
-Filter "system.webServer/security/requestFiltering" `
-Name "removeServerHeader" -Value $true
Summary
IIS with ARR on Windows Server 2019 provides enterprise-grade reverse proxy capabilities including load balancing across multiple backend servers, health monitoring with automatic failover, session affinity for stateful applications, SSL offloading to reduce backend CPU load, and path-based routing to direct different URL paths to different backend pools. The combination of ARR and URL Rewrite gives granular control over request routing without requiring a separate dedicated load balancer product for many enterprise workloads.