<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Smallsun2025</title>
    <description>The latest articles on Forem by Smallsun2025 (@smallsun2025).</description>
    <link>https://forem.com/smallsun2025</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3205819%2F54e303d9-afbd-49c9-8def-92686bc71799.png</url>
      <title>Forem: Smallsun2025</title>
      <link>https://forem.com/smallsun2025</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/smallsun2025"/>
    <language>en</language>
    <item>
      <title>Create and Assign a Custom Role in Azure Using Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Mon, 21 Jul 2025 13:35:26 +0000</pubDate>
      <link>https://forem.com/smallsun2025/create-and-assign-a-custom-role-in-azure-using-terraform-11k2</link>
      <guid>https://forem.com/smallsun2025/create-and-assign-a-custom-role-in-azure-using-terraform-11k2</guid>
      <description>&lt;p&gt;🧭 Introduction&lt;br&gt;
In today's post, we’ll explore how to create a custom role in Azure using Terraform and assign it to a specific resource group. This is a critical step toward managing fine-grained permissions in enterprise-grade Azure deployments.&lt;/p&gt;

&lt;p&gt;Whether you're building production systems or just learning Infrastructure as Code (IaC), this project gives you a practical look at customizing access control with Terraform.&lt;br&gt;
🗂 Project Structure&lt;br&gt;
Here’s a quick look at the project files:&lt;br&gt;
azure-custom-role-assignment/&lt;br&gt;
├── main.tf               # Define custom role + assignment&lt;br&gt;
├── variables.tf          # Input variables&lt;br&gt;
├── terraform.tfvars      # Variable values&lt;br&gt;
├── outputs.tf            # Outputs (like Role Definition ID)&lt;br&gt;
🔧 What the Terraform Code Does&lt;br&gt;
Creates a Custom Role using azurerm_role_definition&lt;br&gt;
The role is defined in JSON format and includes permissions like Microsoft.Resources/subscriptions/resourceGroups/*.&lt;/p&gt;

&lt;p&gt;Assigns the Role to a user, group, or service principal using azurerm_role_assignment.&lt;/p&gt;

&lt;p&gt;Scopes the Role Assignment to a specific resource group for tight access control.&lt;br&gt;
🚀 How to Deploy&lt;br&gt;
Make sure you have:&lt;/p&gt;

&lt;p&gt;✅ Azure CLI (az login)&lt;/p&gt;

&lt;p&gt;✅ Terraform installed&lt;/p&gt;

&lt;p&gt;Then follow these steps:&lt;/p&gt;

&lt;p&gt;terraform init&lt;br&gt;
terraform plan&lt;br&gt;
terraform apply&lt;/p&gt;

&lt;p&gt;When prompted, type yes.&lt;/p&gt;

&lt;p&gt;After deployment, your custom role will be created and assigned — scoped to the resource group you specified.&lt;/p&gt;

&lt;p&gt;🔍 Example Use Case&lt;br&gt;
Let’s say you want to grant read-only access to a service principal but only within a specific resource group, not across the whole subscription. This setup enables that — all in one Terraform script!&lt;/p&gt;

&lt;p&gt;✅ Conclusion&lt;br&gt;
Custom roles are a powerful way to enforce principle of least privilege in Azure. With just a few lines of Terraform, you can define exactly what actions are permitted, where, and by whom.&lt;/p&gt;

&lt;p&gt;This example helps solidify your understanding of:&lt;/p&gt;

&lt;p&gt;Role Definition JSON structure&lt;/p&gt;

&lt;p&gt;Role Assignment best practices&lt;/p&gt;

&lt;p&gt;Scoped access control via Terraform&lt;/p&gt;

&lt;p&gt;🔜 Coming Next...&lt;br&gt;
Managing Key Vault secrets via Terraform&lt;/p&gt;

&lt;p&gt;Building reusable modules for RBAC policies&lt;/p&gt;

&lt;p&gt;Advanced Role Assignments using Azure AD groups&lt;/p&gt;

&lt;p&gt;If you found this useful, feel free to ⭐ the repo and share your thoughts in the comments!&lt;/p&gt;

&lt;p&gt;📝 Ready to post on Dev.to&lt;br&gt;
📦 Repo name suggestion: azure-custom-role-assignment&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy Azure Load Balancer and Virtual Machines using Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Sat, 12 Jul 2025 12:12:38 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-azure-load-balancer-and-virtual-machines-using-terraform-4gpk</link>
      <guid>https://forem.com/smallsun2025/deploy-azure-load-balancer-and-virtual-machines-using-terraform-4gpk</guid>
      <description>&lt;p&gt;📘 Post Content&lt;/p&gt;

&lt;h1&gt;
  
  
  🚀 Deploy Azure Load Balancer and Virtual Machines using Terraform
&lt;/h1&gt;

&lt;p&gt;In this blog, I’ll demonstrate how to use Terraform to deploy a basic Azure infrastructure including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A resource group&lt;/li&gt;
&lt;li&gt;A virtual network and subnet&lt;/li&gt;
&lt;li&gt;Two Windows virtual machines&lt;/li&gt;
&lt;li&gt;A public Load Balancer with a backend pool and health probe&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔧 Files Overview
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines all resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;variables.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Declares variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terraform.tfvars&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets variable values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputs.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Outputs the public IP of Load Balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  📂 &lt;code&gt;main.tf&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
hcl
provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = var.location
}

resource "azurerm_virtual_network" "vnet" {
  name                = "example-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_subnet" "subnet" {
  name                 = "example-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}

resource "azurerm_network_interface" "nic" {
  count               = 2
  name                = "example-nic-${count.index}"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_windows_virtual_machine" "vm" {
  count               = 2
  name                = "example-vm-${count.index}"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name
  size                = "Standard_B1s"
  admin_username      = var.admin_username
  admin_password      = var.admin_password
  network_interface_ids = [azurerm_network_interface.nic[count.index].id]

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2019-Datacenter"
    version   = "latest"
  }
}

resource "azurerm_public_ip" "lb_public_ip" {
  name                = "example-lb-pip"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name
  allocation_method   = "Static"
  sku                 = "Basic"
}

resource "azurerm_lb" "lb" {
  name                = "example-lb"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name
  sku                 = "Basic"

  frontend_ip_configuration {
    name                 = "PublicIPAddress"
    public_ip_address_id = azurerm_public_ip.lb_public_ip.id
  }
}

resource "azurerm_lb_backend_address_pool" "bepool" {
  name                = "backend-pool"
  resource_group_name = azurerm_resource_group.rg.name
  loadbalancer_id     = azurerm_lb.lb.id
}

resource "azurerm_lb_probe" "probe" {
  name                = "http-probe"
  resource_group_name = azurerm_resource_group.rg.name
  loadbalancer_id     = azurerm_lb.lb.id
  protocol            = "Tcp"
  port                = 80
}

resource "azurerm_lb_rule" "lbrule" {
  name                           = "http-rule"
  resource_group_name            = azurerm_resource_group.rg.name
  loadbalancer_id                = azurerm_lb.lb.id
  protocol                       = "Tcp"
  frontend_port                  = 80
  backend_port                   = 80
  frontend_ip_configuration_name = "PublicIPAddress"
  backend_address_pool_id        = azurerm_lb_backend_address_pool.bepool.id
  probe_id                       = azurerm_lb_probe.probe.id
}



📂 variables.tf
variable "location" {
  description = "Azure region"
  default     = "japaneast"
}

variable "resource_group_name" {
  description = "Resource Group name"
}

variable "admin_username" {
  description = "VM admin username"
}

variable "admin_password" {
  description = "VM admin password"
  sensitive   = true
}

📂 terraform.tfvars
resource_group_name = "rg-lb-vm-demo"
admin_username      = "azureuser"
admin_password      = "P@ssw0rd1234!"

📂 outputs.tf

output "public_ip" {
  value = azurerm_public_ip.lb_public_ip.ip_address
}

▶️ Deploy Steps
1.Open terminal and navigate to your project folder

2.Initialize Terraform:
terraform init

3.Preview the plan:
terraform plan

4.Apply the configuration:
terraform apply
Once the deployment is done, Terraform will output a public IP. You can access this in your browser to test the Load Balancer after setting up web services on each VM.

✅ What’s Next
In the next post, I’ll show how to automatically install Nginx or IIS on the VM using remote-exec provisioner, so the VMs will instantly become web servers after deployment.

Stay tuned!
Thanks for reading 🙌
If you liked this article, feel free to ⭐️ the repo or leave a comment!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
    </item>
    <item>
      <title>Create Azure Managed Image with Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Sun, 06 Jul 2025 12:21:21 +0000</pubDate>
      <link>https://forem.com/smallsun2025/create-azure-managed-image-with-terraform-4g3h</link>
      <guid>https://forem.com/smallsun2025/create-azure-managed-image-with-terraform-4g3h</guid>
      <description>&lt;h1&gt;
  
  
  Automate Managed Image Creation from Windows VM with Terraform on Azure
&lt;/h1&gt;

&lt;p&gt;📌 &lt;strong&gt;1. Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Creating a reusable VM image is a key part of cloud infrastructure workflows. In this tutorial, we’ll use Terraform to automate the process of deploying a Windows Virtual Machine (VM), preparing it with necessary configurations, and capturing a Managed Image from it. This is especially useful for building base images for application servers or golden images for dev/test environments.&lt;/p&gt;

&lt;p&gt;📁 &lt;strong&gt;2. Project Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The repository contains the following Terraform files:&lt;br&gt;
azure-windows-image/&lt;br&gt;
├── main.tf # Core resource definitions&lt;br&gt;
├── variables.tf # Input variables&lt;br&gt;
├── terraform.tfvars # Actual variable values&lt;br&gt;
├── outputs.tf # Outputs like image ID&lt;br&gt;
├── sysprep-guide.txt # Reminder on how to generalize VM&lt;/p&gt;

&lt;p&gt;🔧 &lt;strong&gt;3. Terraform Code Breakdown&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This Terraform configuration includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource Group&lt;/strong&gt; – a container for all related Azure resources
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Network &amp;amp; Subnet&lt;/strong&gt; – basic network setup
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows Virtual Machine&lt;/strong&gt; – used as the base image
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managed Image Resource&lt;/strong&gt; – created from the generalized VM disk
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startup script (optional)&lt;/strong&gt; – to configure software before capturing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key snippet to define a managed image:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
hcl
resource "azurerm_image" "managed_image" {
  name                = var.image_name
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  os_disk {
    os_type  = "Windows"
    os_state = "Generalized"
    blob_uri = azurerm_virtual_machine.vm.storage_os_disk[0].vhd_uri
    caching  = "ReadWrite"
  }
}

📦 4. Deployment Steps

1.Login to Azure CLI
az login

2.Initialize Terraform
terraform init

3.Review the execution plan
terraform plan

4.Apply the configuration
terraform apply

5.Generalize the VM using sysprep
Log in to the VM using RDP and run:
C:\Windows\System32\Sysprep\Sysprep.exe /oobe /generalize /shutdown
This will shut down and prepare the VM for image capture.

6.Run apply again to capture image
After the VM is generalized and shut down:
terraform apply -auto-approve


7.Get the image output
Terraform will output the image ID or name, which can be used for future VM creation.

✅ 5. Conclusion

With a few lines of Terraform and a bit of sysprep preparation, you’ve successfully created a reusable Windows managed image on Azure. This is an essential skill for building consistent environments across dev, test, and production.

🔜 Coming Next...

Creating VMs from Managed Images

Adding custom tags and encryption

Building a golden image pipeline with Packer + Terraform

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>cloud</category>
      <category>iac</category>
    </item>
    <item>
      <title>Deploy Load Balanced Windows VMs with IIS on Azure using Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Sun, 29 Jun 2025 12:57:51 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-load-balanced-windows-vms-with-iis-on-azure-using-terraform-31eo</link>
      <guid>https://forem.com/smallsun2025/deploy-load-balanced-windows-vms-with-iis-on-azure-using-terraform-31eo</guid>
      <description>&lt;h1&gt;
  
  
  🧭 Introduction
&lt;/h1&gt;

&lt;p&gt;In this guide, we will deploy a pair of Windows Server 2022 virtual machines behind an Azure Load Balancer, automatically install IIS on them using a startup script, and configure NAT rules to allow RDP access. This is a great hands-on example to learn Infrastructure as Code (IaC) and understand how Azure Load Balancers distribute traffic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;本指南将通过 Terraform 创建两个 VM + 负载均衡器 + NAT 规则 + 自动 IIS 安装，适合练习云架构基础。&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  🗂 Project Structure
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
bash
terraform-lb-iis-vm/
├── main.tf                # All core infrastructure resources
├── variables.tf           # Input variables (e.g., username/password)
├── terraform.tfvars       # Actual values for variables
├── outputs.tf             # Output info (e.g., Public IP)
├── startup-script.ps1     # Script to install IIS on each VM

🔧 What This Code Does
Creates a Resource Group and Virtual Network

Defines a Public Load Balancer with Backend Pool

Sets up NAT rules for RDP (TCP 50001 &amp;amp; 50002)

Deploys two Windows Server VMs and installs IIS

Associates the VMs with the Load Balancer backend pool

This architecture allows HTTP access via Load Balancer's Public IP, and RDP access via port NAT.

🪜 How to Deploy
Make sure you have:

Azure CLI installed and logged in (az login)

Terraform installed locally

Steps:
terraform init
terraform plan
terraform apply

When prompted, type yes.


🌐 Access Instructions
VM1 RDP: RDP to PublicIP:50001

VM2 RDP: RDP to PublicIP:50002

HTTP Test: http://PublicIP (should show IIS welcome page)



✅ Conclusion
Using only Terraform, we have:

Created two VMs

Configured a Load Balancer and NAT

Installed IIS automatically via startup script

This project demonstrates how to combine multiple Azure services in an automated and repeatable way. It’s a foundational building block for scalable web applications.

🔜 Coming Next...
Use Azure Run Command to manage VMs remotely

Add autoscaling rules for backend VMs

Integrate with Azure Monitor for health probes

If you find this helpful, feel free to ⭐️ the repo and share your feedback!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
    </item>
    <item>
      <title>Automate VM Image Creation on Azure with Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Wed, 25 Jun 2025 11:40:37 +0000</pubDate>
      <link>https://forem.com/smallsun2025/automate-vm-image-creation-on-azure-with-terraform-5ci9</link>
      <guid>https://forem.com/smallsun2025/automate-vm-image-creation-on-azure-with-terraform-5ci9</guid>
      <description>&lt;p&gt;📌 1. Introduction&lt;br&gt;
Creating a reusable VM image is a core part of cloud infrastructure workflows. In this tutorial, we’ll use Terraform to create a Managed Image from an existing Azure VM — fully automated and reproducible. This is especially useful when building base images for application servers, golden images for dev/test, or setting up a repeatable environment base.&lt;/p&gt;

&lt;p&gt;📁 2. Project Structure&lt;br&gt;
The project contains the following Terraform files:&lt;/p&gt;

&lt;p&gt;azure-managed-image/&lt;br&gt;
├── main.tf           # Define VM and image resources&lt;br&gt;
├── variables.tf      # Declare input variables&lt;br&gt;
├── terraform.tfvars  # Provide actual values for variables&lt;br&gt;
├── outputs.tf        # Output the Managed Image ID&lt;/p&gt;

&lt;p&gt;⚙️ 3. What the Terraform Code Does&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provisions a temporary Virtual Machine using azurerm_windows_virtual_machine.&lt;/li&gt;
&lt;li&gt;Adds a custom script (startup-script.sh) to configure the VM during creation.&lt;/li&gt;
&lt;li&gt;After VM is ready, it creates a Managed Image from this VM.&lt;/li&gt;
&lt;li&gt;Outputs the image ID, which can be used in future Terraform configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 4. How to Deploy&lt;/p&gt;

&lt;p&gt;Make sure you have the Azure CLI installed and logged in (&lt;code&gt;az login&lt;/code&gt;), and Terraform installed.&lt;/p&gt;

&lt;p&gt;Then follow these commands:&lt;/p&gt;

&lt;p&gt;terraform init&lt;br&gt;&lt;br&gt;
terraform plan&lt;br&gt;&lt;br&gt;
terraform apply  &lt;/p&gt;

&lt;p&gt;After a few minutes, you’ll get the Managed Image ID in the output.&lt;/p&gt;

&lt;p&gt;✅ 5. Conclusion&lt;br&gt;
By using Terraform to create a Managed Image, we can simplify our infrastructure pipeline and reuse golden images in future deployments. This is a core DevOps practice that helps ensure consistency and efficiency in cloud environments.&lt;/p&gt;

&lt;p&gt;🔜 Coming Next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploying VMs from Managed Images&lt;/li&gt;
&lt;li&gt;Creating Image Versions with Shared Image Gallery&lt;/li&gt;
&lt;li&gt;Using Packer + Terraform for advanced image pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! ⭐️ this repo if you found it helpful!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy Windows VM with NSG and IIS using Terraform on Azure</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Mon, 23 Jun 2025 10:17:18 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-windows-vm-with-nsg-and-iis-using-terraform-on-azure-4485</link>
      <guid>https://forem.com/smallsun2025/deploy-windows-vm-with-nsg-and-iis-using-terraform-on-azure-4485</guid>
      <description>&lt;p&gt;🧭 Introduction（引言）&lt;br&gt;
Deploying a Windows Virtual Machine (VM) with a Network Security Group (NSG) and installing IIS is a common scenario for setting up demo environments or learning web server basics. In this tutorial, we’ll use Terraform to fully automate this setup on Azure — ideal for anyone learning cloud infrastructure as code (IaC).&lt;/p&gt;

&lt;p&gt;🗂 Project Structure&lt;br&gt;
Here’s a quick overview of the project files:&lt;br&gt;
terraform-windows-vm-iis/&lt;br&gt;
├── main.tf              # Core resource definitions&lt;br&gt;
├── variables.tf         # Variable declarations&lt;br&gt;
├── terraform.tfvars     # Variable values&lt;br&gt;
├── outputs.tf           # Output info (IP address, etc.)&lt;br&gt;
├── iis-install.ps1      # Startup script to install IIS&lt;/p&gt;

&lt;p&gt;🔧 What the Terraform Code Does&lt;br&gt;
Creates a Resource Group to hold all the infrastructure.&lt;/p&gt;

&lt;p&gt;Deploys a Windows Virtual Machine using azurerm_windows_virtual_machine.&lt;/p&gt;

&lt;p&gt;Creates and attaches a Public IP, Network Interface, NSG, and associates everything together.&lt;/p&gt;

&lt;p&gt;Installs IIS on the VM automatically by running a PowerShell script (iis-install.ps1) via the custom_data property.&lt;/p&gt;

&lt;p&gt;🚀 How to Deploy&lt;br&gt;
Make sure you have:&lt;/p&gt;

&lt;p&gt;Azure CLI installed and logged in (az login)&lt;/p&gt;

&lt;p&gt;Terraform installed&lt;/p&gt;

&lt;p&gt;Then follow these steps:&lt;br&gt;
terraform init&lt;br&gt;
terraform plan&lt;br&gt;
terraform apply&lt;/p&gt;

&lt;p&gt;When prompted, type yes.&lt;/p&gt;

&lt;p&gt;After a few minutes, you’ll get the public IP output. Paste that into your browser, and you should see the default IIS welcome page!&lt;/p&gt;

&lt;p&gt;✅ Conclusion&lt;br&gt;
With just a few lines of Terraform, you've deployed a fully functional IIS server on Azure. This is a perfect beginner-friendly project to understand how to provision VMs, work with NSGs, and automate server initialization.&lt;/p&gt;

&lt;p&gt;🔜 Coming Next...&lt;br&gt;
How to manage Azure VMs with Run Command&lt;/p&gt;

&lt;p&gt;Adding custom domain and SSL to IIS&lt;/p&gt;

&lt;p&gt;Creating reusable Terraform modules&lt;/p&gt;

&lt;p&gt;If you found this useful, feel free to ⭐️ the repo and share feedback!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy a Windows VM with NSG and IIS using Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Fri, 20 Jun 2025 13:13:11 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-a-windows-vm-with-nsg-and-iis-using-terraform-9pj</link>
      <guid>https://forem.com/smallsun2025/deploy-a-windows-vm-with-nsg-and-iis-using-terraform-9pj</guid>
      <description>&lt;p&gt;🧭 Introduction&lt;br&gt;
When deploying infrastructure on Azure, Terraform allows you to build repeatable, automated, and secure environments. In this post, we’ll demonstrate how to deploy a Windows Virtual Machine (VM) with a Network Security Group (NSG) and install IIS via a startup script. This setup is ideal for beginners or cloud engineers exploring infrastructure as code (IaC) for web services on Windows.&lt;/p&gt;

&lt;p&gt;📁 Project Structure&lt;/p&gt;

&lt;p&gt;azure-windows-iis-demo/&lt;br&gt;
├── main.tf               # Core resource definitions (VM, NSG, IP, NIC)&lt;br&gt;
├── variables.tf          # Input variables declaration&lt;br&gt;
├── terraform.tfvars      # Variable values&lt;br&gt;
├── outputs.tf            # Outputs like public IP&lt;br&gt;
├── iis-install.ps1       # Startup script to install IIS&lt;br&gt;
Each file keeps the configuration modular, clear, and easy to maintain.&lt;/p&gt;

&lt;p&gt;Terraform Configuration Breakdown&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Virtual Network, Subnet, and NSG&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;resource "azurerm_network_security_group" "nsg" {&lt;br&gt;
  name                = "win-nsg"&lt;br&gt;
  location            = azurerm_resource_group.rg.location&lt;br&gt;
  resource_group_name = azurerm_resource_group.rg.name&lt;/p&gt;

&lt;p&gt;security_rule {&lt;br&gt;
    name                       = "allow_http"&lt;br&gt;
    priority                   = 100&lt;br&gt;
    direction                  = "Inbound"&lt;br&gt;
    access                     = "Allow"&lt;br&gt;
    protocol                   = "Tcp"&lt;br&gt;
    source_port_range          = "&lt;em&gt;"&lt;br&gt;
    destination_port_range     = "80"&lt;br&gt;
    source_address_prefix      = "&lt;/em&gt;"&lt;br&gt;
    destination_address_prefix = "*"&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Opens port 80 to allow web traffic (IIS access)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Windows VM + IIS Script
resource "azurerm_virtual_machine" "vm" {
...
os_profile {
computer_name  = "webvm"
admin_username = var.admin_username
admin_password = var.admin_password
custom_data    = filebase64("iis-install.ps1")
}
}
custom_data runs PowerShell to install IIS after boot.&lt;/li&gt;
&lt;li&gt;Output
output "public_ip_address" {
description = "The public IP address of the Windows VM"
value       = azurerm_public_ip.vm_pip.ip_address
}
After deployment, this will show the VM’s public IP so you can test IIS.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How to Deploy&lt;br&gt;
Make sure you have Terraform installed and configured locally.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: Login to Azure
&lt;/h1&gt;

&lt;p&gt;az login&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2: Initialize
&lt;/h1&gt;

&lt;p&gt;terraform init&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3: Preview changes
&lt;/h1&gt;

&lt;p&gt;terraform plan&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4: Deploy
&lt;/h1&gt;

&lt;p&gt;terraform apply&lt;br&gt;
Type yes when prompted. After deployment, access the IIS default page by visiting the outputted public IP in a browser.&lt;br&gt;
✅ ConclusionThis project helps you understand:&lt;/p&gt;

&lt;p&gt;How to securely deploy Windows VMs with NSGs&lt;/p&gt;

&lt;p&gt;How to run PowerShell scripts during provisioning&lt;/p&gt;

&lt;p&gt;How to automate web server setup via Terraform&lt;/p&gt;

</description>
      <category>terraform</category>
    </item>
    <item>
      <title>Deploy a Linux VM on Azure with a Custom Startup Script using Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Sun, 15 Jun 2025 13:55:32 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-a-linux-vm-on-azure-with-a-custom-startup-script-using-terraform-565e</link>
      <guid>https://forem.com/smallsun2025/deploy-a-linux-vm-on-azure-with-a-custom-startup-script-using-terraform-565e</guid>
      <description>&lt;h2&gt;
  
  
  🗂 Project Structure
&lt;/h2&gt;

&lt;p&gt;The Terraform project consists of the following files:&lt;/p&gt;

&lt;p&gt;azure-linuxvm-nsg-nginx-demo/&lt;br&gt;
├── main.tf # Main infrastructure definitions&lt;br&gt;
├── variables.tf # Input variable declarations&lt;br&gt;
├── terraform.tfvars # Variable values (location, credentials, etc.)&lt;br&gt;
├── outputs.tf # Outputs like public IP&lt;br&gt;
├── startup-script.sh # Bash script to install and enable nginx&lt;/p&gt;

&lt;p&gt;Each file serves a specific purpose to keep the project modular, secure, and easy to manage.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Terraform Configuration Breakdown
&lt;/h2&gt;

&lt;p&gt;This section explains each component used in the deployment.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Resource Group
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"rg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resource_group_name&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;💡&lt;/span&gt; &lt;span class="nx"&gt;Creates&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;hold&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;related&lt;/span&gt; &lt;span class="nx"&gt;Azure&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Virtual&lt;/span&gt; &lt;span class="nx"&gt;Network&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;Subnet&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_virtual_network"&lt;/span&gt; &lt;span class="s2"&gt;"vnet"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vnet-demo"&lt;/span&gt;
  &lt;span class="nx"&gt;address_space&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.0.0.0/16"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"subnet"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"subnet-demo"&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_resource_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;virtual_network_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_virtual_network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;address_prefixes&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.0.1.0/24"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;💡&lt;/span&gt; &lt;span class="nx"&gt;Defines&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;internal&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;VM&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;reside&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Public&lt;/span&gt; &lt;span class="nx"&gt;IP&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_public_ip"&lt;/span&gt; &lt;span class="s2"&gt;"public_ip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"public-ip-demo"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resource_group_name&lt;/span&gt;
  &lt;span class="nx"&gt;allocation_method&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Dynamic"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;💡&lt;/span&gt; &lt;span class="nx"&gt;Allows&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;VM&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;accessible&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;internet&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Network&lt;/span&gt; &lt;span class="nx"&gt;Security&lt;/span&gt; &lt;span class="nx"&gt;Group&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NSG&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_network_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"nsg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nsg-demo"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resource_group_name&lt;/span&gt;

  &lt;span class="nx"&gt;security_rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SSH"&lt;/span&gt;
    &lt;span class="nx"&gt;priority&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1001&lt;/span&gt;
    &lt;span class="nx"&gt;direction&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Inbound"&lt;/span&gt;
    &lt;span class="nx"&gt;access&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;source_port_range&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"*"&lt;/span&gt;
    &lt;span class="nx"&gt;destination_port_range&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"22"&lt;/span&gt;
    &lt;span class="nx"&gt;source_address_prefix&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"*"&lt;/span&gt;
    &lt;span class="nx"&gt;destination_address_prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"*"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;security_rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
    &lt;span class="nx"&gt;priority&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1002&lt;/span&gt;
    &lt;span class="nx"&gt;direction&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Inbound"&lt;/span&gt;
    &lt;span class="nx"&gt;access&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;source_port_range&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"*"&lt;/span&gt;
    &lt;span class="nx"&gt;destination_port_range&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"80"&lt;/span&gt;
    &lt;span class="nx"&gt;source_address_prefix&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"*"&lt;/span&gt;
    &lt;span class="nx"&gt;destination_address_prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"*"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;💡&lt;/span&gt; &lt;span class="nx"&gt;Allows&lt;/span&gt; &lt;span class="nx"&gt;traffic&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;ports&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SSH&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTP&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="nx"&gt;IP&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Network&lt;/span&gt; &lt;span class="nx"&gt;Interface&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;NSG&lt;/span&gt; &lt;span class="nx"&gt;Binding&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_network_interface"&lt;/span&gt; &lt;span class="s2"&gt;"nic"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nic-demo"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resource_group_name&lt;/span&gt;

  &lt;span class="nx"&gt;ip_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ipconfig"&lt;/span&gt;
    &lt;span class="nx"&gt;subnet_id&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="nx"&gt;private_ip_address_allocation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Dynamic"&lt;/span&gt;
    &lt;span class="nx"&gt;public_ip_address_id&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_public_ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;network_security_group_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_network_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;💡&lt;/span&gt; &lt;span class="nx"&gt;Binds&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;NIC&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;NSG&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Associates&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;IP&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;### 6. Startup Script: `startup-script.sh`&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;

&lt;h1&gt;
  
  
  !/bin/bash
&lt;/h1&gt;

&lt;p&gt;sudo apt-get update&lt;br&gt;
sudo apt-get install -y nginx&lt;br&gt;
sudo systemctl start nginx&lt;br&gt;
sudo systemctl enable nginx&lt;/p&gt;

&lt;p&gt;💡 This script installs and starts nginx automatically when the VM is created.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;source_image_reference {&lt;br&gt;
    publisher = "Canonical"&lt;br&gt;
    offer     = "UbuntuServer"&lt;br&gt;
    sku       = "18.04-LTS"&lt;br&gt;
    version   = "latest"&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;os_disk {&lt;br&gt;
    caching              = "ReadWrite"&lt;br&gt;
    storage_account_type = "Standard_LRS"&lt;br&gt;
    name                 = "osdisk-demo"&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;computer_name       = "demo-vm"&lt;br&gt;
  provision_vm_agent  = true&lt;br&gt;
  custom_data         = base64encode(file("startup-script.sh"))&lt;br&gt;
}&lt;br&gt;
💡 This creates a Linux VM and runs the startup script to configure the web server.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outputs
output "resource_group_name" {
value = azurerm_resource_group.rg.name
}&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;output "public_ip_address" {&lt;br&gt;
  value = azurerm_public_ip.public_ip.ip_address&lt;br&gt;
}&lt;br&gt;
💡 After deployment, these outputs help you identify the resource group and access the VM.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Conclusion
&lt;/h2&gt;

&lt;p&gt;With just a few Terraform files, we successfully deployed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A secure Linux Virtual Machine on Azure&lt;/li&gt;
&lt;li&gt;A fully working nginx web server&lt;/li&gt;
&lt;li&gt;Automated provisioning via a startup script&lt;/li&gt;
&lt;li&gt;Public access through a dynamically assigned IP address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach demonstrates the power of Infrastructure as Code (IaC) and how easily repeatable environments can be created using Terraform.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 GitHub Repository
&lt;/h2&gt;

&lt;p&gt;You can find the full source code for this project here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/Smallsun2025/azure-linuxvm-nsg-nginx-demo" rel="noopener noreferrer"&gt;https://github.com/Smallsun2025/azure-linuxvm-nsg-nginx-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐️ Feel free to star, fork, or leave feedback!&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Coming Next
&lt;/h2&gt;

&lt;p&gt;In future posts, I’ll walk through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating Azure VM images with Packer + Terraform
&lt;/li&gt;
&lt;li&gt;Setting up 3-tier architecture with Load Balancer
&lt;/li&gt;
&lt;li&gt;Using Terraform Cloud for remote state &amp;amp; collaboration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow for more Azure automation tips!&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Deploy Azure VM from Custom Image using Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Wed, 11 Jun 2025 12:52:28 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-azure-vm-from-custom-image-using-terraform-2e11</link>
      <guid>https://forem.com/smallsun2025/deploy-azure-vm-from-custom-image-using-terraform-2e11</guid>
      <description>&lt;p&gt;🗂 Project Structure&lt;br&gt;
This Terraform project consists of the following files:&lt;br&gt;
azure-vm-from-image-demo/&lt;br&gt;
├── main.tf            # Core infrastructure resources&lt;br&gt;
├── variables.tf       # Input variables&lt;br&gt;
├── terraform.tfvars   # Variable values (e.g., image ID, subnet ID)&lt;br&gt;
├── outputs.tf         # Useful outputs (e.g., VM ID, IP)&lt;/p&gt;

&lt;p&gt;🔧 Terraform Configuration Explained&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resource Group + Network Interface
In main.tf, we start by creating a resource group and a network interface that connects to an existing subnet:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;resource "azurerm_resource_group" "rg" {&lt;br&gt;
  name     = var.resource_group_name&lt;br&gt;
  location = var.location&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "azurerm_network_interface" "nic" {&lt;br&gt;
  name                = "vm-from-image-nic"&lt;br&gt;
  location            = azurerm_resource_group.rg.location&lt;br&gt;
  resource_group_name = azurerm_resource_group.rg.name&lt;/p&gt;

&lt;p&gt;ip_configuration {&lt;br&gt;
    name                          = "internal"&lt;br&gt;
    subnet_id                     = var.subnet_id&lt;br&gt;
    private_ip_address_allocation = "Dynamic"&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;💡 Explanation: This NIC connects the VM to the specified subnet. You’ll need to pass in an existing subnet ID (from a previous project or manual setup).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Virtual Machine from Custom Image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;resource "azurerm_linux_virtual_machine" "vm" {&lt;br&gt;
  name                            = var.vm_name&lt;br&gt;
  resource_group_name             = azurerm_resource_group.rg.name&lt;br&gt;
  location                        = azurerm_resource_group.rg.location&lt;br&gt;
  size                            = "Standard_B1s"&lt;br&gt;
  admin_username                  = var.admin_username&lt;br&gt;
  admin_password                  = var.admin_password&lt;br&gt;
  network_interface_ids           = [azurerm_network_interface.nic.id]&lt;br&gt;
  disable_password_authentication = false&lt;/p&gt;

&lt;p&gt;source_image_id = var.custom_image_id&lt;/p&gt;

&lt;p&gt;os_disk {&lt;br&gt;
    caching              = "ReadWrite"&lt;br&gt;
    storage_account_type = "Standard_LRS"&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
💡 Explanation: Instead of using a marketplace image, we’re referencing an existing custom image by its full resource ID (e.g., /subscriptions/.../images/demo-vm-image).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Variables + tfvars
To keep the project reusable and configurable, we use the following variables in variables.tf and set actual values in terraform.tfvars:
variable "custom_image_id" {
description = "The resource ID of the custom managed image"
type        = string
}&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;variable "subnet_id" {&lt;br&gt;
  description = "Subnet ID for VM NIC"&lt;br&gt;
  type        = string&lt;br&gt;
}&lt;br&gt;
And in terraform.tfvars:&lt;/p&gt;

&lt;p&gt;custom_image_id = "/subscriptions/xxxxx/resourceGroups/xxx/providers/Microsoft.Compute/images/demo-vm-image"&lt;br&gt;
subnet_id       = "/subscriptions/xxxxx/resourceGroups/xxx/providers/Microsoft.Network/virtualNetworks/demo-vnet/subnets/demo-subnet"&lt;br&gt;
🛠 You can get these IDs from previous deployments or from the Azure Portal.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outputs
We output useful values like VM ID and private IP address:
output "vm_id" {
value = azurerm_linux_virtual_machine.vm.id
}&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;output "private_ip" {&lt;br&gt;
  value = azurerm_network_interface.nic.private_ip_address&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;🚀 Deployment Steps&lt;br&gt;
To deploy this project, follow these steps:&lt;/p&gt;

&lt;p&gt;az login&lt;br&gt;
terraform init&lt;br&gt;
terraform plan&lt;br&gt;
terraform apply&lt;/p&gt;

&lt;p&gt;✅ Summary&lt;br&gt;
This post showed how to:&lt;/p&gt;

&lt;p&gt;Deploy a VM from a custom managed image in Azure&lt;/p&gt;

&lt;p&gt;Use Terraform to automate the setup&lt;/p&gt;

&lt;p&gt;Connect the VM to an existing subnet&lt;/p&gt;

&lt;p&gt;Maintain modular, reusable code using variables and outputs&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>iac</category>
      <category>devops</category>
    </item>
    <item>
      <title>Deploy Azure Snapshot and Managed Image with Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Sun, 08 Jun 2025 13:26:36 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-azure-snapshot-and-managed-image-with-terraform-59ja</link>
      <guid>https://forem.com/smallsun2025/deploy-azure-snapshot-and-managed-image-with-terraform-59ja</guid>
      <description>&lt;h2&gt;
  
  
  🧭 Introduction
&lt;/h2&gt;

&lt;p&gt;When managing virtual machines in Azure, creating backups and reusable VM images is a crucial part of infrastructure lifecycle management. In this post, we’ll walk through how to use Terraform to create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Snapshot&lt;/strong&gt; (point-in-time backup of a managed disk)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Managed Image&lt;/strong&gt; (used to create new VMs from a base configuration)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful for both disaster recovery and automated environment deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗂 Project Structure
&lt;/h2&gt;

&lt;p&gt;The Terraform project consists of four files:&lt;br&gt;
azure-image-snapshot-demo/&lt;br&gt;
├── main.tf # Resource definitions: snapshot + image&lt;br&gt;
├── variables.tf # Input variables&lt;br&gt;
├── terraform.tfvars # Variable values&lt;br&gt;
├── outputs.tf # Exported resource IDs&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Terraform Resource Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Resource Group&lt;/li&gt;
&lt;/ol&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
hcl
resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = var.location
}

2. Managed Disk
resource "azurerm_managed_disk" "os_disk" {
  name                 = "demo-os-disk"
  location             = azurerm_resource_group.rg.location
  resource_group_name  = azurerm_resource_group.rg.name
  storage_account_type = "Standard_LRS"
  create_option        = "Empty"
  disk_size_gb         = 30
}

3. Snapshot
resource "azurerm_snapshot" "vm_snapshot" {
  name                = "demo-vm-snapshot"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  create_option       = "Copy"
  source_uri          = azurerm_managed_disk.os_disk.id
}

4. Managed Image
resource "azurerm_image" "vm_image" {
  name                = "demo-vm-image"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  os_disk {
    os_type          = "Linux"
    os_state         = "Generalized"
    blob_uri         = null
    managed_disk_id  = azurerm_snapshot.vm_snapshot.id
  }
}
⚙️ How to Deploy (Optional)
az login
terraform init
terraform apply
terraform output

✅ Conclusion
With just a few lines of Terraform, we can automate the process of backing up a virtual machine and preparing a custom image. This is especially helpful when building golden images for reproducible environments or setting up disaster recovery strategies.

👉 GitHub Repository:
https://github.com/Smallsun2025/azure-image-snapshot-demo

If you found this helpful, please ⭐️ the repo or leave a comment!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>azure</category>
      <category>terraform</category>
      <category>devops</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Deploy an Azure VM with Network Security Group (NSG) using Terraform</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Sun, 01 Jun 2025 14:47:26 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-an-azure-vm-with-network-security-group-nsg-using-terraform-3p01</link>
      <guid>https://forem.com/smallsun2025/deploy-an-azure-vm-with-network-security-group-nsg-using-terraform-3p01</guid>
      <description>&lt;h2&gt;
  
  
  🧭 Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, we’ll walk through how to use Terraform to deploy a simple Azure virtual machine (VM) along with a Network Security Group (NSG). This is a great hands-on example for beginners looking to understand how Infrastructure as Code (IaC) applies to cloud networking and compute resources.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗂 Project Structure
&lt;/h2&gt;

&lt;p&gt;The project contains the following Terraform files:&lt;/p&gt;

&lt;p&gt;azure-vm-nsg-template/&lt;br&gt;
├── main.tf # Main resource definitions (VM, NSG, NIC, RG)&lt;br&gt;
├── variables.tf # Input variable declarations&lt;br&gt;
├── terraform.tfvars # Variable values (e.g. VM name, location)&lt;br&gt;
├── outputs.tf # Output values like IP address&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Resource Definitions Breakdown
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Resource Group
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
hcl
resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = var.location
}
2. Network Security Group (NSG)
resource "azurerm_network_security_group" "nsg" {
  name                = "demo-nsg"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  security_rule {
    name                       = "Allow-SSH"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}
3. Virtual Network + Subnet
resource "azurerm_virtual_network" "vnet" {
  name                = "demo-vnet"
  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                 = "demo-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}
4. Network Interface
resource "azurerm_network_interface" "nic" {
  name                = "demo-nic"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

5. Associate NSG with NIC
resource "azurerm_network_interface_security_group_association" "nsg_assoc" {
  network_interface_id      = azurerm_network_interface.nic.id
  network_security_group_id = azurerm_network_security_group.nsg.id
}
6. Virtual Machine
resource "azurerm_linux_virtual_machine" "vm" {
  name                = var.vm_name
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  size                = "Standard_B1s"
  admin_username      = var.admin_username

  network_interface_ids = [azurerm_network_interface.nic.id]

  admin_password = var.admin_password
  disable_password_authentication = false

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }
}
🚀 How to Deploy (Optional)
az login
terraform init
terraform plan
terraform apply
✅ Conclusion
This example demonstrates how to deploy a basic virtual machine with an associated NSG using Terraform. It’s a great step toward building more complex cloud environments and is especially helpful for those preparing for Azure infrastructure roles or certifications.
👉 GitHub Repository: https://github.com/Smallsun2025/azure-vm-nsg-template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>azure</category>
      <category>terraform</category>
      <category>beginners</category>
      <category>devops</category>
    </item>
    <item>
      <title>Deploy Azure Infrastructure with Terraform: RG + VNet + Subnet</title>
      <dc:creator>Smallsun2025</dc:creator>
      <pubDate>Sun, 25 May 2025 10:35:55 +0000</pubDate>
      <link>https://forem.com/smallsun2025/deploy-azure-infrastructure-with-terraform-rg-vnet-subnet-2jp3</link>
      <guid>https://forem.com/smallsun2025/deploy-azure-infrastructure-with-terraform-rg-vnet-subnet-2jp3</guid>
      <description>&lt;h2&gt;
  
  
  🧭 Introduction
&lt;/h2&gt;

&lt;p&gt;When starting with Azure infrastructure as code (IaC), Terraform is one of the most powerful tools available. In this post, we’ll walk through how to use Terraform to create a basic network setup on Azure — including a Resource Group, Virtual Network (VNet), and Subnet. This is an ideal starting point for beginners who want to automate infrastructure deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗂 Project Structure
&lt;/h2&gt;

&lt;p&gt;The project consists of four core Terraform files:&lt;br&gt;
azure-terraform-infra-demo/&lt;br&gt;
├── main.tf # Main resource definitions&lt;br&gt;
├── variables.tf # Input variable declarations&lt;br&gt;
├── terraform.tfvars # Variable values&lt;br&gt;
├── outputs.tf # Output values&lt;/p&gt;

&lt;p&gt;Each file serves a specific purpose and keeps the configuration modular and easy to manage.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Terraform Configuration Breakdown
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Resource Group
&lt;/h3&gt;

&lt;p&gt;resource "azurerm_resource_group" "rg" {&lt;br&gt;
  name     = var.resource_group_name&lt;br&gt;
  location = var.location&lt;br&gt;
}&lt;br&gt;
This creates a logical container for all other Azure resources.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Virtual Network&lt;br&gt;
resource "azurerm_virtual_network" "vnet" {&lt;br&gt;
name                = "demo-vnet"&lt;br&gt;
address_space       = ["10.0.0.0/16"]&lt;br&gt;
location            = azurerm_resource_group.rg.location&lt;br&gt;
resource_group_name = azurerm_resource_group.rg.name&lt;br&gt;
}&lt;br&gt;
Defines a virtual network in the specified resource group.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Subnet&lt;br&gt;
resource "azurerm_subnet" "subnet" {&lt;br&gt;
name                 = "demo-subnet"&lt;br&gt;
resource_group_name  = azurerm_resource_group.rg.name&lt;br&gt;
virtual_network_name = azurerm_virtual_network.vnet.name&lt;br&gt;
address_prefixes     = ["10.0.1.0/24"]&lt;br&gt;
}&lt;br&gt;
Creates a subnet inside the virtual network.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🚀 How to Deploy&lt;br&gt;
Once you have all files ready, you can deploy the infrastructure using the following steps. Make sure you have the Azure CLI and Terraform installed locally.&lt;/p&gt;

&lt;p&gt;Step 1: Login to Azure&lt;br&gt;
az login&lt;/p&gt;

&lt;p&gt;Step 2: Initialize Terraform&lt;br&gt;
terraform init&lt;/p&gt;

&lt;p&gt;Step 3: Preview the Plan&lt;br&gt;
terraform plan&lt;/p&gt;

&lt;p&gt;Step 4: Apply the Configuration&lt;br&gt;
terraform apply&lt;/p&gt;

&lt;p&gt;Type yes when prompted to confirm, and Terraform will begin creating the resources on Azure.&lt;/p&gt;

&lt;p&gt;✅ Conclusion&lt;br&gt;
This simple project is a great starting point for anyone new to Terraform on Azure. By automating the creation of a Resource Group, Virtual Network, and Subnet, you can begin building more advanced infrastructure in a modular and repeatable way.&lt;/p&gt;

&lt;p&gt;In future posts, I plan to share:&lt;/p&gt;

&lt;p&gt;How to deploy Azure Virtual Machines with NSGs&lt;/p&gt;

&lt;p&gt;How to create snapshots and managed images&lt;/p&gt;

&lt;p&gt;Comparing Terraform and Bicep for infrastructure as code&lt;/p&gt;

&lt;p&gt;Building multi-subnet architectures with internal routing&lt;/p&gt;

&lt;p&gt;Thanks for reading! Feel free to ⭐️ the GitHub repo or leave a comment if you found this helpful.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>cloud</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
