Introduction to IIS Web Farm on Windows Server 2019

An IIS Web Farm is a group of two or more IIS servers that together serve the same web application, providing horizontal scalability and high availability. As traffic increases beyond what a single server can handle, a web farm distributes load across multiple servers. When a server fails, the remaining servers continue serving requests. Windows Server 2019 supports web farms using the Web Farm Framework (WFF) for configuration synchronisation, Application Request Routing (ARR) for load balancing, and Shared Configuration for keeping applicationHost.config identical across all nodes. This guide covers designing, deploying, and managing an IIS web farm.

Web Farm Architecture Overview

A typical IIS web farm consists of:

Frontend load balancer: An ARR server (or hardware load balancer) that distributes incoming requests across web servers. This server does not host web applications itself.

Web nodes: Two or more IIS servers hosting identical copies of the web application.

Shared storage: A UNC file share (DFS or SMB) hosting web application files, or a deployment pipeline that pushes identical content to each node.

Session state server or distributed cache: SQL Server Session State or Redis for sharing session data across nodes (required for stateful ASP.NET applications without sticky sessions).

Install ARR on the Load Balancer Node

# On the ARR/load balancer server
Install-WindowsFeature -Name Web-Server -IncludeManagementTools

# Install URL Rewrite and ARR (download from Microsoft)
# msiexec /i rewrite_amd64_en-US.msi /quiet
# msiexec /i ARRv3_setup_x64.EXE /quiet

# Enable ARR proxy
Set-WebConfigurationProperty `
    -PSPath "IIS:" `
    -Filter "system.webServer/proxy" `
    -Name "enabled" -Value $true

Install IIS Web Farm Framework

# Download Web Farm Framework 2.2 from Microsoft Web Platform Installer
# Install on the primary ARR server
# msiexec /i webfarm_v1.1_amd64_en_us.msi /quiet

# After installation, verify Web Farm Framework module
Get-WebConfiguration -Filter "system.webServer/globalModules/add" |
    Where-Object name -match "WebFarm" | Select-Object name

Create a Server Farm with ARR

cd "C:WindowsSystem32inetsrv"

# Create the web farm
.appcmd.exe set config -section:webFarms /+"[name='ProductionFarm']"

# Add all web nodes to the farm
.appcmd.exe set config -section:webFarms `
    /+"[name='ProductionFarm'].servers.[address='10.1.10.1',httpPort='80']"

.appcmd.exe set config -section:webFarms `
    /+"[name='ProductionFarm'].servers.[address='10.1.10.2',httpPort='80']"

.appcmd.exe set config -section:webFarms `
    /+"[name='ProductionFarm'].servers.[address='10.1.10.3',httpPort='80']"

# Set load balancing algorithm
.appcmd.exe set config -section:webFarms `
    /[name='ProductionFarm'].applicationRequestRouting.loadBalancing.algorithm:WeightedRoundRobin

Configure Health Monitoring

ARR pings each backend node to detect failures. When a node fails its health check, ARR stops sending it traffic until it recovers:

# Configure health check URL and interval
.appcmd.exe set config -section:webFarms `
    /[name='ProductionFarm'].applicationRequestRouting.healthCheck.url:"http://node/healthcheck.aspx"

.appcmd.exe set config -section:webFarms `
    /[name='ProductionFarm'].applicationRequestRouting.healthCheck.interval:00:00:15

.appcmd.exe set config -section:webFarms `
    /[name='ProductionFarm'].applicationRequestRouting.healthCheck.timeout:00:00:05

.appcmd.exe set config -section:webFarms `
    /[name='ProductionFarm'].applicationRequestRouting.healthCheck.responseMatch:"Healthy"

# Create the health check endpoint on all web nodes
# healthcheck.aspx simply returns "Healthy" with HTTP 200

Configure IIS Shared Configuration

Shared Configuration exports the IIS applicationHost.config to a UNC share. All nodes read configuration from the same file, ensuring sites, bindings, application pools, and modules are identical across all nodes:

# On Node 1 (primary), export shared configuration
# Create a share accessible to all IIS nodes
New-Item -ItemType Directory -Path "D:IISSharedConfig" -Force
New-SmbShare -Name "IISConfig" -Path "D:IISSharedConfig" `
    -FullAccess "corpDomain Computers","SYSTEM"

