Home DevOps Microsoft Azure — Azure Load Balancer
Intermediate 8 min · July 12, 2026

Microsoft Azure — Azure Load Balancer

Public and internal load balancer, frontend IP, backend pools, health probes, and load-balancing rules..

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Verified
production tested
July 12, 2026
last updated
436
articles · all by Naren
Before you start⏱ 25 min
  • Azure subscription with contributor access, Azure CLI 2.50+, basic understanding of networking (TCP/IP, subnets, NSGs), familiarity with Azure portal and resource groups.
✦ Definition~90s read
What is Microsoft Azure?

Microsoft Azure — Azure Load Balancer is a core Azure service that handles load balancer in the Microsoft cloud ecosystem.

Azure Load Balancer is like having a specialized tool that handles load balancer in the Microsoft cloud — you manage the configuration, Azure handles the infrastructure.
Plain-English First

Azure Load Balancer is like having a specialized tool that handles load balancer in the Microsoft cloud — you manage the configuration, Azure handles the infrastructure.

Azure is Microsoft's cloud computing platform offering over 200 services. This article covers azure load balancer with production-ready configurations, best practices, and hands-on examples.

Azure Load Balancer: The Stateless Workhorse

Azure Load Balancer (ALB) operates at Layer 4 of the OSI model, distributing TCP/UDP traffic across healthy backend instances. Unlike Application Gateway (Layer 7), ALB is stateless—it doesn't inspect payloads. This makes it ideal for high-throughput, low-latency scenarios like database replicas, DNS servers, or any workload where you need raw packet forwarding. ALB supports both public (inbound internet) and internal (private VNet) load balancing. It uses a five-tuple hash (source IP, source port, destination IP, destination port, protocol) to maintain session affinity when configured with 'Client IP' persistence. Crucially, ALB does not terminate TLS; that's a job for a reverse proxy or Application Gateway. In production, you'll often pair ALB with a TLS terminator behind it. ALB's health probes are configurable: HTTP, HTTPS, or TCP. For TCP, a simple SYN-ACK check suffices; for HTTP, you can probe a specific endpoint like /health. Always set a short probe interval (5s) and low unhealthy threshold (2) to detect failures fast. ALB's backend pools can be VMs, VMSS, or IP addresses (including on-prem via VPN). Standard SKU is mandatory for production—Basic SKU lacks availability zones and SLA.

create-alb.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
az network lb create \
  --resource-group prod-rg \
  --name prod-lb \
  --sku Standard \
  --public-ip-address prod-pip \
  --frontend-ip-name frontend \
  --backend-pool-name backend-pool

az network lb probe create \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name tcp-probe \
  --protocol Tcp \
  --port 80 \
  --interval 5 \
  --threshold 2

az network lb rule create \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name http-rule \
  --protocol Tcp \
  --frontend-port 80 \
  --backend-port 80 \
  --frontend-ip-name frontend \
  --backend-pool-name backend-pool \
  --probe-name tcp-probe
