This project provisions a scalable Azure environment using modular Bicep templates — deploying multiple Linux VMs behind a Load Balancer, each configured with NGINX via Custom Script Extension.
✅ Virtual Network + Subnet + Network Security Group (NSG)
✅ Azure Load Balancer (Standard SKU) with TCP probe and rule
✅ Static Public IP for Load Balancer frontend
✅ Two Ubuntu 22.04 LTS Linux Virtual Machines
✅ Custom Script Extension to install and configure NGINX
✅ Load-balanced web access with hostname-based response
iac-hands-on-3/
├── main.bicep # Orchestrates all module deployments
├── parameters.json # Input parameters (e.g., SSH public key)
├── scripts/
│ └── install-nginx.sh # Script executed on each VM
├── modules/
│ ├── network.bicep # VNet, Subnet, NSG
│ ├── loadbalancer.bicep # Public IP + LB + probe + rule
│ └── vm-multi.bicep # Multiple Linux VMs with extensions
├── README.md # Project documentation
└── CHANGELOG.md # Version historyBefore you start:
Ensure you have the Azure CLI installed and logged in (az login)
Make sure your parameters.json file contains a valid SSH public key
Run this command from the root of the project:
az deployment group create \
--resource-group rg-iac-lab \
--template-file main.bicep \
--parameters @parameters.jsonAfter deployment, access the public IP output from the deployment:
curl http://<public-ip>You should see a custom NGINX page showing the instance name (e.g., nginxvm-0, nginxvm-1), confirming load balancing is working.
Password login is disabled
Only SSH public key authentication is allowed
NSG allows only TCP ports 22 (SSH) and 80 (HTTP)
No public IPs are assigned to individual VMs
This project uses parameters.json, which is ignored by Git. Clone the example file below to provide your own inputs:
cp parameters.example.json parameters.jsonAzure Bicep (modular architecture)
Azure CLI
Ubuntu Server 22.04 LTS
NGINX via Custom Script Extension
Azure Load Balancer (Standard SKU)
SSH key authentication
MIT License