π Project Structure
The Terraform project consists of the following files:
azure-linuxvm-nsg-nginx-demo/
βββ main.tf # Main infrastructure definitions
βββ variables.tf # Input variable declarations
βββ terraform.tfvars # Variable values (location, credentials, etc.)
βββ outputs.tf # Outputs like public IP
βββ startup-script.sh # Bash script to install and enable nginx
Each file serves a specific purpose to keep the project modular, secure, and easy to manage.
π§ Terraform Configuration Breakdown
This section explains each component used in the deployment.
1. Resource Group
resource "azurerm_resource_group" "rg" {
name = var.resource_group_name
location = var.location
}
π‘ Creates a container to hold all related Azure resources.
2. Virtual Network and Subnet
resource "azurerm_virtual_network" "vnet" {
name = "vnet-demo"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "subnet" {
name = "subnet-demo"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.1.0/24"]
}
π‘ Defines the internal network where the VM will reside.
3. Public IP Address
resource "azurerm_public_ip" "public_ip" {
name = "public-ip-demo"
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Dynamic"
}
π‘ Allows the VM to be accessible from the internet.
4. Network Security Group (NSG)
resource "azurerm_network_security_group" "nsg" {
name = "nsg-demo"
location = var.location
resource_group_name = var.resource_group_name
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "HTTP"
priority = 1002
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
π‘ Allows traffic to ports 22 (SSH) and 80 (HTTP) from any IP.
5. Network Interface + NSG Binding
resource "azurerm_network_interface" "nic" {
name = "nic-demo"
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "ipconfig"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.public_ip.id
}
network_security_group_id = azurerm_network_security_group.nsg.id
}
π‘ Binds the NIC to the subnet and NSG. Associates a public IP.
---
### 6. Startup Script: `startup-script.sh`
bash
!/bin/bash
sudo apt-get update
sudo apt-get install -y nginx
sudo systemctl start nginx
sudo systemctl enable nginx
π‘ This script installs and starts nginx automatically when the VM is created.
- Linux Virtual Machine resource "azurerm_linux_virtual_machine" "vm" { name = var.vm_name location = var.location resource_group_name = var.resource_group_name network_interface_ids = [azurerm_network_interface.nic.id] size = "Standard_B1s" admin_username = var.admin_username admin_password = var.admin_password disable_password_authentication = false
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
name = "osdisk-demo"
}
computer_name = "demo-vm"
provision_vm_agent = true
custom_data = base64encode(file("startup-script.sh"))
}
π‘ This creates a Linux VM and runs the startup script to configure the web server.
- Outputs output "resource_group_name" { value = azurerm_resource_group.rg.name }
output "public_ip_address" {
value = azurerm_public_ip.public_ip.ip_address
}
π‘ After deployment, these outputs help you identify the resource group and access the VM.
β Conclusion
With just a few Terraform files, we successfully deployed:
- A secure Linux Virtual Machine on Azure
- A fully working nginx web server
- Automated provisioning via a startup script
- Public access through a dynamically assigned IP address
This approach demonstrates the power of Infrastructure as Code (IaC) and how easily repeatable environments can be created using Terraform.
π¦ GitHub Repository
You can find the full source code for this project here:
π https://github.com/Smallsun2025/azure-linuxvm-nsg-nginx-demo
βοΈ Feel free to star, fork, or leave feedback!
π§ Coming Next
In future posts, Iβll walk through:
- Creating Azure VM images with Packer + Terraform
- Setting up 3-tier architecture with Load Balancer
- Using Terraform Cloud for remote state & collaboration
Follow for more Azure automation tips!
Top comments (0)