Output
{
"loadBalancer": {
"name": "prod-lb",
"sku": {
"name": "Standard"
},
"probes": [
{
"name": "tcp-probe",
"protocol": "Tcp",
"port": 80,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
],
"loadBalancingRules": [
{
"name": "http-rule",
"protocol": "Tcp",
"frontendPort": 80,
"backendPort": 80
}
]
}
}
🔥Standard SKU vs Basic
Always use Standard SKU in production. Basic SKU lacks availability zones, has no SLA, and doesn't support NAT gateway or cross-region load balancing. Standard SKU also enables outbound rules and connection draining.
📊 Production Insight
In production, we once saw a 5-minute outage because the health probe interval was set to 30s with threshold 3. A backend VM failed, but traffic kept flowing to it for 90 seconds. Set probe interval to 5s and unhealthy threshold to 2 for sub-10 second failover.
🎯 Key Takeaway
Azure Load Balancer is a Layer 4, stateless load balancer ideal for TCP/UDP traffic with low latency requirements.
azure-load-balancer THECODEFORGE.IO Azure Load Balancer Traffic Flow Step-by-step path from client to backend Client Request Inbound traffic arrives at LB frontend IP Load Balancing Rule Maps frontend IP:Port to backend pool Health Probe Check Probes backend instances for health status Backend Pool Selection Distributes traffic to healthy instances Session Persistence Optional: 5-tuple hash for sticky sessions Response to Client Backend replies directly, LB is stateless ⚠ Health probe misconfiguration can drop all traffic Ensure probe interval and threshold match app sensitivity THECODEFORGE.IO
thecodeforge.io
Azure Load Balancer

Backend Pools: Choosing the Right Membership Type

Azure Load Balancer supports three backend pool membership types: Virtual Machines, Virtual Machine Scale Sets (VMSS), and IP addresses (including on-premises). For production, VMSS is the recommended approach because it integrates with autoscaling and rolling upgrades. When using VMs, you must manually add/remove them from the backend pool—error-prone during scaling events. IP-based pools allow you to target any IP, including on-prem servers via VPN or ExpressRoute, but you lose automatic health probe integration with Azure VMs. For VMSS, ALB automatically adds new instances and removes terminated ones. However, note that ALB does not wait for connection draining before removing an instance—it stops sending new connections immediately. To avoid dropped connections, configure connection draining (idle timeout) on the load balancing rule. The default idle timeout is 4 minutes; set it to match your application's longest request. When using VMSS with a custom image, ensure the health probe endpoint is responsive before the instance is marked healthy. A common pitfall: the application starts listening on port 80 before it's ready to serve traffic, causing 502 errors. Use a startup script that delays health probe response until the app is fully initialized.

configure-backend-pool.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Add VMSS to backend pool
az network lb address-pool create \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name backend-pool

az network lb address-pool vmss add \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name backend-pool \
  --vmss-name prod-vmss \
  --backend-addresses '[{"ipAddress":"10.0.1.4"},{"ipAddress":"10.0.1.5"}]'

# For IP-based pool (on-prem)
az network lb address-pool address add \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --pool-name backend-pool \
  --name onprem-1 \
  --ip-address 192.168.1.10 \
  --subnet /subscriptions/.../subnets/onprem-subnet
Output
{
"backendAddressPool": {
"name": "backend-pool",
"loadBalancerBackendAddresses": [
{
"name": "onprem-1",
"ipAddress": "192.168.1.10"
}
]
}
}
⚠ Connection Draining
ALB does not support true connection draining. When a backend is removed, existing connections are terminated immediately. Use application-level retry logic or set a low idle timeout to minimize impact.
📊 Production Insight
We had a production incident where a VMSS rolling upgrade caused all instances to be replaced simultaneously, dropping all active connections. Solution: use a rolling upgrade with max surge=1 and configure health probe with a grace period.
🎯 Key Takeaway
Use VMSS backend pools for autoscaling and automatic instance management; IP-based pools for hybrid scenarios.

Health Probes: The Canary in the Coal Mine

Health probes are ALB's mechanism to determine backend instance health. Three protocols: TCP, HTTP, HTTPS. TCP probe checks if the port is listening—fast but shallow. HTTP/HTTPS probes check a specific endpoint (e.g., /health) and expect a 200 OK. Always prefer HTTP probes for application-level health. Design your /health endpoint to verify dependencies: database connectivity, cache, disk space. A common mistake is a health endpoint that returns 200 even when the app is broken (e.g., stuck in a deadlock). Implement a liveness check that fails fast. Probe configuration: interval (default 15s), unhealthy threshold (default 2), healthy threshold (default 2). For production, set interval to 5s, unhealthy threshold to 2, healthy threshold to 1. This gives ~10s detection of failure. Be careful with probe port—it must match the backend port unless you use a separate health port. ALB probes originate from Azure's infrastructure IP range (168.63.129.16). Ensure your NSG allows inbound traffic from this IP on the probe port. If you block it, all instances will be marked unhealthy. Also, probes are sent from all Azure regions where the LB is deployed; for cross-region, you need to allow broader ranges.

health-endpoint.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from flask import Flask, jsonify
import psycopg2
import os

app = Flask(__name__)

def check_db():
    try:
        conn = psycopg2.connect(
            host=os.getenv('DB_HOST'),
            port=5432,
            dbname=os.getenv('DB_NAME'),
            user=os.getenv('DB_USER'),
            password=os.getenv('DB_PASS'),
            connect_timeout=2
        )
        conn.close()
        return True
    except Exception:
        return False

@app.route('/health')
def health():
    if not check_db():
        return jsonify({"status": "unhealthy", "reason": "database down"}), 503
    return jsonify({"status": "healthy"}), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)
