Azure Compute

Your First Azure Virtual Machine: A Step-by-Step Deployment in Portal, CLI and PowerShell

Spinning up your first Azure Virtual Machine is the moment cloud stops being abstract. You click a few times, wait ninety seconds, and you are holding the keyboard of a real Windows or Linux server in a Microsoft datacentre — one you can SSH or RDP into from your laptop, install anything on, and tear down for nothing when you are done. An Azure VM is Infrastructure as a Service (IaaS): Azure runs the physical host, the hypervisor, the network fabric and the storage; you own everything from the operating system up. That single line — “OS and up is yours” — explains every decision you are about to make, from which image to pick to which firewall ports to open.

The trouble is that the create-a-VM experience asks roughly thirty questions across five tabs, and a beginner has no idea which ones matter. Pick the wrong VM size and you overpay or get a sluggish box; leave the wrong port open and you have published RDP to the whole internet within the hour; forget auto-shutdown and a forgotten test VM bills you for a month. This guide walks every one of those decisions, then deploys the same VM three ways so you understand what the clicks actually do: first in the Azure portal (to see every field), then with the az CLI (to script it), then as a Bicep template (to version-control and recreate it identically).

By the end you will have a running, reachable VM you built deliberately — not one you clicked “Create” on and hoped for. You will know what each resource it spawned is for, how to connect securely, how to read the cost, and — the part most tutorials skip — how to delete every trace of it so your free credit lasts. We use a Linux (Ubuntu) VM with SSH as the primary example because it is cheapest and clearest, and call out the Windows + RDP differences at every step.

What problem this solves

You need a server — to host a website, run a background job, try a database, practise Linux, or reproduce a production issue. On-premises that means procuring hardware, racking it, installing an OS, waiting weeks. With an Azure VM it is a few minutes, billed by the second, thrown away when you are finished. A VM is the most familiar unit of compute there is: a whole machine you control — the right first step before containers or serverless.

What goes wrong without a deliberate process: beginners accept every default — an oversized SKU billing 24×7, port 3389 (RDP) or 22 (SSH) open to 0.0.0.0/0, a public IP they did not know costs money, and no idea which of the six spawned resources to keep. Within a week that is a security incident (bots find open RDP in minutes) or a bill that eats their ₹15,000 free credit on one idle box. The fix is simply knowing what each field means and choosing on purpose. This bites everyone new to Azure, every AZ-900/AZ-104 candidate, and every PaaS-only developer needing a raw box — and it is foundational, since AKS nodes and App Service workers are VMs underneath.

The resources one VM actually creates, so nothing in the wizard surprises you:

Resource the wizard creates What it is Costs money? Can you reuse it? Notes
Virtual machine The compute instance (CPU + RAM) Yes (per second, when running) n/a Deallocate to stop compute billing
OS disk (managed disk) The boot disk holding the OS Yes (always, even when VM is stopped) Yes (can reattach) Premium SSD vs Standard SSD/HDD
Network interface (NIC) Connects the VM to a subnet No (the NIC itself) Yes One VM can have several
Public IP address Internet-routable address Yes (Standard SKU, hourly) Yes (if static) Skip it for private-only VMs
Network security group (NSG) The VM/subnet firewall No Yes Where you control SSH/RDP access
Virtual network + subnet The private network it lives in No Yes (and you should) Created once, reused by many VMs

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You need an Azure subscription (a free account gives ~₹15,000 / US$200 credit for 30 days) and either the Azure portal or Azure Cloud Shell / a local az CLI. No prior VM experience is assumed; you should be comfortable pasting terminal commands. The Linux path needs an SSH client (built into macOS, Linux, modern Windows), the Windows path an RDP client (built into Windows; Microsoft Remote Desktop on macOS).

This sits at the base of the Compute track. Upstream: every VM goes into a resource group (Azure Resource Hierarchy Explained: Subscriptions, Resource Groups and Resources) and onto a virtual network (Azure Virtual Network, Subnets and NSGs: Networking Fundamentals); which datacentre — and whether you spread across zones — is Azure Regions and Availability Zones: Designing for Resilience. Downstream, once it runs, you protect it (Protect Your First Azure VM with Azure Backup: A Guided Walkthrough) and watch it (Azure Monitor and Application Insights: Full-Stack Observability).

The division of responsibility — the most important IaaS mental model, and a frequent exam question:

Layer Who manages it on a VM Why it matters to you
Physical datacentre, host hardware, hypervisor Microsoft You never patch firmware or replace disks
Physical network, host-level DDoS, fabric Microsoft The plumbing is handled
Guest OS (Ubuntu/Windows) and patches You You run apt upgrade / Windows Update
Runtime, middleware, apps You Your stack, your responsibility
OS firewall + NSG rules You You decide who can reach SSH/RDP
Data on the disks You You back it up and encrypt it
Identity & access (who can manage the VM) You (via Azure RBAC) You grant least privilege

Core concepts

A handful of terms recur through every step; pin them down and the wizard reads like plain English.

A VM is rented by size (SKU), billed by the second, and stoppable. The VM size (Standard_B1s, Standard_D2s_v5, …) fixes vCPUs, RAM and price. You pay compute only while running (allocated). Deallocating (the portal “Stop”) releases the hardware and ends that charge — but the disk and any static public IP keep billing. Shutting the OS down from inside the guest does not deallocate; Azure still bills compute. This surprises everyone once.

The OS comes from an image. An image is a disk template — Ubuntu 22.04 LTS, Windows Server 2022, Red Hat, thousands more in the Azure Marketplace — that becomes the VM’s OS disk. Base images carry no software charge (infrastructure only); some commercial images add a per-hour fee.

Disks are managed and come in tiers. Managed disks are virtual disks Azure provisions for you; the tier sets performance and price — Standard HDD (cheapest), Standard SSD (dev/test), Premium SSD (production default), Ultra/Premium SSD v2 (demanding databases). A first VM uses Standard SSD; production app servers want Premium SSD.

The VM lives on a network guarded by an NSG. It gets a NIC on a subnet inside a virtual network (VNet) — a private IP space that is yours. A Network Security Group (NSG) is a stateful allow/deny firewall (port, protocol, source, destination) on the NIC or subnet, where you permit SSH (22) or RDP (3389) — and, critically, from where. Golden rule: never allow management ports from Any; scope them to your own IP.

Reaching it from the internet needs a public IP. By default a VM has only a private IP. To connect from your laptop you attach a public IP (simple, but exposing) or use a safer path — Azure Bastion or a VPN. This lab uses a public IP locked to your source IP; production prefers Bastion.

With those five models in hand, the next section makes each concrete choice — and tells you exactly what to pick for a first VM.

Choosing the right options before you click create

These five choices account for almost all of a beginner’s regret. Make them deliberately and the rest is mechanical.

Region — where the VM physically runs

A region is a datacentre cluster (Central India, East US, …). Pick the one closest to you or your users for lowest latency; prices differ by region (Central India/East US beat Japan East). Resilience later means Availability Zones; a first VM needs no zone. Not every size exists everywhere — if a SKU is greyed out, switch region or size.

VM size — burstable B-series is the right first pick

For learning, dev/test and low-traffic workloads the B-series (burstable) is purpose-built and cheapest: a low baseline CPU that banks credits while idle, bursting when busy. Reach for D-series only for sustained CPU. The practical first-VM size menu:

Size vCPU RAM Family Good for Rough cost (running 24×7)
Standard_B1s 1 1 GiB Burstable Smallest learning box, tiny services ~₹650–900 / ~US$8–11 per month
Standard_B2s 2 4 GiB Burstable Comfortable dev box, small web app ~₹2,600–3,200 / ~US$31–38
Standard_B2ms 2 8 GiB Burstable More memory for dev/test ~₹4,000–4,800 / ~US$48–58
Standard_D2s_v5 2 8 GiB General purpose Steady CPU, small production ~₹6,500–7,500 / ~US$78–90

Indicative pay-as-you-go Linux prices that vary by region and currency; confirm in the Azure Pricing Calculator. Start at B1s/B2s, step up to D-series for sustained CPU, and turn the VM off when not in use.

Image — Linux is cheaper and clearer; Windows when you need it

Pick Ubuntu 22.04 LTS for the cheapest, fastest-booting, license-free box. Pick Windows Server 2022 when you need IIS, the .NET Framework, AD tooling or Windows-only software; Windows adds a license cost to the per-hour price (or use Azure Hybrid Benefit). The image also fixes login: Linux → SSH, Windows → RDP.

Authentication — SSH keys over passwords, always

For Linux choose SSH public key: the public key goes on the VM, the private key stays on your laptop — no password to brute-force (bots hammer passwords on internet-facing Linux within minutes). For Windows you must use a username + strong password (RDP) — long, unique, port still locked to your IP. Compared:

Method OS Security Convenience Use when
SSH public key Linux High (no password to guess) Generate key once Always, for Linux
Password Linux Low (brute-forceable) No key to manage Avoid; only throwaway labs
Username + password Windows Medium (strength-dependent) Familiar Windows VMs (required for RDP)
Microsoft Entra login Linux & Windows High (central identity, MFA) Extra setup Org-managed fleets later

Inbound ports — open nothing to the world

The wizard offers to open SSH/RDP/HTTP, defaulting the source to Any. Do not accept that. Open only the management port you need (22 or 3389), then scope its source to your own public IP. The single most common first-VM mistake is leaving 3389/22 open to 0.0.0.0/0. The small set of ports you will actually touch:

Port Protocol Purpose Open it from Never open from
22 TCP (SSH) Linux remote shell Your IP only Any / 0.0.0.0/0
3389 TCP (RDP) Windows remote desktop Your IP only Any / 0.0.0.0/0
80 TCP (HTTP) Web server (if you host one) Any is OK for a public site
443 TCP (HTTPS) Secure web (if you host one) Any is OK for a public site

Architecture at a glance

Hold the shape as three layers, left to right. On the left, you at your laptop with a private SSH key and a known public IP. In the middle, the Azure edge: your request hits a public IP bound to the VM’s network interface (NIC), guarded by a network security group whose one inbound rule says “TCP 22 from my IP” — everything else denied. On the right, the VM inside a subnet (10.0.0.0/24) of a virtual network (10.0.0.0/16), with a private IP, an OS disk (Standard SSD holding Ubuntu), and its compute.

When you type ssh azureuser@<public-ip>, the packet flows laptop → internet → public IP → NSG (checked, allowed) → NIC → VM, where sshd answers on 22; because the NSG is stateful, that one inbound rule suffices and the reply returns automatically. That is the whole model — a guarded door (NSG) in front of a networked box (NIC + subnet) backed by a disk, reached through one address — all in a single resource group so cleanup is one command. The lab builds exactly this; the teardown deletes exactly this.

Real-world scenario

Meghana, a backend developer at a 40-person Pune logistics startup, RouteCrate, is told on a Friday to “stand up a box to run the new label-printing service over the weekend so QA can hammer it Monday.” It needs Python and a few packages, must be reachable by three QA engineers, and must not cost much — the team’s Azure budget is tracked tightly in INR.

She has never built a VM solo. Her first instinct is the portal wizard, and she nearly clicks straight through: it defaulted to a Standard_D2s_v5 with Premium SSD and offered SSH from Any. She catches herself — switches to Standard_B2s (plenty for a label service at a fraction of the price), the disk to Standard SSD, picks Ubuntu 22.04 LTS and SSH public key, and lets it create the VNet and NSG, planning to fix the SSH source after. The VM is up in a minute; she immediately changes the NSG SSH source from Any to her office CIDR 203.0.113.0/24 plus the three engineers’ home IPs, SSHes in (chmod 600 on the key first — a step the portal never reminds you about), runs sudo apt update && sudo apt install -y python3-pip, deploys, and opens port 8080 only to the same trusted IPs.

The Friday discipline pays off twice. When one QA engineer “can’t connect,” she checks the NSG, sees their IP missing (mobile data, not office WiFi), and adds it in thirty seconds — far better than the box having been open to the world. And auto-shutdown at 9 PM IST means it runs ~30 hours over the weekend instead of 72, costing under ₹300. On Monday she captures it as Bicep — the next environment is one az deployment command. The lesson she repeats to new hires: the wizard’s defaults optimise for “it works,” not “cheap and safe” — those two you choose yourself.

Advantages and disadvantages

A VM gives you a whole machine, which is its strength and its burden. The trade-off, plainly:

Advantages of a VM Disadvantages of a VM
Full control — any OS, any software, kernel-level access You own all OS patching, hardening and maintenance
Familiar mental model (it’s just a server) More to manage than PaaS/serverless (no auto-scale by default)
Runs literally anything, including legacy apps Pay even when idle unless you deallocate
Lift-and-shift from on-prem with minimal change You must secure it (open ports = your problem)
Predictable, fixed performance per SKU Slower to scale than containers/functions
Per-second billing; throw it away anytime Disk bills continue while the VM is merely stopped

Right tool: legacy or stateful apps, a specific OS/kernel, GPU workloads, full-control dev boxes, lift-and-shift. Wrong tool: stateless web apps (App Service), event-driven glue (Functions), microservices at scale (AKS/Container Apps) — all of which hand OS-patching and scaling back to Azure. As a first step, though, the VM teaches the fundamentals everything else builds on.

