How to Configure Network Load Balancing on Windows Server 2019

Network Load Balancing (NLB) is a Windows Server feature that distributes TCP/IP network traffic across multiple servers, providing scalability and availability for stateless applications such as web servers, VPN servers, and terminal servers. NLB operates at Layer 4 (transport layer) of the OSI model and does not require additional hardware. Unlike Failover Clustering, NLB is designed for outbound load distribution, not for high availability of stateful server roles. Windows Server 2019 NLB supports up to 32 nodes per cluster.

NLB Architecture and How It Works

NLB creates a virtual IP address (VIP) shared by all cluster nodes. All nodes receive all incoming packets destined for the VIP. The NLB driver on each node uses a deterministic algorithm based on the client’s source IP/port to decide whether to process the packet or discard it. This ensures only one node processes each client connection, but all nodes share the incoming traffic load. NLB does not require a central load balancer appliance — all nodes participate in the distribution algorithm simultaneously.

Installing NLB

# Install NLB on all servers that will be cluster members
Install-WindowsFeature -Name NLB, RSAT-NLB -IncludeManagementTools

# Verify installation
Get-WindowsFeature -Name NLB, RSAT-NLB

# Import the NLB module
Import-Module NetworkLoadBalancingClusters

Creating an NLB Cluster

Create the NLB cluster on the first node. Choose the cluster IP address carefully — this is the VIP clients will connect to. It must be in the same subnet as the node’s physical IP:

# Create a new NLB cluster on the first node
New-NlbCluster `
    -HostName "web01.corp.example.com" `
    -ClusterPrimaryIP "192.168.1.100" `
    -SubnetMask "255.255.255.0" `
    -InterfaceName "Ethernet" `
    -OperationMode Multicast `
    -ClusterName "WEB-NLB"

# View the created cluster
Get-NlbCluster

# View cluster properties
Get-NlbCluster -HostName "web01.corp.example.com" | Format-List

Adding Nodes to the NLB Cluster

Add additional web servers to the NLB cluster. Each node gets a unique priority number (1-32) for tie-breaking in the load distribution algorithm:

# Add a second node to the cluster
Add-NlbClusterNode `
    -HostName "web02.corp.example.com" `
    -NewNodeName "web02.corp.example.com" `
    -NewNodeInterface "Ethernet"

# Add a third node
Add-NlbClusterNode `
    -HostName "web01.corp.example.com" `
    -NewNodeName "web03.corp.example.com" `
    -NewNodeInterface "Ethernet"

# Set the host priority for each node (lower number = higher priority for single-host rules)
Get-NlbClusterNode -HostName "web01.corp.example.com" | Set-NlbClusterNode -HostPriority 1
Get-NlbClusterNode -HostName "web02.corp.example.com" | Set-NlbClusterNode -HostPriority 2
Get-NlbClusterNode -HostName "web03.corp.example.com" | Set-NlbClusterNode -HostPriority 3

# View all cluster nodes
Get-NlbClusterNode | Select-Object HostName, Status, HostPriority, DedicatedIPAddress

Configuring Port Rules

Port rules define how traffic is distributed across the cluster. A rule specifies which ports and protocols are load balanced and the affinity (client stickiness) setting. Create specific rules for each service the cluster hosts:

# Remove the default all-ports rule (replaces it with specific rules)
Remove-NlbClusterPortRule -HostName "web01.corp.example.com" -Port 0

# Create a port rule for HTTP (TCP 80) with no affinity (each connection goes to any node)
Add-NlbClusterPortRule `
    -HostName "web01.corp.example.com" `
    -Protocol TCP `
    -StartPort 80 `
    -EndPort 80 `
    -Mode Multiple `
    -Affinity None `
    -LoadWeight Equal

# Create a port rule for HTTPS (TCP 443) with single client affinity
# (All connections from the same client IP go to the same node)
Add-NlbClusterPortRule `
    -HostName "web01.corp.example.com" `
    -Protocol TCP `
    -StartPort 443 `
    -EndPort 443 `
    -Mode Multiple `
    -Affinity Single `
    -LoadWeight Equal

# Create a port rule for RDP with Single affinity (session persistence)
Add-NlbClusterPortRule `
    -HostName "web01.corp.example.com" `
    -Protocol TCP `
    -StartPort 3389 `
    -EndPort 3389 `
    -Mode Multiple `
    -Affinity Single `
    -LoadWeight Equal

# Create a port rule handled by a single host (all traffic goes to priority-1 node)
Add-NlbClusterPortRule `
    -HostName "web01.corp.example.com" `
    -Protocol TCP `
    -StartPort 8443 `
    -EndPort 8443 `
    -Mode Single