Output
HTTP/1.1 200 OK
Content-Type: application/json
{"status": "healthy"}
💡Probe Source IP
Azure health probes originate from 168.63.129.16. Add an NSG rule to allow inbound TCP traffic from this IP on the probe port. Without it, all backends will be marked unhealthy.
📊 Production Insight
We once had a cascading failure where a database slowdown caused all health endpoints to timeout, marking all instances unhealthy. The LB stopped sending traffic, and the app went down. Solution: implement circuit breakers in the health endpoint to fail fast, not wait for timeout.
🎯 Key Takeaway
Health probes determine backend availability; use HTTP probes with dependency checks for accurate health signals.
azure-load-balancer THECODEFORGE.IO Azure Load Balancer Architecture Layered view of components and tiers Client Tier Internet | Azure Virtual Network Load Balancer Tier Frontend IP Config | Load Balancing Rules | Health Probes Backend Pool Tier NIC-based Membership | IP-based Membership Compute Tier Virtual Machines | VMSS Instances Availability Tier Availability Zones | Cross-Region LB Monitoring Tier Metrics | Diagnostic Logs | Alerts THECODEFORGE.IO
thecodeforge.io
Azure Load Balancer

Load Balancing Rules and Session Persistence

Load balancing rules define how traffic is distributed. Each rule binds a frontend IP:port to a backend pool:port. You can have multiple rules for different protocols (e.g., TCP 80, TCP 443). Session persistence (affinity) is optional: None, Client IP, or Client IP and Protocol. For stateless apps, use None. For stateful apps (e.g., shopping cart), use Client IP. However, Client IP persistence can cause uneven distribution if many users share the same IP (NAT). For better distribution, use Client IP and Protocol, which adds the protocol to the hash. ALB uses a five-tuple hash by default; session persistence modifies the hash to include only the specified fields. Important: session persistence is not sticky sessions in the traditional sense—it's based on the hash, not a cookie. If a backend goes down, the hash is recalculated, and traffic may go to a different backend. For true sticky sessions, use Application Gateway with cookie-based affinity. Also, note that session persistence is per rule, not per backend. If you have multiple rules, each can have its own persistence setting. In production, avoid session persistence for high-availability; design your app to be stateless or use a distributed cache (Redis) for session state.

create-lb-rule.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
az network lb rule create \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name http-rule \
  --protocol Tcp \
  --frontend-port 80 \
  --backend-port 80 \
  --frontend-ip-name frontend \
  --backend-pool-name backend-pool \
  --probe-name http-probe \
  --idle-timeout 4 \
  --enable-tcp-reset true \
  --load-distribution SourceIPProtocol
Output
{
"loadBalancingRule": {
"name": "http-rule",
"protocol": "Tcp",
"frontendPort": 80,
"backendPort": 80,
"idleTimeoutInMinutes": 4,
"enableTcpReset": true,
"loadDistribution": "SourceIPProtocol"
}
}
🔥TCP Reset
Enable TCP reset on idle timeout to immediately close connections that exceed the idle timeout. This prevents half-open connections and improves resource cleanup.
📊 Production Insight
We debugged a case where session persistence caused a single backend to receive 80% of traffic because many users were behind the same corporate NAT. Switched to None and used Redis for session state, solving the imbalance.
🎯 Key Takeaway
Load balancing rules map frontend ports to backend pools; session persistence uses hash-based affinity, not cookies.

Outbound Rules: SNAT and Source NAT

Azure Load Balancer provides outbound connectivity for backend instances via Source Network Address Translation (SNAT). When a VM in the backend pool initiates outbound traffic, ALB translates the source IP to the frontend public IP. This is critical for VMs that need to reach the internet (e.g., for updates, external APIs). Outbound rules are configured on the load balancer. You define which frontend IP to use, which backend pool, and the port allocation strategy. The default SNAT port allocation is 1024 ports per VM, but you can adjust with 'Manual' or 'Use Default'. For production, use 'Manual' and allocate based on expected concurrent connections. A common failure: SNAT port exhaustion. Each outbound connection consumes a port; when all ports are used, new connections fail. Symptoms: intermittent connectivity, timeouts. To mitigate, use multiple frontend IPs (up to 16) to increase port pool. Also, consider using Azure NAT Gateway for larger scale—it provides 64,512 ports per IP and scales better. Outbound rules are only available on Standard SKU. Basic SKU uses default outbound access (no control). Always configure explicit outbound rules to avoid relying on default behavior, which can change.

create-outbound-rule.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Create outbound rule
az network lb outbound-rule create \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name outbound-rule \
  --frontend-ip-configs frontend \
  --backend-pool-name backend-pool \
  --protocol All \
  --idle-timeout 4 \
  --outbound-ports 10000

# Add additional frontend IP for more SNAT ports
az network lb frontend-ip create \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name frontend2 \
  --public-ip-address prod-pip2

az network lb outbound-rule update \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name outbound-rule \
  --frontend-ip-configs frontend frontend2
