DEV Community

Cover image for How to Create a Virtual Machine on Azure Using a Reusable Terraform Script
Akash Roy
Akash Roy

Posted on

1 2 1 1

How to Create a Virtual Machine on Azure Using a Reusable Terraform Script

Deploying infrastructure shouldn't be a copy-paste headache. Here's how to make your Azure VM setup repeatable and clean using Terraform.

When I started using Terraform to manage infrastructure on Azure, one thing became clear very quickly: writing the same Terraform config every time gets old fast.

In this blog, I'm going to show you how to create an Azure Virtual Machine using a reusable Terraform script. By the end of this post, you'll have a modular setup you can use across projects—without rewriting the whole thing each time.


What You’ll Need

Before we begin, make sure you’ve got the following:


Step 1: Create the Folder Structure

Let’s keep things clean.

mkdir terraform-azure-vm
cd terraform-azure-vm

mkdir modules
mkdir modules/vm
Enter fullscreen mode Exit fullscreen mode

We’ll keep our reusable VM code inside modules/vm and the environment-specific code in the root folder.


Step 2: Build the Reusable VM Module

Inside modules/vm/, create these files:

main.tf

resource "azurerm_network_interface" "nic" {
  name                = "${var.vm_name}-nic"
  location            = var.location
  resource_group_name = var.resource_group_name

  ip_configuration {
    name                           = "internal"
    subnet_id                      = var.subnet_id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_windows_virtual_machine" "vm" {
  name                = var.vm_name
  resource_group_name = var.resource_group_name
  location            = var.location
  size                = var.vm_size
  admin_username      = var.admin_username
  admin_password      = var.admin_password
  network_interface_ids = [azurerm_network_interface.nic.id]

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

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2019-Datacenter"
    version   = "latest"
  }
}
Enter fullscreen mode Exit fullscreen mode

variables.tf

variable "vm_name" {}
variable "resource_group_name" {}
variable "location" {}
variable "subnet_id" {}
variable "vm_size" {}
variable "admin_username" {}
variable "admin_password" {}
Enter fullscreen mode Exit fullscreen mode

Step 3: Use the Module in Your Environment

Go to the root folder and create:

main.tf

provider "azurerm" {
  features {}
}

module "vm" {
  source              = "./modules/vm"
  vm_name             = "dev-vm"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  subnet_id           = azurerm_subnet.subnet.id
  vm_size             = "Standard_B1s"
  admin_username      = "azureuser"
  admin_password      = "MySecureP@ssw0rd123"
}

resource "azurerm_resource_group" "rg" {
  name     = "dev-rg"
  location = "East US"
}

resource "azurerm_virtual_network" "vnet" {
  name                = "dev-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                 = "dev-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Don’t Forget the Backend (Optional but recommended)

For team use or remote state management, configure a backend.tf file using Azure Storage Account.


Step 5: Deploy It!

terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

Done! Your Azure VM is up and running.


Wrapping Up

With this modular approach, the next time you need a VM? Just tweak a few inputs. No more rewriting long scripts or fighting with syntax every time.

Let me know in the comments if you'd like to see a Linux version, auto-shutdown scripts, or cost-saving tricks next!


Happy Terraforming!

Tiger Data image

🐯 🚀 Timescale is now TigerData: Building the Modern PostgreSQL for the Analytical and Agentic Era

We’ve quietly evolved from a time-series database into the modern PostgreSQL for today’s and tomorrow’s computing, built for performance, scale, and the agentic future.

So we’re changing our name: from Timescale to TigerData. Not to change who we are, but to reflect who we’ve become. TigerData is bold, fast, and built to power the next era of software.

Read more

Top comments (0)

ITRS image

See What Users Experience in The Browser — Anywhere, Anytime

Simulate logins, checkouts, and payments on SaaS, APIs, and internal apps. Catch issues early, baseline web performance, and stay ahead of incidents. Easily record user journeys right from your browser.

Start Free Trial

👋 Kindness is contagious

Explore this insightful write-up, celebrated by our thriving DEV Community. Developers everywhere are invited to contribute and elevate our shared expertise.

A simple "thank you" can brighten someone’s day—leave your appreciation in the comments!

On DEV, knowledge-sharing fuels our progress and strengthens our community ties. Found this useful? A quick thank you to the author makes all the difference.

Okay