Hands-on lab

This is the centrepiece. You will deploy the same Ubuntu VM three ways — portal, az CLI, Bicep — connect, validate, and tear it down. The portal shows every field, the CLI shows how fast scripting is, the Bicep shows version-controlled infra. Everything goes into one resource group, rg-firstvm-lab. Windows + RDP differences are called out throughout.

Cost note: a Standard_B1s with a Standard SSD, run only during the lab and then deleted, costs a few rupees. Do not leave it running — the teardown removes everything.

Part 0 — Prerequisites and a key pair

  1. Have an Azure subscription (a free account works) and sign in to portal.azure.com.

  2. Pick your tooling: for the CLI parts, Azure Cloud Shell (the >_ icon) has az pre-installed and pre-authenticated; or install the CLI locally and run az login.

  3. Know your own public IP (you will lock SSH/RDP to it):

    curl -s https://api.ipify.org ; echo
    # → e.g. 203.0.113.45   (this is YOUR_IP for the rest of the lab)
    

    Expected: one IPv4 address; use it as YOUR_IP/32.

  4. Generate an SSH key pair (skip if you use the portal’s “Generate new key pair”):

    ssh-keygen -t rsa -b 4096 -f ~/.ssh/firstvm_key -N ""
    # Creates ~/.ssh/firstvm_key (private) and ~/.ssh/firstvm_key.pub (public)
    

    Expected: two files; the .pub one is the public key you hand to Azure.

Part A — Deploy via the Azure portal (see every field)

For understanding, fill the five tabs deliberately.

  1. Click Create a resource → Virtual machine (or search “Virtual machines” → Create). You land on the Basics tab.
  2. Project details:
    • Subscription: your subscription.
    • Resource group: Create new, name it rg-firstvm-lab — your blast radius and cleanup target.
  3. Instance details:
    • Virtual machine name: vm-firstvm-01.
    • Region: pick the closest cheap region, e.g. (Asia Pacific) Central India or (US) East US.
    • Availability options: No infrastructure redundancy required.
    • Security type: Standard (or Trusted launch).
    • Image: Ubuntu Server 22.04 LTS - x64 Gen2. (Windows: Windows Server 2022 Datacenter.)
    • Size: See all sizesStandard_B1s (B2s for more headroom).
  4. Administrator account:
    • Authentication type: SSH public key (Windows: Password — set a strong username/password); Username: azureuser.
    • SSH public key source: Use existing public key and paste ~/.ssh/firstvm_key.pub, or Generate new key pair (download the private key now — you cannot re-download it).
  5. Inbound port rules: Allow selected portsSSH (22) (Windows: RDP (3389)). Heed the “exposed to the internet” warning — we tighten the source in step 9.
  6. Next: DisksOS disk type: Standard SSD (LRS); leave the rest default. (Premium SSD for production.)
  7. Next: Networking → let Azure create new for the Virtual network (10.0.0.0/16), Subnet (10.0.0.0/24), Public IP (Standard), and NSG = Basic with the SSH rule. Leave Delete public IP and NIC when VM is deleted ticked.
  8. Skip Management/Monitoring/Advanced/Tags, click Review + create. Expected output: a green Validation passed banner and a cost-per-hour estimate.
  9. Click Create. Deployment runs ~30–90 s. Expected output: Your deployment is complete, listing the VM, disk, NIC, public IP, NSG and VNet. Click Go to resource.
  10. Lock the SSH source to your IP — immediately. VM blade → Networking → the port-22 inbound rule → change Source from Any to IP AddressesSource IP addresses/CIDR ranges = YOUR_IP/32Save. Expected: the rule shows your IP; the internet can no longer reach port 22.

Validate: on the VM Overview, copy the Public IP address, then from your laptop:

chmod 600 ~/.ssh/firstvm_key      # macOS/Linux: private key must not be world-readable
ssh -i ~/.ssh/firstvm_key azureuser@<PUBLIC_IP>
# Accept the host fingerprint the first time (type: yes)

Expected: an Ubuntu shell prompt like azureuser@vm-firstvm-01:~$. You are in. (Windows: open Remote Desktop, enter the public IP, then azureuser and your password.)

Part B — Deploy via the az CLI (the fast, scriptable way)