Output
{
"outboundRule": {
"name": "outbound-rule",
"allocatedOutboundPorts": 10000,
"frontendIPConfigurations": [
{"id": "/subscriptions/.../frontendIPConfigurations/frontend"},
{"id": "/subscriptions/.../frontendIPConfigurations/frontend2"}
]
}
}
⚠ SNAT Port Exhaustion
Each outbound connection consumes a SNAT port. Monitor SNAT port usage with Azure Monitor metrics. If usage exceeds 80%, add more frontend IPs or switch to NAT Gateway.
📊 Production Insight
We hit SNAT exhaustion during a Black Friday sale. The fix: added 4 additional frontend IPs and reduced idle timeout to 2 minutes. Also implemented connection pooling in the app to reuse connections.
🎯 Key Takeaway
Outbound rules control SNAT for backend instances; monitor port usage to avoid exhaustion.

High Availability: Availability Zones and Cross-Region

Standard SKU ALB supports availability zones. You can deploy a zone-redundant frontend (spans all zones) or zonal (pinned to one zone). Zone-redundant is recommended for production—it survives a zone outage. Backend VMs should also be distributed across zones. For cross-region load balancing, Azure offers Cross-Region Load Balancer (preview). It distributes traffic across regional ALBs using a global frontend IP. This is useful for active-passive or active-active multi-region deployments. Cross-region LB uses a health probe on the regional LB's frontend. If a region fails, traffic is redirected to the next healthy region. However, cross-region LB does not support session persistence—each request may go to a different region. For stateful apps, use Traffic Manager or Front Door instead. In production, always deploy ALB in a zone-redundant configuration. Also, ensure backend VMs are in the same zones as the frontend to avoid cross-zone latency. For critical workloads, combine ALB with Azure Front Door for global load balancing and DDoS protection.

zone-redundant-alb.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Create zone-redundant public IP
az network public-ip create \
  --resource-group prod-rg \
  --name prod-pip \
  --sku Standard \
  --zone 1 2 3

# Create zone-redundant frontend
az network lb frontend-ip create \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name frontend \
  --public-ip-address prod-pip \
  --zone 1 2 3

# Create backend VMs in each zone
for zone in 1 2 3; do
  az vm create \
    --resource-group prod-rg \
    --name vm-zone-$zone \
    --zone $zone \
    --vnet-name prod-vnet \
    --subnet backend-subnet \
    --image UbuntuLTS \
    --admin-username azureuser \
    --generate-ssh-keys
done
Output
{
"publicIP": {
"name": "prod-pip",
"sku": {"name": "Standard"},
"zones": ["1", "2", "3"]
},
"frontendIPConfiguration": {
"name": "frontend",
"zones": ["1", "2", "3"]
}
}
💡Zone-Redundant vs Zonal
Zone-redundant frontend survives a zone outage. Zonal frontend is pinned to one zone—if that zone fails, the LB goes down. Always choose zone-redundant for production.
📊 Production Insight
During a regional outage, our zone-redundant ALB kept serving traffic because backends were in two remaining zones. We had a playbook to manually scale up the healthy zones. Test zone failure scenarios in a non-prod environment.
🎯 Key Takeaway
Use zone-redundant frontend and distribute backends across zones for high availability within a region.

Monitoring and Diagnostics: Logs, Metrics, Alerts

Azure Load Balancer integrates with Azure Monitor for metrics and logs. Key metrics: Packet Count, Byte Count, SNAT Connection Count, Health Probe Status, Data Path Availability. Set alerts on Health Probe Status (if backend count drops below threshold) and SNAT Connection Count (if >80% utilized). For deep diagnostics, enable NSG flow logs and LB logs. LB logs include load balancer rule events and health probe events. However, LB logs are verbose; enable only for troubleshooting. Use Azure Monitor Workbooks to create dashboards. A common issue: data path availability metric shows 0 when the LB frontend is unreachable (e.g., NSG blocking). Always monitor this metric. For proactive monitoring, set up action groups to notify on alert triggers. Also, use Azure Resource Health to check LB health. In production, we recommend a minimum of 90% data path availability alert. For SNAT, set a warning at 70% and critical at 90%. Additionally, log backend instance health changes to detect flapping instances (rapidly toggling healthy/unhealthy). Flapping can indicate misconfigured health probes or application instability.

setup-alerts.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Create metric alert for health probe status
az monitor metrics alert create \
  --resource-group prod-rg \
  --name "HealthProbeAlert" \
  --scopes /subscriptions/.../loadBalancers/prod-lb \
  --condition "avg HealthProbeStatus < 1" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --action-groups /subscriptions/.../actionGroups/prod-ag

# Create alert for SNAT port usage
az monitor metrics alert create \
  --resource-group prod-rg \
  --name "SNATAlert" \
  --scopes /subscriptions/.../loadBalancers/prod-lb \
  --condition "avg SnatConnectionCount > 8000" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --action-groups /subscriptions/.../actionGroups/prod-ag