# Export configuration from the IIS Manager GUI:
# IIS Manager > Computer > Shared Configuration > Export Configuration
# Or via command line:
$iisConfigPath = "D:IISSharedConfig"
$password = ConvertTo-SecureString "Str0ngKey2019!" -AsPlainText -Force

# Export using appcmd
cd "C:WindowsSystem32inetsrv"
.appcmd.exe set config -section:configProtectedData -providers:@name=AesProvider

# Enable shared configuration pointing to the UNC share
# This is done via IIS Manager GUI or registry:
$sharedConfigPath = "HKLM:SOFTWAREMicrosoftInetStpConfiguration"
New-Item -Path $sharedConfigPath -Force
Set-ItemProperty -Path $sharedConfigPath -Name "SharedConfigEnabled" -Value 1 -Type DWord
Set-ItemProperty -Path $sharedConfigPath -Name "SharedConfigPhysicalPath" -Value "\fileserverIISConfig"

Deploy Web Content to All Nodes

Web content must be identical on all nodes. Use one of these approaches:

# Option 1: DFS Replication — replicate web root across all nodes automatically
# Install DFS Replication on all nodes
Install-WindowsFeature -Name FS-DFS-Replication -IncludeManagementTools

# Create a replication group (use DFS Management console or PowerShell)
New-DfsReplicationGroup -GroupName "WebContent" -DomainName "corp.example.com"
Add-DfsrMember -GroupName "WebContent" -ComputerName "WebNode1","WebNode2","WebNode3"

# Option 2: MSDeploy (Web Deploy) to push content to each node
# msdeploy -verb:sync -source:contentPath="C:buildsmyapp" 
#           -dest:contentPath="C:inetpubwwwrootmyapp",computerName="WebNode2"

# Option 3: Robocopy scheduled task from a central build server
robocopy "C:buildsmyapp" "\webnode2wwwrootmyapp" /E /MIR /Z /LOG:"C:deploy-logswebnode2.log"

Configure Session State for Web Farm

ASP.NET in-process session state is stored in the worker process’s memory. In a web farm, a user might be served by a different node on each request, losing their session. Solutions are sticky sessions, SQL Server session state, or Redis:

# Configure SQL Server Session State on each web node
# First, create the ASPState database on SQL Server
# aspnet_regsql.exe -S sqlserver.corp.local -E -ssadd -sstype p

# Then configure web.config on all nodes:
# 

# Or configure Machine Keys to be identical (required for encrypted session cookies)
# Generate a fixed machine key for all nodes in web.config:
# 

Monitor Farm Health

# View server farm status via appcmd
.appcmd.exe list webfarm "ProductionFarm"

# Check individual server health
.appcmd.exe list server /webFarmName:ProductionFarm

# ARR Dashboard is available in IIS Manager
# Machines with errors appear in red, healthy nodes in green

# PowerShell health check across all nodes
$nodes = @("10.1.10.1","10.1.10.2","10.1.10.3")
foreach ($node in $nodes) {
    try {
        $r = Invoke-WebRequest -Uri "http://$node/healthcheck.aspx" -TimeoutSec 5
        Write-Host "$node : $($r.StatusCode) - $($r.Content.Trim())"
    } catch {
        Write-Host "$node : FAILED - $_"
    }
}

Summary

An IIS Web Farm on Windows Server 2019 combines ARR for intelligent load distribution, Shared Configuration for consistent IIS settings across all nodes, DFS Replication or Web Deploy for content distribution, and SQL Server or Redis session state for stateful application support. Health monitoring ensures failed nodes are automatically removed from rotation, and weighted round-robin or least-requests algorithms distribute traffic efficiently. Together these components provide a horizontally scalable, highly available web application platform within the Windows Server ecosystem.