Back

Azure Load Balancer as a Traffic Contract — A Clean Terraform Module Baseline

Using a Terraform Azure Load Balancer Module as a Clean Baseline

This article shows how to use a Terraform Azure Load Balancer module to define an explicit traffic contract between the public edge and independently managed backend virtual machines.

Azure Load Balancer is often introduced too late in the infrastructure lifecycle — after virtual machines already exist, after ports are opened, after someone says “let’s just test connectivity first”.

In production architectures, this order leads to unclear traffic boundaries and implicit assumptions about routing and availability.

This article intentionally takes a different approach.

The goal of this example is not high availability tuning, autoscaling, or feature completeness.
It focuses on one core concept:

A Load Balancer is a separate Azure resource that defines a traffic contract between the public edge and independently managed compute instances.

What this example is — and what it is not

Before looking at Terraform, it is important to understand the scope.

What this example focuses on

  • an explicit public traffic entry point

  • explicit backend membership

  • an explicit health contract

  • no hidden coupling between compute and traffic

What this example intentionally avoids

  • ❌ autoscaling

  • ❌ availability zones discussion

  • ❌ Application Gateway / WAF

  • ❌ TLS termination

  • ❌ portal-driven configuration

This is a foundation pattern, not a feature showcase.

If you’re looking for a low-level walkthrough using raw Terraform resources, see
Azure Load Balancer with Terraform — using raw resources.

This article builds on top of that foundation by wrapping the Load Balancer into a reusable, contract-first Terraform module.

Architecture overview

The deployment consists of a minimal but complete traffic path from the public internet to private backend compute.

The architecture includes:

  • One Virtual Network with a private subnet

  • Multiple Linux Virtual Machines acting as backend instances

  • One Public Azure Load Balancer (Standard SKU)

  • One public frontend IP

  • One backend address pool with VM NICs attached

  • One TCP health probe

  • One load balancing rule (TCP/80 → TCP/80)

Each backend VM runs an identical NGINX service but remains an independent compute unit.

The Load Balancer does not “own” compute.
It only routes traffic according to an explicit contract.

Terraform Azure Load Balancer module — public load balancer routing traffic to multiple backend virtual machines

Figure 1. Public Azure Load Balancer distributing inbound traffic to multiple backend Virtual Machines.

The Load Balancer as a traffic boundary

In this baseline, the Load Balancer is treated as a traffic boundary, not a convenience feature.

It answers three explicit questions:

  1. Where does traffic enter the platform?

  2. Which backends are eligible to receive traffic?

  3. Under what conditions is traffic routed?

All three answers are declared in Terraform.

Using the terraform-az-fk-loadbalancer module

At the center of this example is the terraform-az-fk-loadbalancer module.
The entire Load Balancer configuration is expressed through a small, explicit interface.

module "loadbalancer" {
  source = "github.com/foggykitchen/terraform-az-fk-loadbalancer"

  name                = "fk-public-lb"
  resource_group_name = azurerm_resource_group.foggykitchen_rg.name
  location            = azurerm_resource_group.foggykitchen_rg.location

  public_lb = true

  probe = {
    name                = "http-health-probe"
    protocol            = "Tcp"
    port                = 80
    interval_in_seconds = 5
    number_of_probes    = 2
  }

  rule = {
    name          = "http-rule"
    protocol      = "Tcp"
    frontend_port = 80
    backend_port  = 80
  }
}

This block is intentionally small — but every attribute has architectural meaning.

Public edge selection

The flag:

public_lb = true

explicitly declares that this Load Balancer represents a public edge.

There is no ambiguity about where inbound traffic enters the platform.
The public IP exists solely to expose the Load Balancer — not the backend VMs.

Health probes define routing eligibility

The probe configuration is not monitoring.

It is a routing gate.

probe = {
  name                = "http-health-probe"
  protocol            = "Tcp"
  port                = 80
  interval_in_seconds = 5
  number_of_probes    = 2
}

Only backend instances that satisfy this probe are considered eligible to receive traffic.

If a backend VM stops responding on TCP/80:

  • it is removed from the routing path

  • traffic is not sent “best effort”

  • no additional logic is required

Health probes are not observability tools.
They define who is allowed to receive traffic.

Load balancing rules as an explicit contract

The rule configuration defines the public contract of the service:

rule = {
  name          = "http-rule"
  protocol      = "Tcp"
  frontend_port = 80
  backend_port  = 80
}

There are no implicit ports.
There is no hidden protocol translation.

The rule explicitly states:

  • which protocol is accepted

  • which frontend port is exposed

  • which backend port is targeted

This clarity is intentional.

Backend independence

One of the most important design choices in this baseline is decoupling compute from traffic.

Backend Virtual Machines:

  • are created independently

  • are managed independently

  • do not “belong” to the Load Balancer

Traffic routing is achieved by attaching NICs to the backend address pool.

This means:

  • compute can be replaced without redefining the edge

  • traffic policy remains stable

  • responsibilities stay separated

The Load Balancer routes traffic to independently managed compute instances — nothing more, nothing less.

Validation and behavior

After tofu apply:

  • the public IP responds on TCP/80

  • refreshing the page returns responses from different backend VMs

  • stopping NGINX on one VM removes it from routing within seconds

No autoscaling.
No orchestration.
Just explicit contracts.

Why this belongs in Azure Foundations

This pattern is often skipped or abstracted away — and that is a mistake.

Without an explicit Load Balancer:

  • private compute becomes unreachable or incorrectly exposed

  • routing rules become implicit

  • health semantics are unclear

This is why Load Balancer configuration belongs in Azure Foundations, not only in “advanced networking”.

Everything built later — autoscaling, zonal architectures, Application Gateway, AKS ingress — builds on top of this contract.
They do not replace it.

👉 See the full Azure infrastructure with Terraform architecture model: Azure Infrastructure with Terraform – Architecture Model

Closing thoughts

This example intentionally stays minimal.

Not because Azure Load Balancer is simple —
but because foundations should be.

By expressing the traffic boundary explicitly through a Terraform module, the architecture becomes:

  • predictable

  • reviewable

  • composable

And most importantly: understandable.

Azure Load Balancer behavior and limitations are documented in the official Microsoft documentation.

Explore more Azure Foundation patterns

🔹 Networking foundation

Azure Virtual Network as an Isolation Boundary (Terraform)

How a purpose-driven Terraform module terraform-az-fk-vnet defines Azure VNet intent, subnet boundaries, and future workload placement.

🔹 Compute foundation

Private Azure Virtual Machines with Terraform (No Public IPs) 

Building a private Azure compute foundation using the terraform-az-fk-compute module, with explicit VM, NIC, and Load Balancer attachment responsibilities.

🔹 Storage foundation

Azure Storage with Private Endpoint — A Clean Terraform Baseline 

Building a private Azure storage foundation using the terraform-az-fk-storage module, with Private Endpoint, Private DNS, and explicit data access paths.

🔹 Traffic / edge

Azure Load Balancer with Terraform — Using Raw Resources

A pre-module, low-level walkthrough using raw Terraform resources, originally part of the Multicloud Foundations series, showing the same traffic contract before abstraction.

azure fundamentals terraform course architecture diagram with vnet subnets private endpoints and compute

From Load Balancer to Real Azure Traffic Architecture

This example shows how traffic is distributed across backend workloads — but real Azure platforms require consistent traffic design across networking, compute, and storage.
Load Balancer is a core building block of production-grade Azure architectures.

🔒 Lifetime • ⚙️ Networking & Compute Labs • 🧠 Architecture-first

Check also other courses:​

Leave A Reply

Build Real Azure Architecture with Terraform / OpenTofu

Learn how to design, provision, and evolve Azure platforms step by step — starting from networking, through compute and storage, to private connectivity.

No portals. No shortcuts. Just real, production-ready architecture.

🎓 What you’ll learn:
- Virtual Network design and subnet architecture
- Compute patterns (VMs, Load Balancers, scaling)
- Storage layers (Blob, File, Disks)
- Private connectivity (Private Endpoints, DNS, NAT Gateway)

azure fundamentals terraform course architecture diagram with vnet subnets private endpoints and compute