Output
{
"metricAlert": {
"name": "HealthProbeAlert",
"condition": "avg HealthProbeStatus < 1",
"windowSize": "PT5M",
"evaluationFrequency": "PT1M"
}
}
🔥Data Path Availability
This metric indicates if the LB frontend is reachable. If it drops to 0, no traffic can flow. Common causes: NSG blocking, public IP deleted, or backend pool empty.
📊 Production Insight
We missed a slow SNAT exhaustion because we only alerted on >90%. By the time alert fired, connections were dropping. Now we alert at 70% and have automated scale-up of frontend IPs.
🎯 Key Takeaway
Monitor health probe status and SNAT connection count; set alerts for proactive incident response.

Troubleshooting Common Failures

Even with proper configuration, things go wrong. Here are common failure modes and how to diagnose them. 1) Backend marked unhealthy: Check NSG rules—ensure 168.63.129.16 is allowed on probe port. Verify the health endpoint returns 200. Use az network lb probe show to see probe status. 2) No traffic to backend: Check load balancing rule mapping. Verify backend pool has instances. Use az network lb list-backend-address-pool to list addresses. 3) Intermittent timeouts: Likely SNAT port exhaustion. Check SnatConnectionCount metric. Increase frontend IPs or reduce idle timeout. 4) Connection resets: TCP reset enabled? If idle timeout is too low, connections may be reset prematurely. Increase idle timeout or disable TCP reset if not needed. 5) Uneven traffic distribution: Session persistence causing imbalance. Check load distribution setting. Use SourceIPProtocol for better distribution. 6) Cross-region issues: Ensure regional LBs are healthy. Cross-region LB uses health probes on regional frontends. If a regional LB is down, traffic fails over. Test failover by stopping a regional LB. Always have a troubleshooting runbook with these steps. Use Azure Network Watcher's IP flow verify to test connectivity. Also, enable diagnostic logs for the LB to capture rule hits.

troubleshoot.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Check health probe status
az network lb probe show \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name http-probe \
  --query "loadBalancingRules[].{name:name, provisioningState:provisioningState}"

# List backend pool addresses
az network lb address-pool list \
  --resource-group prod-rg \
  --lb-name prod-lb \
  --name backend-pool \
  --query "loadBalancerBackendAddresses[].ipAddress"

# Verify NSG allows probe
az network nsg rule list \
  --resource-group prod-rg \
  --nsg-name backend-nsg \
  --query "[?destinationPortRange=='80']"

# Check SNAT metrics
az monitor metrics list \
  --resource /subscriptions/.../loadBalancers/prod-lb \
  --metric SnatConnectionCount \
  --interval PT1H \
  --output table
Output
Backend IPs: 10.0.1.4, 10.0.1.5
NSG Rule: Allow TCP 80 from 168.63.129.16
SNAT Connection Count: 4500 (avg)
⚠ Common Pitfall: Probe Port Mismatch
If your health probe port differs from the backend port, ensure the backend is listening on the probe port. Otherwise, the probe will fail and mark the instance unhealthy.
📊 Production Insight
We once spent hours debugging 'no traffic' only to find the backend pool was empty because a deployment script removed all VMs. Always have a minimum instance count guardrail in your IaC.
🎯 Key Takeaway
Systematic troubleshooting: check NSG, probe status, SNAT metrics, and load distribution.

Production Deployment with Infrastructure as Code

Manual creation of ALB is error-prone. Use Infrastructure as Code (IaC) with Terraform or ARM/Bicep. Below is a Terraform example for a production-grade ALB with zone redundancy, health probes, and outbound rules. Key practices: parameterize everything, use remote state, and implement CI/CD pipelines. In the Terraform config, note the use of for_each to create multiple frontend IPs for SNAT. Also, the health probe depends on the backend pool. Always set depends_on explicitly to avoid race conditions. For production, use modules to encapsulate LB configuration. Test changes in a staging environment first. Use Terraform workspaces for environment separation. Also, enable prevent_destroy on critical resources like the LB itself. For secrets (e.g., health endpoint passwords), use Azure Key Vault. Finally, integrate with Azure Policy to enforce SKU Standard and zone-redundancy. This ensures compliance across all subscriptions.

main.tfHCL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
resource "azurerm_lb" "prod" {
  name                = "prod-lb"
  location            = azurerm_resource_group.prod.location
  resource_group_name = azurerm_resource_group.prod.name
  sku                 = "Standard"
}