The same VM in a handful of commands, in Cloud Shell or a local authenticated az. The VM name (vm-firstvm-cli) differs from Part A’s, so both share the rg-firstvm-lab group.

  1. Set variables (edit YOUR_IP):

    RG=rg-firstvm-lab
    LOC=centralindia            # or eastus
    VM=vm-firstvm-cli
    YOUR_IP=203.0.113.45        # from Part 0, step 3
    
  2. Create the resource group:

    az group create --name $RG --location $LOC
    

    Expected: JSON with "provisioningState": "Succeeded".

  3. Create the VM — one command builds the VNet, subnet, NIC, public IP, NSG (SSH open) and disk:

    az vm create \
      --resource-group $RG \
      --name $VM \
      --image Ubuntu2204 \
      --size Standard_B1s \
      --admin-username azureuser \
      --ssh-key-values ~/.ssh/firstvm_key.pub \
      --storage-sku StandardSSD_LRS \
      --public-ip-sku Standard \
      --nsg-rule SSH \
      --output table
    

    Expected: a table with publicIpAddress, privateIpAddress, powerState: VM running. Note the publicIpAddress.

    To auto-generate a key instead, replace --ssh-key-values ... with --generate-ssh-keys. (Windows: drop the SSH flags, add --admin-password '<StrongP@ssw0rd!>', use --image Win2022Datacenter and --nsg-rule RDP.)

  4. Lock SSH to your IP (--nsg-rule SSH opened it to Any). Find the NSG name, then update the rule source:

    NSG=$(az network nsg list -g $RG --query "[0].name" -o tsv)
    az network nsg rule update \
      --resource-group $RG --nsg-name $NSG --name default-allow-ssh \
      --source-address-prefixes $YOUR_IP/32 \
      --output table
    

    Expected: the rule with sourceAddressPrefix: 203.0.113.45/32; the world can no longer reach port 22.

    If the auto-created rule has a different name, list with az network nsg rule list -g $RG --nsg-name $NSG -o table and update the SSH one.

  5. Connect and validate:

    IP=$(az vm show -d -g $RG -n $VM --query publicIps -o tsv)
    ssh -i ~/.ssh/firstvm_key azureuser@$IP
    

    Expected: the Ubuntu prompt. (Inside, nproc && free -h && lsb_release -a reports 1 vCPU, ~1 GiB, Ubuntu 22.04 — see Part D.)

  6. Optional — set auto-shutdown so you never forget it running:

    az vm auto-shutdown \
      --resource-group $RG --name $VM \
      --time 1530 --email h.vinod@gmail.com   # 1530 UTC = 21:00 IST
    

    Expected: JSON confirming the shutdown-computevm-... schedule.

The CLI flags, so you can adapt the command:

Flag What it sets Common values If you omit it
--image OS image Ubuntu2204, Win2022Datacenter, RHELRaw9 Required (no default)
--size VM SKU Standard_B1s, Standard_B2s, Standard_D2s_v5 Defaults to a D-series (often pricier)
--admin-username Login user azureuser Required
--ssh-key-values / --generate-ssh-keys SSH public key path to .pub, or auto-generate Prompts/uses password
--storage-sku OS disk tier StandardSSD_LRS, Premium_LRS Defaults to Premium (costs more)
--nsg-rule Auto inbound rule SSH, RDP, NONE Opens nothing if NONE
--public-ip-sku / --zone Public IP tier / availability zone Standard; 1/2/3 Standard default; no zone

Part C — Deploy via Bicep (version-controlled, repeatable)

Bicep is Azure’s native infrastructure-as-code language. The self-contained file below builds the same VM — VNet, public IP, NSG, NIC and VM — and is what you commit to git so any teammate recreates it identically. Save it as firstvm.bicep.

param adminUsername string = 'azureuser'
param sshPublicKey string                  // contents of ~/.ssh/firstvm_key.pub
param mySourceIp string                     // e.g. '203.0.113.45/32' — locks SSH to you
param location string = resourceGroup().location
param vmName string = 'vm-firstvm-bicep'

resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' = {
  name: '${vmName}-vnet'
  location: location
  properties: {
    addressSpace: { addressPrefixes: ['10.0.0.0/16'] }
    subnets: [ { name: 'default', properties: { addressPrefix: '10.0.0.0/24' } } ]
  }
}

resource pip 'Microsoft.Network/publicIPAddresses@2023-09-01' = {
  name: '${vmName}-pip'
  location: location
  sku: { name: 'Standard' }
  properties: { publicIPAllocationMethod: 'Static' }
}