# Block a specific port (all traffic dropped by NLB)
Add-NlbClusterPortRule `
    -HostName "web01.corp.example.com" `
    -Protocol All `
    -StartPort 21 `
    -EndPort 21 `
    -Mode Disabled

# List all port rules
Get-NlbClusterPortRule -HostName "web01.corp.example.com" | `
    Select-Object Protocol, StartPort, EndPort, Mode, Affinity, LoadWeight | Format-Table

Configuring NLB Affinity

Affinity determines whether a client’s subsequent connections are directed to the same cluster node. This is critical for applications that store session state locally rather than in a shared database:

None: Load balance each connection to any available node. Best for stateless applications or those using shared session stores. Single: All connections from the same client IP are directed to the same node. Required when session state is stored locally. Network: All clients from the same Class C subnet go to the same node. Useful when clients are behind a proxy that uses multiple IPs from the same subnet.

# Update affinity on an existing port rule
$rule = Get-NlbClusterPortRule -HostName "web01.corp.example.com" -Protocol TCP -Port 443
Set-NlbClusterPortRule -InputObject $rule -Affinity Network

# View affinity settings
Get-NlbClusterPortRule -HostName "web01.corp.example.com" | `
    Select-Object Protocol, StartPort, Affinity

NLB Operation Modes

NLB supports Unicast, Multicast, and IGMP Multicast modes. Unicast mode requires all cluster nodes to share the same MAC address (which prevents nodes from communicating with each other directly). Multicast mode assigns the VIP a multicast MAC address, allowing normal node-to-node communication:

# View current operation mode
Get-NlbCluster | Select-Object ClusterName, OperationMode, IPAddress

# Change to multicast mode (recommended when nodes need to communicate with each other)
Set-NlbCluster -HostName "web01.corp.example.com" -OperationMode Multicast

# Change to IGMP Multicast (reduces network flooding by confining multicast to registered ports)
Set-NlbCluster -HostName "web01.corp.example.com" -OperationMode MulticastIGMP

Managing NLB Cluster Nodes

Control individual nodes for maintenance, rolling updates, or draining connections before taking a server offline:

# Start all nodes
Start-NlbClusterNode -HostName "web01.corp.example.com"
Start-NlbClusterNode -HostName "web02.corp.example.com"

# Stop a node (connections are not drained - existing connections may drop)
Stop-NlbClusterNode -HostName "web03.corp.example.com" -Drain

# Drain a node (waits for existing connections to finish before removing from cluster)
Stop-NlbClusterNode -HostName "web03.corp.example.com" -Drainstop

# Suspend a node (temporarily remove from cluster for maintenance)
Suspend-NlbClusterNode -HostName "web03.corp.example.com"

# Resume after maintenance
Resume-NlbClusterNode -HostName "web03.corp.example.com"

# View node status across all cluster nodes
Get-NlbClusterNode | Select-Object HostName, Status

Monitoring NLB

# Check NLB cluster status
Get-NlbCluster | Select-Object ClusterName, IPAddress, Status

# View NLB node statistics
Get-NlbClusterNodeStatistic -HostName "web01.corp.example.com"

# View port rule statistics
Get-NlbClusterPortRuleStatistic -HostName "web01.corp.example.com"

# View NLB event log
Get-WinEvent -LogName System | Where-Object {$_.ProviderName -like "*NLB*"} | Select-Object -First 20

# Test load distribution
# Send multiple requests and observe which server responds
for ($i = 1; $i -le 10; $i++) {
    $response = Invoke-WebRequest -Uri "http://192.168.1.100/whoami.aspx" -UseBasicParsing
    $response.Content  # Should show different server names
}

Removing a Node from the Cluster

# Remove a specific node from the NLB cluster
Remove-NlbClusterNode -HostName "web01.corp.example.com" -NodeName "web03.corp.example.com"

# Delete the entire NLB cluster
Remove-NlbCluster -HostName "web01.corp.example.com"

NLB is best suited for stateless HTTP/HTTPS workloads where any node can service any request. For applications that require state persistence, either configure shared session storage (Redis, SQL Server session state, or ASP.NET Distributed Cache) to allow None affinity, or use Single affinity with the understanding that node failure will affect clients whose sessions were hosted on the failed node. For enterprise-grade load balancing with health checking, SSL offload, and advanced routing, consider hardware load balancers or Windows Application Request Routing (ARR) with IIS.