resource "azurerm_lb_frontend_ip_configuration" "frontend" {
  name                 = "frontend"
  loadbalancer_id      = azurerm_lb.prod.id
  public_ip_address_id = azurerm_public_ip.prod.id
  zones                = ["1", "2", "3"]
}

resource "azurerm_lb_backend_address_pool" "backend" {
  loadbalancer_id = azurerm_lb.prod.id
  name            = "backend-pool"
}

resource "azurerm_lb_probe" "http" {
  loadbalancer_id = azurerm_lb.prod.id
  name            = "http-probe"
  protocol        = "Http"
  port            = 80
  request_path    = "/health"
  interval_in_seconds = 5
  number_of_probes     = 2
}

resource "azurerm_lb_rule" "http" {
  loadbalancer_id                = azurerm_lb.prod.id
  name                           = "http-rule"
  protocol                       = "Tcp"
  frontend_port                  = 80
  backend_port                   = 80
  frontend_ip_configuration_name = azurerm_lb_frontend_ip_configuration.frontend.name
  backend_address_pool_ids       = [azurerm_lb_backend_address_pool.backend.id]
  probe_id                       = azurerm_lb_probe.http.id
  idle_timeout_in_minutes        = 4
  enable_tcp_reset               = true
}

resource "azurerm_lb_outbound_rule" "outbound" {
  loadbalancer_id = azurerm_lb.prod.id
  name            = "outbound-rule"
  protocol        = "All"
  allocated_outbound_ports = 10000
  frontend_ip_configurations {
    name = azurerm_lb_frontend_ip_configuration.frontend.name
  }
  backend_address_pool_id = azurerm_lb_backend_address_pool.backend.id
}
Output
Apply complete! Resources: 6 added.
💡Terraform State
Store Terraform state in Azure Storage with encryption and locking. Never use local state for production. Use azurerm_backend_container for remote state.
📊 Production Insight
We had a deployment that accidentally deleted the LB because Terraform state was stale. Now we use prevent_destroy on critical resources and run terraform plan in CI with manual approval.
🎯 Key Takeaway
Use IaC (Terraform/Bicep) for repeatable, auditable ALB deployments; parameterize and use remote state.

Security: NSGs, DDoS, and Private Endpoints

Azure Load Balancer itself is not a security appliance—it's a traffic distributor. Security must be implemented at the network and application layers. First, Network Security Groups (NSGs) on backend subnets: allow only traffic from the LB frontend IP (or VNet) and health probe source IP (168.63.129.16). Deny all other inbound. For public ALB, enable Azure DDoS Protection Standard on the VNet. This protects against volumetric attacks. ALB does not have built-in WAF; use Azure Application Gateway or Front Door for Layer 7 filtering. For internal ALB, use Private Endpoints to expose services privately. ALB can be placed behind a firewall (e.g., Azure Firewall) for traffic inspection. However, this adds latency. For compliance, enable diagnostic logs and send to Log Analytics. Use Azure Policy to enforce that ALBs are Standard SKU and have NSGs attached. Also, restrict outbound traffic from backend VMs using NSGs or Azure Firewall. Never allow unrestricted outbound. Finally, use Managed Identities for VMs to access Azure resources securely, avoiding connection strings in code.

nsg-rules.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Allow LB health probe
az network nsg rule create \
  --resource-group prod-rg \
  --nsg-name backend-nsg \
  --name AllowLBProbe \
  --priority 100 \
  --direction Inbound \
  --access Allow \
  --protocol Tcp \
  --source-address-prefixes 168.63.129.16 \
  --source-port-ranges '*' \
  --destination-address-prefixes '*' \
  --destination-port-ranges 80

# Allow traffic from LB frontend
az network nsg rule create \
  --resource-group prod-rg \
  --nsg-name backend-nsg \
  --name AllowLBTraffic \
  --priority 110 \
  --direction Inbound \
  --access Allow \
  --protocol Tcp \
  --source-address-prefixes 10.0.0.4/32 \
  --source-port-ranges '*' \
  --destination-address-prefixes '*' \
  --destination-port-ranges 80

# Deny all other inbound
az network nsg rule create \
  --resource-group prod-rg \
  --nsg-name backend-nsg \
  --name DenyAllInbound \
  --priority 4096 \
  --direction Inbound \
  --access Deny \
  --protocol '*' \
  --source-address-prefixes '*' \
  --source-port-ranges '*' \
  --destination-address-prefixes '*' \
  --destination-port-ranges '*'