resource nsg 'Microsoft.Network/networkSecurityGroups@2023-09-01' = {
  name: '${vmName}-nsg'
  location: location
  properties: {
    securityRules: [ {
      name: 'Allow-SSH-From-MyIP'
      properties: {
        priority: 1000
        direction: 'Inbound'
        access: 'Allow'
        protocol: 'Tcp'
        sourceAddressPrefix: mySourceIp   // your IP only — never '*'
        sourcePortRange: '*'
        destinationAddressPrefix: '*'
        destinationPortRange: '22'
      }
    } ]
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2023-09-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    ipConfigurations: [ {
      name: 'ipconfig1'
      properties: {
        subnet: { id: '${vnet.id}/subnets/default' }   // the subnet created above
        publicIPAddress: { id: pip.id }
        privateIPAllocationMethod: 'Dynamic'
      }
    } ]
    networkSecurityGroup: { id: nsg.id }
  }
}

resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = {
  name: vmName
  location: location
  properties: {
    hardwareProfile: { vmSize: 'Standard_B1s' }
    storageProfile: {
      imageReference: { publisher: 'Canonical', offer: '0001-com-ubuntu-server-jammy', sku: '22_04-lts-gen2', version: 'latest' }
      osDisk: { createOption: 'FromImage', managedDisk: { storageAccountType: 'StandardSSD_LRS' } }
    }
    osProfile: {
      computerName: vmName
      adminUsername: adminUsername
      linuxConfiguration: {
        disablePasswordAuthentication: true
        ssh: {
          publicKeys: [ {
            path: '/home/${adminUsername}/.ssh/authorized_keys'
            keyData: sshPublicKey
          } ]
        }
      }
    }
    networkProfile: { networkInterfaces: [ { id: nic.id } ] }
  }
}

output publicIp string = pip.properties.ipAddress

Deploy it into the same resource group:

az deployment group create \
  --resource-group rg-firstvm-lab \
  --template-file firstvm.bicep \
  --parameters \
      sshPublicKey="$(cat ~/.ssh/firstvm_key.pub)" \
      mySourceIp="203.0.113.45/32"

Expected: "provisioningState": "Succeeded" and an outputs.publicIp value; SSH to it as before. The win over both prior methods: this NSG is born locked to your IP — no “open then tighten” gap, because sourceAddressPrefix is your IP from the first deploy. That is why teams move VM creation into Bicep.

Part D — Validate the deployment

Whichever path you used, confirm the box is healthy:

Check Command / action Expected result
VM is running az vm get-instance-view -g $RG -n $VM --query "instanceView.statuses[?starts_with(code,'PowerState')].displayStatus" -o tsv VM running
You can SSH in ssh -i ~/.ssh/firstvm_key azureuser@$IP Ubuntu shell prompt
Port 22 is locked to you az network nsg rule list -g $RG --nsg-name $NSG --query "[?destinationPortRange=='22'].sourceAddressPrefix" -o tsv your IP/32, not *
Size & OS match inside the VM: nproc; free -h; lsb_release -d 1 vCPU, ~1 GiB, Ubuntu 22.04
Outbound works inside the VM: `curl -sI https://www.microsoft.com head -1`

Part E — Teardown (do not skip this)

One command deletes the VM, disk, NIC, public IP, NSG and VNet together — zero billable leftovers:

az group delete --name rg-firstvm-lab --yes --no-wait
az group exists --name rg-firstvm-lab     # → false once deletion finishes

Expected: the prompt returns immediately (--no-wait); deletion finishes in a couple of minutes. (In the portal: Resource groups → rg-firstvm-lab → Delete.) This is why everything went into one group: delete the group, and the bill stops. A VM “stopped” from inside the OS, or a disk orphaned by a half-deleted VM, keeps charging — the group delete guarantees a clean exit.

Common mistakes & troubleshooting

The failures every first-timer hits, with the exact way to confirm and fix each.

