A client of mine in Ohio called me on a Friday afternoon because their on-premises file server had finally run out of disk space, and their finance team couldn’t process month-end reports. They needed compute capacity that afternoon, not after a six-week hardware procurement cycle.
This is the exact situation where an Azure VM (Azure Virtual Machine) becomes the right tool. It gave that client a fully functional Windows Server instance, provisioned in about ten minutes, with room to scale as their data grew.
I’ve deployed hundreds of Azure VMs over the years for organizations ranging from five-person startups in Austin to multi-state healthcare networks, and I still see the same mistakes repeated: wide-open network security groups, VMs left running 24/7 that should have been shut down at night, and administrator credentials stored in plain text files.
This guide walks through everything I’ve learned building Azure virtual machine deployments that are secure, cost-aware, and easy for a small IT team to maintain long after I’ve moved on to the next project.
By the end of this article, you’ll be able to create an Azure VM using the Azure Portal, Azure CLI, and Bicep, configure its networking and identity correctly, secure remote access, and set up monitoring and backup so the VM doesn’t become a forgotten liability sitting on your monthly bill.
What Is an Azure VM and When Should You Use One?
An Azure VM is an on-demand, scalable computing resource in Microsoft Azure that gives you full control over the operating system, similar to a physical server, but without the hardware maintenance burden. You choose the operating system, size, storage, and networking, and Azure handles the underlying physical infrastructure.
I recommend an Azure VM instead of a platform-as-a-service option like Azure App Service when a client needs:
- Full control over the OS, including custom software installations or legacy applications that won’t run in a managed environment
- Specific compliance requirements that require OS-level configuration
- Lift-and-shift migrations of existing on-premises servers, similar to the kind of workload covered in how to migrate a VMware VM to Azure step by step
- Long-running background processes that don’t fit a serverless execution model
If your workload is a modern web application or API that doesn’t need OS-level control, I usually steer clients toward Azure App Service or Azure Functions instead, since those reduce the patching and maintenance burden significantly. I cover that trade-off in more detail in my comparison of Azure Functions vs. App Service.
Pro Tip: In my experience, half the “we need a bigger VM” requests I get are really “we need to redesign the application,” not “we need more compute.” Always ask why the workload needs full OS access before defaulting to a VM.
Planning Your Azure VM Architecture
Before you open the Azure Portal, a few architecture decisions will save you significant rework later.
Subscriptions and Resource Groups
An Azure subscription is the billing and governance boundary for all your Azure resources. If you’re running production and development workloads for the same organization, I typically recommend separating them into different subscriptions or, at minimum, different resource groups, which are logical containers for related Azure resources that share a lifecycle.
Grouping your VM, its virtual network, disks, and network security group into a single, well-named resource group makes it far easier to manage permissions and track cost. If you’re new to this concept, I’d point you toward what is resource group in Azure to see how it differs from a subscription.
I also strongly recommend following a consistent Azure resource group naming convention from day one. I learned this lesson the hard way on a project with three regional IT teams, each naming resource groups differently, which made cost reporting a nightmare six months later.
Choosing a Region and Availability Approach
Regions are the physical geographic locations where Azure runs its datacenters. For most U.S.-based organizations I work with, East US, West US 2, or Central US offer the best balance of latency and service availability. Within a supported region, availability zones are physically separate datacenters that protect your VM from a single datacenter failure.
If your Azure VM is business-critical, deploying it across availability zones (or using an availability set as a lower-cost alternative) is worth the added complexity.
Pro Tip: I always check availability zone support before committing to a region for a client’s production VM. Not every VM size is available in every zone, and how to check availability zone of Azure VM is a step I run before finalizing any deployment plan, since finding this out after deployment is a frustrating way to spend an afternoon.
Creating an Azure VM Step by Step
Here’s the general order of operations I follow with clients, whether I’m doing this through the portal or through code.
- Define the business requirement (operating system, expected load, compliance needs).
- Select the appropriate VM size and pricing model.
- Create the resource group and choose the region.
- Configure identity, permissions, and networking.
- Deploy the virtual machine.
- Store secrets securely and configure remote access.
- Add monitoring, backups, and alerts.
- Test normal, failure, and unauthorized-access scenarios.
- Review costs and document maintenance requirements.
Step 1: Create the Resource Group
az group create \
--name rg-finance-vm-prod \
--location eastusThis command creates a resource group named rg-finance-vm-prod in the East US region. Every resource related to this VM, its disk, network interface, and network security group, will live inside this resource group, giving your team a single management boundary for permissions, cost tracking, and cleanup. If you’d rather do this through the portal first, create a resource group in Azure walks through the same process visually.
Step 2: Create the Virtual Machine
az vm create \
--resource-group rg-finance-vm-prod \
--name vm-finance-app01 \
--image Win2022Datacenter \
--size Standard_D2s_v5 \
--admin-username azureadmin \
--generate-ssh-keys \
--public-ip-sku StandardLet me break down the important parameters here. The --image flag specifies Windows Server 2022 Datacenter, though you could swap this for an Ubuntu or Red Hat image depending on your workload. The --size flag sets the VM size, in this case Standard_D2s_v5, a general-purpose size with 2 vCPUs and 8 GB of RAM, suitable for a small line-of-business application.
The --public-ip-sku Standard flag ensures the public IP is zone-redundant and compatible with Standard load balancers, which matters if you expand this into a multi-VM setup later. The full command reference is available at az vm create if you need additional parameters for your scenario.
If you’d rather use the graphical interface, the walkthrough on how to create a virtual machine in Azure covers the portal-based process screen by screen, which I still recommend to clients who are new to Azure and want to see every configuration option before scripting it.
Pro Tip: I never use
Standard_Bburstable sizes for production database or application servers. They’re excellent for dev and test environments, but I’ve seen them throttle CPU credits at the worst possible moment during a month-end processing job.
Step 3: Create the VM with Azure PowerShell
Some of my clients’ IT teams are more comfortable in PowerShell, especially those coming from a Windows Server administration background.
$ResourceGroupName = "rg-finance-vm-prod"
$Location = "eastus"
$VMName = "vm-finance-app01"
$VMSize = "Standard_D2s_v5"
New-AzVM `
-ResourceGroupName $ResourceGroupName `
-Name $VMName `
-Location $Location `
-Size $VMSize `
-Image "Win2022Datacenter" `
-Credential (Get-Credential)The Get-Credential cmdlet prompts for an administrator username and password interactively rather than hardcoding it into the script, which is a small habit that prevents credentials from ending up in your command history or a shared script file.
The $ResourceGroupName, $Location, and $VMSize variables make the script reusable across environments simply by changing the values at the top. If PowerShell isn’t already installed and configured on your machine, the Azure PowerShell tutorial covers setup from scratch.
Step 4: Deploy Using Bicep for Repeatable Infrastructure
For any client running more than a handful of VMs, I push hard for infrastructure as code instead of manual portal clicks. Here’s a simplified Bicep template for a single VM deployment.
param location string = resourceGroup().location
param vmName string = 'vm-finance-app01'
param adminUsername string
@secure()
param adminPassword string
resource nic 'Microsoft.Network/networkInterfaces@2023-05-01' = {
name: '${vmName}-nic'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: 'Dynamic'
}
}
]
}
}
resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = {
name: vmName
location: location
properties: {
hardwareProfile: {
vmSize: 'Standard_D2s_v5'
}
osProfile: {
computerName: vmName
adminUsername: adminUsername
adminPassword: adminPassword
}
networkProfile: {
networkInterfaces: [
{
id: nic.id
}
]
}
}
}Notice the @secure() decorator on the adminPassword parameter. This tells Azure Resource Manager, the deployment and management layer behind every Azure resource, to treat this value as sensitive and avoid logging it in deployment history.
You’d supply the actual password value through a parameter file or, better yet, pull it from Azure Key Vault during the pipeline run rather than typing it manually. Repeatable deployments like this eliminate the “it worked when I clicked through the portal but the script is different” problem I’ve run into more than once when handing off a project to an internal IT team.
Pro Tip: I keep a Bicep module library for common VM configurations across client engagements. It cuts deployment time roughly in half compared to starting from scratch every time.
Securing Your Azure VM
Security is where I see the most costly mistakes, usually from teams moving fast to hit a deadline.
Identity and Access Management
Never rely solely on local administrator accounts for ongoing access. Instead, integrate your VM with Microsoft Entra ID, the identity service used for authentication and access management across Azure, and assign permissions through role-based access control (RBAC) rather