Public IPs, Load Balancers & NAT Gateway
Why this matters
This module covers how traffic gets in to a set of backends (public IP + Load Balancer) and how it gets out to the internet in a controlled way (NAT Gateway). The Azure Load Balancer is your L4 load balancer from track 1, and its health-probe behavior is the single most common cause of "my backends show unhealthy and nothing works" — you'll break and fix exactly that. These are also the first resources in this track that bill hourly, so cleanup starts mattering for real here.
Concepts
Public IPs and SKUs
A public IP is a separate Azure resource you attach to something (a Load Balancer frontend, a NAT Gateway, a VM NIC). It comes in Basic and Standard SKUs and Dynamic or Static allocation. Use Standard + Static for anything real: Standard is zone-redundant, secure-by-default (no inbound unless an NSG allows it), and is required by Standard Load Balancer and NAT Gateway. Basic SKU is on a deprecation path — don't build on it. Standard public IPs bill a small hourly rate even when idle.
Azure Load Balancer (L4)
The Azure Load Balancer is Azure's implementation of the L4 (TCP/UDP) load balancer from track 1: it distributes flows across a backend pool using a hashing algorithm, operating at the transport layer with no awareness of HTTP. It has four building blocks: a frontend (the IP clients hit — public or internal), a backend pool (the NICs/IPs receiving traffic), a health probe (how it decides a backend is alive), and load-balancing rules (which frontend port maps to which backend port for which pool/probe). For HTTP-aware features (path routing, TLS termination, WAF) you need Application Gateway (module 06), not this.
Health probes decide everything
A load-balancing rule only sends traffic to backends the health probe
considers healthy. A probe defines a protocol (TCP/HTTP/HTTPS), a port, an
interval, and (for HTTP) a request path expecting a 200 response. If the probe
targets a port nothing is listening on, or an HTTP path that returns non-200,
or if an NSG blocks the probe's source, every backend shows unhealthy and the
LB sends no traffic — even though the backends are fine. Probes originate
from Azure's infrastructure IP 168.63.129.16, so your NSG must allow the
AzureLoadBalancer service tag inbound (the default rule does this).
Internal vs public load balancers
A Load Balancer frontend can be a public IP (internet-facing) or a private IP inside a subnet (internal load balancer, ILB). An ILB spreads internal traffic — e.g. an app tier balancing across a data tier — without exposing anything publicly. Same probe/rule model, different frontend.
NAT Gateway for outbound
By default VMs get outbound internet via implicit SNAT, but that default is unpredictable and being retired for new deployments. A NAT Gateway is the recommended, explicit way to give a subnet outbound internet: you attach it to the subnet, give it a Standard public IP, and all outbound flows from that subnet source-NAT through it with a large, stable pool of SNAT ports. It's outbound-only (it never allows unsolicited inbound) and bills hourly plus per GB processed. This is the "controlled source NAT for egress" idea from track 1.
Command reference
| Command | What it does | Example |
|---|---|---|
az network public-ip create |
Creates a public IP | az network public-ip create -g lb-lab-rg -n lb-pip --sku Standard --allocation-method Static |
az network lb create |
Creates a Load Balancer with a frontend + backend pool | az network lb create -g lb-lab-rg -n web-lb --sku Standard --public-ip-address lb-pip --frontend-ip-name fe --backend-pool-name bepool |
az network lb probe create |
Creates a health probe | az network lb probe create -g lb-lab-rg --lb-name web-lb -n http-probe --protocol Http --port 80 --path / |
az network lb rule create |
Creates a load-balancing rule | az network lb rule create -g lb-lab-rg --lb-name web-lb -n http-rule --protocol Tcp --frontend-port 80 --backend-port 80 --frontend-ip-name fe --backend-pool-name bepool --probe-name http-probe |
az network lb show |
Shows LB config | az network lb show -g lb-lab-rg -n web-lb |
az network nat gateway create |
Creates a NAT Gateway | az network nat gateway create -g lb-lab-rg -n egress-nat --public-ip-addresses nat-pip --idle-timeout 10 |
az network vnet subnet update |
Attaches a NAT Gateway to a subnet | az network vnet subnet update -g lb-lab-rg --vnet-name lab-vnet -n app-subnet --nat-gateway egress-nat |
Flag breakdown — az network public-ip create -g lb-lab-rg -n lb-pip --sku Standard --allocation-method Static:
--sku:Standard(recommended) orBasic(deprecated).--allocation-method:Static(fixed IP) orDynamic. Standard SKU is effectively static.
Flag breakdown — az network lb rule create ... -n http-rule --protocol Tcp --frontend-port 80 --backend-port 80 --frontend-ip-name fe --backend-pool-name bepool --probe-name http-probe:
--protocol: transport protocol (Tcp/Udp).--frontend-port: the port clients connect to on the frontend IP.--backend-port: the port traffic is delivered to on backends.--frontend-ip-name: which frontend config this rule uses.--backend-pool-name: which backend pool receives the traffic.--probe-name: the health probe that gates this rule — no healthy probe, no traffic.
Flag breakdown — az network lb probe create ... -n http-probe --protocol Http --port 80 --path /:
--protocol:Tcp,Http, orHttps.--port: the port the probe connects to on backends.--path: for HTTP/HTTPS, the URL path that must return 200 (invalid for TCP probes — a common misconfiguration).
Flag breakdown — az network nat gateway create ... -n egress-nat --public-ip-addresses nat-pip --idle-timeout 10:
--public-ip-addresses: the Standard public IP(s) the NAT Gateway SNATs through.--idle-timeout: minutes before an idle outbound flow is dropped (4–120).
Hands-on exercises
Set up a group and a VNet:
az group create --name lb-lab-rg --location eastus
az network vnet create -g lb-lab-rg -n lab-vnet \
--address-prefixes 10.0.0.0/16 \
--subnet-name app-subnet --subnet-prefixes 10.0.1.0/24
Create a Standard static public IP.
az network public-ip create -g lb-lab-rg -n lb-pip \ --sku Standard --allocation-method StaticVerify:
az network public-ip show -g lb-lab-rg -n lb-pip --query ipAddressreturns an assigned address. (This IP now bills hourly.)Create a Standard Load Balancer with a frontend and backend pool.
az network lb create -g lb-lab-rg -n web-lb --sku Standard \ --public-ip-address lb-pip \ --frontend-ip-name fe --backend-pool-name bepoolVerify:
az network lb show -g lb-lab-rg -n web-lb -o tableshows the LB; it has a frontend and an (empty) backend pool.Add an HTTP health probe.
az network lb probe create -g lb-lab-rg --lb-name web-lb \ -n http-probe --protocol Http --port 80 --path /Add a load-balancing rule.
az network lb rule create -g lb-lab-rg --lb-name web-lb -n http-rule \ --protocol Tcp --frontend-port 80 --backend-port 80 \ --frontend-ip-name fe --backend-pool-name bepool --probe-name http-probeVerify:
az network lb rule list -g lb-lab-rg --lb-name web-lb -o tableshowshttp-rulereferencinghttp-probe.Add backends. In a full lab you'd create two small VMs running a web server on port 80 and add their NICs to
bepool(viaaz network nic ip-config address-pool add). If you want the full effect, create two VMs now; otherwise reason through the probe behavior in the next exercises. Backends are where the real cost is, so keep them tiny (e.g.Standard_B1s) and short-lived.Diagnose and fix: backends show unhealthy (probe misconfiguration). This is the flagship failure. Suppose your web server actually listens on port 8080, not 80, but your probe targets port 80. The probe fails, all backends show unhealthy, and the LB delivers no traffic even though the app is running. Diagnose: the LB frontend IP times out; the backend pool health shows all-down; the app responds fine if you hit a backend's private IP:8080 directly. The mismatch is probe port vs. listening port. Fix: point the probe (and rule backend port) at the real port:
az network lb probe update -g lb-lab-rg --lb-name web-lb \ -n http-probe --port 8080 az network lb rule update -g lb-lab-rg --lb-name web-lb \ -n http-rule --backend-port 8080Verify: after the probe interval, backend health flips to healthy and the frontend IP starts serving. Lesson: an LB only sends traffic to probe-healthy backends; a probe pointed at the wrong port fails silently and looks like a total outage. (A second common variant: a TCP probe is fine, but an HTTP probe with
--path /healthreturns 404 because the app has no/healthroute — same symptom, fix the path or the app.)Create a NAT Gateway for controlled egress.
az network public-ip create -g lb-lab-rg -n nat-pip \ --sku Standard --allocation-method Static az network nat gateway create -g lb-lab-rg -n egress-nat \ --public-ip-addresses nat-pip --idle-timeout 10 az network vnet subnet update -g lb-lab-rg --vnet-name lab-vnet \ -n app-subnet --nat-gateway egress-natVerify:
az network vnet subnet show ... -n app-subnet --query natGatewayreferencesegress-nat. Now all outbound traffic fromapp-subnetSNATs throughnat-pip— from a VM in the subnet,curl ifconfig.mewould returnnat-pip's address.Diagnose and fix: no outbound after removing default outbound. Standard Load Balancer does not provide default outbound SNAT to its backends the way Basic did. If a VM in a Standard-LB backend pool has no NAT Gateway, no instance-level public IP, and no outbound rule, it may have no internet egress at all (secure-by-default). Symptom:
curlfrom the VM hangs. Fix: attach a NAT Gateway to the subnet (as in exercise 7) — the recommended modern pattern — rather than relying on implicit SNAT.Cleanup (important — these bill hourly). The public IPs, Load Balancer, NAT Gateway, and any VMs all cost money. Delete the whole group:
az group delete --name lb-lab-rg --yes --no-waitVerify: after a few minutes,
az group show -n lb-lab-rgreturns not-found. Don't leave this lab running overnight.
Independent challenge
Combine this module with module 02 (NSGs). Stand up a Standard Load
Balancer with a public frontend and a backend pool of two tiny VMs serving a
page on port 80. Put an NSG on the subnet. First, deliberately misconfigure it
so the health probe is blocked (remove/deny the AzureLoadBalancer inbound
allowance) and observe all backends going unhealthy; then fix the NSG so probes
and client traffic both flow, and confirm the frontend IP serves the page.
Articulate the difference between "the probe can't reach the backend" and "the
probe reaches a backend that returns the wrong status." Tear the whole resource
group down the moment you're done — every piece here bills hourly.
Stuck? One hint
Health probes come from the Azure infrastructure address 168.63.129.16,
covered by the AzureLoadBalancer service tag. If your NSG's custom rules
override the default AllowAzureLoadBalancerInBound, the probe can't reach the
backend and everything shows unhealthy — distinct from a probe that does
reach the backend but gets a non-200/closed-port response. Check the NSG with
az network watcher test-ip-flow using 168.63.129.16 as the remote source.
Common mistakes & troubleshooting
- Probe port/path mismatch. The number-one LB failure: probe points at a port nothing listens on, or an HTTP path that isn't 200. All backends go unhealthy and it looks like a full outage.
- NSG blocking the probe. Overriding
AllowAzureLoadBalancerInBound(or denying168.63.129.16) kills health checks. Backends fine, probe blocked. - Assuming Standard LB gives outbound by default. It doesn't. Add a NAT Gateway (or outbound rule / instance public IP) for egress.
- Mixing Basic and Standard SKUs. A Standard LB needs a Standard public IP; Basic and Standard don't interoperate cleanly. Standardize on Standard.
- Expecting L7 features from the LB. No TLS termination, no path routing, no host-based routing — that's Application Gateway (module 06).
- Cost pitfall: Standard public IPs, the Load Balancer, and the NAT
Gateway all bill hourly, and VMs bill for compute + disk. This is the first
module where forgetting
az group deletegenuinely costs money. Delete promptly.
Checkpoint quiz
Write down your answer to each question before expanding it — checking without attempting first is the single easiest way to fool yourself into thinking you've learned this.
- Your Load Balancer's frontend IP times out and all backends show unhealthy, but hitting a backend's private IP on the app port works fine. Name two distinct causes and how you'd tell them apart.
- Which OSI layer does Azure Load Balancer operate at, and name two things it therefore cannot do that Application Gateway can.
- What are the four building blocks of an Azure Load Balancer?
- Why might a VM behind a Standard Load Balancer have no outbound internet access, and what's the recommended fix?
- From what source IP do health probes originate, and which service tag / default NSG rule must permit them?
- What does a NAT Gateway do, is it inbound or outbound, and how does it bill?
- Why should you use Standard + Static public IPs rather than Basic + Dynamic?
Show answers
- (a) Probe misconfiguration — probe port/path doesn't match what the app
serves (fix the probe). (b) NSG blocking the probe source
(
168.63.129.16/AzureLoadBalancertag). Tell them apart withaz network watcher test-ip-flowfrom the probe source, and by checking whether the probe port matches the listening port. - Layer 4 (transport). It can't terminate TLS, do HTTP path/host-based routing, or apply a WAF — those are L7 (App Gateway).
- Frontend IP configuration, backend pool, health probe, and load-balancing rule(s).
- Standard LB provides no default outbound SNAT (secure by default). Add a NAT Gateway to the subnet (recommended), or an outbound rule / instance public IP.
168.63.129.16, permitted by theAzureLoadBalancerservice tag via the defaultAllowAzureLoadBalancerInBoundrule.- It provides controlled, scalable outbound (SNAT) internet access for a subnet; it is outbound-only (no unsolicited inbound); it bills hourly plus per-GB processed.
- Standard is zone-redundant, secure-by-default, static, and required by Standard LB and NAT Gateway; Basic is deprecated and Dynamic IPs can change.
Next
05 — VNet peering & Private Endpoints: connect VNets over Azure's backbone and reach PaaS services on private IPs.