# Symptom Root cause How to confirm Fix
1 ssh hangs then times out NSG source is not your IP (or your IP changed) az network nsg rule list -g $RG --nsg-name $NSG -o table — check the port-22 source Update the rule source to your current IP/32
2 Permission denied (publickey) Wrong key, or wrong username ssh -v -i <key> azureuser@IP shows which key is offered Use the matching private key; user is azureuser
3 WARNING: UNPROTECTED PRIVATE KEY FILE! Private key is world-readable (macOS/Linux) ls -l ~/.ssh/firstvm_key shows rw-r--r-- chmod 600 ~/.ssh/firstvm_key
4 RDP “can’t connect” to Windows VM Port 3389 not open to your IP, or VM still booting NSG rule for 3389; VM Overview shows running Open 3389 from your IP; wait for boot to finish
5 az vm create fails: SKU not available That size isn’t offered in that region az vm list-skus -l $LOC --size Standard_B --query "[].name" -o tsv Pick an available size or change region
6 Quota error: “Operation could not be completed… quota” Subscription vCPU quota for that family is 0/low (common on new/free) error names the family + region Pick a family you have quota for, or request a quota increase
7 Bill is higher than expected on an idle VM You stopped the OS but didn’t deallocate Portal shows Stopped not Stopped (deallocated) az vm deallocate -g $RG -n $VM to release compute
8 VM deleted but charges continue Orphaned managed disk / static public IP left behind az disk list -g $RG -o table; az network public-ip list -g $RG -o table Delete the resource group, not just the VM
9 Forgot the password / lost the SSH key No way to log in n/a Reset via VM → Reset password (uses the VMAccess extension)
10 Can SSH but apt/outbound fails An NSG/UDR blocks outbound, or there is no outbound path inside VM curl -I https://microsoft.com hangs Ensure default outbound is allowed; see the VNet guide below

For connectivity problems that survive the table — packets that leave your laptop but never reach the VM, or outbound that mysteriously fails — work through Diagnosing Azure VNet Connectivity: NSGs, UDRs, Effective Routes & Network Watcher, whose effective security rules and Network Watcher tools show exactly which rule allowed or dropped a flow.

The single highest-value habit: when SSH/RDP won’t connect, check the NSG source first — the cause of most first-VM connection failures, almost always because the rule is still Any or your home IP rotated.

Best practices

Security notes

A VM exposed to the internet is attacked continuously, so security is non-negotiable from minute one. Least exposure: allow management ports only from trusted sources — an open 0.0.0.0/0 rule on 22 or 3389 is found and brute-forced within minutes. Beyond a throwaway lab, give the VM no public IP: use a private subnet behind Azure Bastion (browser-based RDP/SSH, no public IP, no open ports) or a VPN.

Identity: control who manages the VM with Azure RBAC — grant Virtual Machine Contributor, not Owner; for logging into the OS, Microsoft Entra login brings MFA/Conditional Access to SSH/RDP. Secrets: never bake credentials into the VM — store them in Azure Key Vault: Secrets, Keys and Certificates Done Right and give the VM a managed identity to fetch them. Encryption: managed disks are encrypted at rest by default; enable Azure Disk Encryption or customer-managed keys for stricter needs. Patching: an unpatched guest OS is the most common real VM compromise — keep it current, store the SSH key with chmod 600, never commit it to git, and rotate it if exposed.

Cost & sizing

A VM’s bill has three independent parts. Compute is charged per second while allocated (running) and is the largest line — it stops the instant you deallocate. Disk is charged continuously, even when stopped, until you delete it. Public IP (Standard) carries a small hourly charge whether or not the VM runs. What drives the bill:

Cost driver Billed when Rough order of magnitude How to control it
Compute (the VM size) While running/allocated ₹650+ / ~US$8+ per month for B1s, up linearly with SKU Deallocate when idle; auto-shutdown; smaller SKU
OS managed disk Always (even stopped) ~₹150–500 / ~US$2–6 per month (Standard vs Premium) Standard SSD for dev; delete with the RG
Public IP (Standard) While allocated to a resource ~₹250–350 / ~US$3–4 per month Skip it (use Bastion); release when unused
Outbound data transfer Per GB egressed to internet Pennies for light use; free inbound Keep traffic in-region; cache
Software (some images) Per hour for commercial images Varies; Ubuntu/Win base = infra only Use license-free images; Hybrid Benefit

Two facts save the most money: deallocate ≠ stop-from-inside (only the portal Stop / az vm deallocate ends the compute charge), and a deleted VM can keep billing if its disk or static public IP are left behind — hence tearing down the whole resource group. For sizing, start small: B1s for learning, B2s/B2ms for a dev box, D-series only for sustained CPU. Free credit (~₹15,000 / US$200 over 30 days) covers far more VM-hours than a beginner uses if you turn the box off — a B1s run two hours a day for a month is under ₹100. Confirm rates in the Azure Pricing Calculator and set a budget and alert in Cost Management.

Interview & exam questions