Output
NSG rules created successfully.
⚠ DDoS Protection
Basic DDoS protection is free but limited. Enable DDoS Protection Standard on the VNet for advanced mitigation. It costs ~$3k/month but is essential for public-facing production workloads.
📊 Production Insight
We mitigated a DDoS attack by enabling DDoS Standard and rate-limiting at the application layer. The LB itself was fine, but backend VMs were overwhelmed. We added auto-scaling and a WAF in front.
🎯 Key Takeaway
Secure ALB with NSGs, DDoS Protection, and private endpoints; use Azure Firewall for traffic inspection if needed.

Cost Optimization and Performance Tuning

Azure Load Balancer pricing is based on rules and data processed. Standard SKU has a fixed hourly cost plus per-GB data processing. To optimize: consolidate rules—each rule adds cost. Use a single rule for multiple ports if possible (e.g., TCP 80-443). For outbound, use NAT Gateway instead of LB outbound rules for better port scalability and lower cost at high volumes. NAT Gateway costs ~$0.045/hour plus data processing, but provides 64,512 ports per IP. For performance, ALB can handle millions of flows. However, ensure backend VMs are sized appropriately. Use accelerated networking on VMs for higher throughput. Also, enable TCP segmentation offload (TSO) on the OS. Monitor latency metrics: ALB adds <1ms latency. If you see higher, check backend response times. For global performance, use cross-region LB or Front Door. In production, right-size your backend pool: too few instances cause overload; too many waste cost. Use autoscaling based on CPU or request count. Finally, consider reserved instances for predictable workloads to save up to 72% on VM costs.

cost-estimate.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Estimate monthly cost
az consumption prices list \
  --query "[?contains(productName, 'Load Balancer')].{name: productName, price: unitPrice}" \
  --output table

# Example: Standard LB with 1 rule, 10GB data
# Hourly: $0.025/hr * 730 = $18.25
# Data: $0.008/GB * 10 = $0.08
# Total: ~$18.33/month

# Compare with NAT Gateway
# Hourly: $0.045/hr * 730 = $32.85
# Data: $0.045/GB * 10 = $0.45
# Total: ~$33.30/month
Output
Product Name | Unit Price
---------------------------------------|-----------
Load Balancer - Standard - 1 Rule | 0.025
Load Balancer - Data Processed | 0.008
NAT Gateway - Basic | 0.045
NAT Gateway - Data Processed | 0.045
💡NAT Gateway vs LB Outbound
For high outbound traffic, use NAT Gateway instead of LB outbound rules. NAT Gateway provides more SNAT ports and better performance at similar cost.
📊 Production Insight
We reduced costs by 30% by moving from LB outbound rules to NAT Gateway for a microservices cluster. The SNAT port exhaustion issues also disappeared.
🎯 Key Takeaway
Optimize cost by consolidating rules, using NAT Gateway for outbound, and autoscaling backends.
Backend Pool Membership Types NIC-based vs IP-based membership comparison NIC-based IP-based Configuration Method Associate VM NIC directly Specify IP addresses manually Flexibility Tied to VM lifecycle Supports on-prem and containers Health Probe Support Automatic probe per NIC Manual probe per IP Scalability Limited to VM count Supports large IP pools Use Case Standard VM deployments Hybrid or containerized workloads THECODEFORGE.IO
thecodeforge.io
Azure Load Balancer

Migration from Basic to Standard SKU

If you're still on Basic SKU, migrate to Standard. Basic SKU is being deprecated and lacks features. Migration steps: 1) Create a new Standard SKU ALB in the same region. 2) Configure frontend IP, backend pool, probes, and rules matching the Basic LB. 3) Update DNS to point to the new LB's public IP. 4) Gradually shift traffic by updating application configurations. 5) Delete the old Basic LB. Important: Standard SKU requires explicit outbound rules; Basic had default outbound. Ensure you configure outbound rules before cutting over. Also, Standard SKU has different NSG requirements—it doesn't allow inbound traffic from the internet unless explicitly allowed. Test in a staging environment first. Use Azure Traffic Manager to perform a blue-green migration. During migration, monitor metrics to ensure no impact. Rollback plan: keep the Basic LB running until traffic is fully migrated. Note that Basic LB does not support availability zones, so if you need HA, you must redeploy backends across zones.

migrate.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Create Standard LB
az network lb create --resource-group prod-rg --name prod-lb-std --sku Standard --public-ip-address prod-pip-std

# Copy configuration from Basic LB
az network lb rule list --resource-group prod-rg --lb-name prod-lb-basic --query "[].{name:name, protocol:protocol, frontendPort:frontendPort, backendPort:backendPort}" -o json > rules.json

# Apply rules to Standard LB
for rule in $(cat rules.json | jq -c '.[]'); do
  name=$(echo $rule | jq -r '.name')
  protocol=$(echo $rule | jq -r '.protocol')
  frontendPort=$(echo $rule | jq -r '.frontendPort')
  backendPort=$(echo $rule | jq -r '.backendPort')
  az network lb rule create --resource-group prod-rg --lb-name prod-lb-std --name $name --protocol $protocol --frontend-port $frontendPort --backend-port $backendPort --frontend-ip-name frontend --backend-pool-name backend-pool --probe-name http-probe
done

# Update DNS
az network dns record-set a update --resource-group dns-rg --zone-name example.com --name www --set targetResource.id=/subscriptions/.../publicIPAddresses/prod-pip-std
Output
Migration completed. DNS updated to new Standard LB.
⚠ Outbound Connectivity
After migration, VMs may lose outbound internet access because Standard LB doesn't have default outbound. Create an outbound rule or use NAT Gateway before cutting over.
📊 Production Insight
We migrated a production Basic LB to Standard and forgot to configure outbound rules. VMs couldn't reach external APIs for 10 minutes. Now we have a pre-migration checklist that includes outbound rules.
🎯 Key Takeaway
Migrate from Basic to Standard SKU for features, SLA, and availability zones; plan outbound connectivity.
⚙ Quick Reference
12 commands from this guide
FileCommand / CodePurpose
create-alb.shaz network lb create \Azure Load Balancer
configure-backend-pool.shaz network lb address-pool create \Backend Pools
health-endpoint.pyfrom flask import Flask, jsonifyHealth Probes
create-lb-rule.shaz network lb rule create \Load Balancing Rules and Session Persistence
create-outbound-rule.shaz network lb outbound-rule create \Outbound Rules
zone-redundant-alb.shaz network public-ip create \High Availability
setup-alerts.shaz monitor metrics alert create \Monitoring and Diagnostics
troubleshoot.shaz network lb probe show \Troubleshooting Common Failures
main.tfresource "azurerm_lb" "prod" {Production Deployment with Infrastructure as Code
nsg-rules.shaz network nsg rule create \Security
cost-estimate.shaz consumption prices list \Cost Optimization and Performance Tuning
migrate.shaz network lb create --resource-group prod-rg --name prod-lb-std --sku Standard ...Migration from Basic to Standard SKU

Key takeaways

1
Stateless Layer 4 Forwarding
Azure Load Balancer distributes TCP/UDP traffic without inspecting payloads, ideal for high-throughput, low-latency workloads.
2
Health Probes Are Critical
Use HTTP probes with dependency checks and short intervals (5s) for fast failure detection; ensure NSG allows probe source IP 168.63.129.16.
3
SNAT Port Management
Monitor outbound connections; use multiple frontend IPs or NAT Gateway to avoid port exhaustion; set alerts at 70% utilization.
4
IaC and Security
Deploy with Terraform/Bicep for repeatability; secure with NSGs, DDoS Protection, and private endpoints; always use Standard SKU.

Common mistakes to avoid

3 patterns
×

Not planning load balancer properly before deployment

Fix
Design your architecture with redundancy, scaling, and security in mind from the start.
×

Ignoring Azure best practices for load balancer

Fix
Follow Microsoft's Well-Architected Framework and review Azure Advisor recommendations regularly.
×

Overlooking cost implications of load balancer

Fix
Set budgets and alerts, right-size resources, and use Azure pricing calculator before deploying.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
Explain Azure Load Balancer and its use cases.
Q02JUNIOR
How does Azure Load Balancer handle high availability?
Q03JUNIOR
What are the security best practices for load balancer?
Q04JUNIOR
How do you optimize costs for load balancer?
Q05JUNIOR
Compare Azure load balancer with self-hosted alternatives.
Q01 of 05JUNIOR

Explain Azure Load Balancer and its use cases.

ANSWER
Microsoft Azure — Azure Load Balancer is an Azure service for managing load balancer in the cloud. Use it when you need reliable, scalable load balancer without managing underlying infrastructure.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What is the difference between Azure Load Balancer and Application Gateway?
02
How do I troubleshoot unhealthy backend instances in Azure Load Balancer?
03
Can Azure Load Balancer handle WebSocket connections?
04
What is SNAT port exhaustion and how do I prevent it?
05
How do I achieve cross-region load balancing with Azure Load Balancer?
06
What are the key differences between Basic and Standard SKU of Azure Load Balancer?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Verified
production tested
July 12, 2026
last updated
436
articles · all by Naren
🔥

That's Azure. Mark it forged?

8 min read · try the examples if you haven't

Previous
Microsoft Azure — VNet Peering & VPN Gateway
19 / 55 · Azure
Next
Microsoft Azure — Application Gateway & WAF