1. Difference between “Stopped” and “Stopped (deallocated)”? “Stopped” (a shutdown from inside the guest) leaves the VM allocated, so compute keeps billing. “Stopped (deallocated)” — the portal Stop or az vm deallocate — releases the compute; you still pay disks and any static public IP. (AZ-900 / AZ-104.)

2. In the shared responsibility model, who manages what for an IaaS VM? Microsoft manages the datacentre, hardware, hypervisor and physical network. You manage the guest OS and its patches, runtime, apps, OS/NSG firewall, data, and identity. Rule of thumb: “from the OS up is yours.” (AZ-900.)

3. Why never open RDP (3389) or SSH (22) to Any/0.0.0.0/0? Internet-facing management ports are scanned and brute-forced within minutes of exposure. Scope the NSG source to your own IP/CIDR, or drop the public IP and use Azure Bastion. (AZ-104 / SC-900.)

4. What is a Network Security Group and where do you attach it? A stateful firewall of priority-ordered allow/deny rules (direction, protocol, port, source, destination), attached to a subnet and/or a NIC. Being stateful, allowing inbound automatically permits the return traffic. (AZ-104.)

5. What does the B-series give you and when is it right? A low baseline CPU that banks credits while idle and bursts when busy — cheap and ideal for dev/test, low-traffic servers and learning. Wrong for sustained high-CPU work, which needs D-series or compute-optimised. (AZ-104.)

6. Name the resources a single VM deployment creates. The VM, an OS managed disk, a NIC, optionally a public IP, an NSG, and a VNet/subnet. This matters for cost (disks and static IPs bill independently) and cleanup (delete the resource group). (AZ-104.)

7. What disk types does Azure offer and which fits a first VM? Standard HDD (cheapest), Standard SSD (dev/test), Premium SSD (low-latency, production default) and Ultra/Premium SSD v2 (demanding databases). A first or dev VM uses Standard SSD; production uses Premium or higher. (AZ-104.)

8. Why prefer SSH keys over passwords for Linux VMs? Key auth removes a guessable secret — no password to brute-force. The private key stays on your machine, the public key on the VM; with port 22 locked to your IP, attack surface drops sharply. (AZ-104 / SC-900.)

9. How do you connect to a VM with no public IP? Use Azure Bastion (managed browser-based RDP/SSH over the private network), or a VPN/ExpressRoute into the VNet, then reach the private IP — the recommended production pattern. (AZ-104.)

10. What is Bicep and why deploy a VM with it instead of the portal? Bicep is Azure’s declarative infrastructure-as-code language (compiles to ARM). It makes deployments repeatable, version-controlled and reviewable, and bakes in safe defaults — like an NSG rule locked to your IP — so every environment is identical and secure by construction. (AZ-104.)

11. Why might az vm create fail with a quota or “SKU not available” error? “SKU not available” means that size is not offered in that region — change size or region. A quota error means the subscription’s vCPU quota for that family/region is exhausted (often 0 on new/free subscriptions); request an increase or pick a family with headroom. (AZ-104.)

12. After deleting a VM, why might billing continue, and how do you prevent it? The managed disk and any static public IP survive a VM delete and keep billing. Deploy into a dedicated resource group and delete the group to remove all dependent resources at once. (AZ-900 / AZ-104.)

Quick check

  1. You shut the VM down from inside Ubuntu with sudo poweroff. Are you still paying for compute? Why?
  2. Which port do you open for Linux remote access, which for Windows, and from what source should each be allowed?
  3. Name three resources, besides the VM itself, that a portal VM deployment creates.
  4. Your ssh connection times out immediately. What is the most likely cause and the first thing to check?
  5. What single Azure CLI command removes the VM and its disk, NIC, public IP, NSG and VNet together?

Answers

  1. Yes. A shutdown from inside the guest leaves the VM allocated to hardware, so compute keeps billing. Only deallocating (portal Stop or az vm deallocate) releases the hardware and stops the compute charge.
  2. Port 22 (SSH) for Linux, port 3389 (RDP) for Windows — each allowed only from your own IP/CIDR, never from Any/0.0.0.0/0.
  3. Any three of: OS managed disk, network interface (NIC), public IP address, network security group (NSG), virtual network + subnet.
  4. The NSG inbound rule for your management port is not allowing your source IP — it is still Any (insecure) or your home IP changed. Check/Update the rule’s source to your current IP/32 first.
  5. az group delete --name rg-firstvm-lab --yes — deleting the resource group removes every resource inside it in one operation.

Glossary

Next steps

AzureVirtual MachinesComputeaz CLIBicepIaaSBeginnerNSG
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading