Create an Azure VM with CLI

Learn to create a virtual machine with Azure CLI in this Azure Tutorial lesson. Hands-on steps, troubleshooting, and what's next.

Focus: create a virtual machine with azure cli

Sponsored

You know the drill: you’re staring at a blank terminal, your app needs a Linux box in the cloud, and you could click through the portal for twenty minutes—or you could type one command and be done. Creating an Azure VM by hand in the portal is slow, error-prone, and impossible to script. This lesson shows you how to create a virtual machine with Azure CLI in under five minutes, using a single, repeatable command that you can drop into CI/CD pipelines or share with your team. By the end, you’ll not only have a running VM, but you’ll understand the moving parts that make it tick—and how to avoid the classic pitfalls that trip up beginners.

The problem this lesson solves

Provisioning a virtual machine in Azure traditionally means logging into the portal, clicking through a dozen blades, answering questions about disks, networking, and authentication, and hoping you didn’t miss a setting. That approach has three serious problems:

  • It’s slow. Every click adds seconds, and a full VM deployment can take 10–15 minutes of manual labor.
  • It’s not repeatable. If you need the same VM again—say, for staging or QA—you have to remember every choice you made.
  • It’s error-prone. One misclick can leave you with a VM in the wrong region, an oversized disk, or no SSH access.

The Azure CLI solves all three. It lets you define your VM in a single, declarative command that you can run, modify, version, and share. No portal, no clicking, no guesswork. For developers who live in the terminal—especially those already using tools like Python or Terraform—the CLI is the fastest path from “I need a VM” to “my VM is ready.”

Core concept / mental model

Think of the Azure CLI as a remote control for Azure. It sends HTTP requests to the Azure Resource Manager (ARM) API, which is the control plane that creates, updates, and deletes resources. When you run az vm create, you’re not just creating a VM—you’re orchestrating a whole stack of dependencies that appear automatically if they don’t already exist.

Here’s a mental model: the VM is like a house, but you don’t see the foundation, plumbing, or electrical wiring unless you ask for them separately. The az vm create command is the general contractor who, by default, brings along:

  • Resource group — the plot of land where everything lives (.e.g., MyResourceGroup)
  • Virtual network and subnet — the road and sidewalks connecting your VM to the internet
  • Public IP address — the house number that lets you find it from outside
  • Network security group (NSG) — the security guard who decides who can knock on the door
  • Network interface (NIC) — the mailbox that connects the VM to the network
  • OS disk — the hard drive where the operating system lives
  • SSH keys or password — the keys to the front door

When you run az vm create with just a name and an image, the CLI creates all of these for you in the background. If they already exist, it reuses them. That’s why you can get a VM up in a single command—but also why you need to understand what’s happening under the hood when something goes wrong.

How it works step by step

Before you type anything, make sure you’re logged in and have the right subscription selected. Then follow these steps:

  1. Log in to Azure with az login. This opens a browser window where you authorize the CLI to act on your behalf. Alternatively, use az login --service-principal for non-interactive (CI/CD) scenarios.
  2. Set your subscription with az account set --subscription "<name-or-id>" if you have more than one. Skip if you only have one subscription.
  3. Create a resource group with az group create --name <rg-name> --location <region>. This is optional—the VM command can create one for you—but it’s good practice to group related resources.
  4. Create the VM with az vm create. At minimum, provide --resource-group, --name, --image, and --generate-ssh-keys. The command will output a JSON blob that includes the public IP address and SSH port.
  5. Connect to the VM using ssh <username>@<public-ip>. Use the private key if you generated one.

Each of these steps maps to a concept: the resource group is your folder, the image is the base OS template, and --generate-ssh-keys creates a key pair locally and uploads the public key to the VM, giving you passwordless authentication.

Hands-on walkthrough

Let’s walk through a complete example. Here’s the minimal command to create an Ubuntu 22.04 LTS VM:

# Log in and set subscription
az login
az account set --subscription "My Subscription"

# Create a resource group in a region near you
ez group create --name myVmResourceGroup --location eastus

# Create the VM with SSH keys
az vm create \
  --resource-group myVmResourceGroup \
  --name myFirstVm \
  --image Ubuntu2204 \
  --admin-username azureuser \
  --generate-ssh-keys

Expected output (abbreviated):

{
  "fqdns": "",
  "id": "/subscriptions/.../resourceGroups/myVmResourceGroup/providers/Microsoft.Compute/virtualMachines/myFirstVm",
  "location": "eastus",
  "macAddress": "00-0D-3A-XX-XX-XX",
  "powerState": "VM running",
  "privateIpAddress": "10.0.0.4",
  "publicIpAddress": "52.123.45.67",
  "resourceGroup": "myVmResourceGroup"
}

Note the publicIpAddress—you’ll need it to SSH. The CLI also generated a key pair in ~/.ssh (id_rsa and id_rsa.pub by default) and uploaded the public key to the VM. Now connect:

ssh azureuser@52.123.45.67

You’ll be dropped into a bash shell on a brand-new Ubuntu server. Run sudo apt update && sudo apt upgrade -y to patch it, then you’re ready to install whatever you need.

Specifying a custom size and disk

By default, the VM uses a standard size (like Standard_D2s_v3) and a 30GB OS disk. To control cost and performance, set --size and --os-disk-size-gb:

ez vm create \
  --resource-group myVmResourceGroup \
  --name myCustomVm \
  --image Ubuntu2204 \
  --size Standard_B1s \
  --os-disk-size-gb 64 \
  --admin-username azureuser \
  --ssh-key-value ~/.ssh/id_rsa.pub

Use --ssh-key-value to reuse an existing key instead of generating a new one. The Standard_B1s size is cheap and perfect for low-traffic workloads.

Using a password for authentication

If you prefer a password over SSH keys, omit the SSH flags and set --admin-password:

ez vm create \
  --resource-group myVmResourceGroup \
  --name myPasswordVm \
  --image Ubuntu2204 \
  --admin-username azureuser \
  --admin-password 'S3cureP@ssw0rd123!'

Pro tip: Always use SSH keys for production. Passwords are easier to brute-force. If you must use a password, make it long and complex—and never commit it to a repo.

Using a custom image or marketplace image

--image accepts a URN like Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:latest or a custom image ID. For example, to use a custom image from a shared image gallery:

ez vm create \
  --resource-group myVmResourceGroup \
  --name myCustomImageVm \
  --image /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Compute/galleries/<gallery>/images/<definition>/versions/latest \
  --admin-username azureuser \
  --generate-ssh-keys

This is how you codify golden images that include your security patches and pre-installed software.

Compare options / when to choose what

You have three primary ways to create a VM: Azure CLI, PowerShell (for Windows-centric workflows), and the Azure portal. Here’s a quick comparison:

Method Repeatable Scriptable Speed Best for
Azure CLI Yes Yes Fast DevOps, automation, infrastructure-as-code
Azure PowerShell Yes Yes Fast Windows admins, Microsoft tooling familiarization
Azure portal No No Slow (clicks) One-off exploration, learning UI

Within the CLI itself, you can use az vm create directly or wrap it in Bicep/Terraform templates. The direct command is great for ad-hoc needs—like spinning up a test VM for a quick experiment. For production, you’ll likely want to use Infrastructure as Code (Bicep or Terraform) so that the entire stack is versioned and deployable to multiple environments.

Troubleshooting & edge cases

Even with a single command, things can go sideways. Here are the most common issues and how to fix them:

  • ERROR: Please install the azure-ai-ml extension first This is a common copy-paste error when you accidentally run a training-cli command. Install the extension with az extension add -n ml or ignore it if you’re creating a regular VM.

  • SSH connection refused Make sure you’re using the correct username and public IP. If you used --generate-ssh-keys, the CLI printed the public IP in the output. Double-check the username—it’s not admin, it’s whatever you passed to --admin-username. Also verify that the default NSG allows port 22 (it does by default—but if you customized the NSG, you may have blocked it).

  • The subscription is not registered to use namespace Microsoft.Compute Run az provider register --namespace Microsoft.Compute and also register Microsoft.Network. This happens when the subscription hasn’t used compute before. The CLI usually does this automatically, but you might hit it in fresh subscriptions.

  • QuotaExceeded errors Your subscription may have a vCPU limit in a region. Check with az vm list-usage --location eastus, then request a quota increase via the portal, or choose a different region.

  • .ssh directory has no files If you run --generate-ssh-keys and ~/.ssh is empty, make sure you have write access and the CLI didn’t silently fail. Run ls ~/.ssh—if it’s empty, rerun the command with --debug to see why.

What you learned & what's next

You now know how to create a virtual machine with Azure CLI—from minimal one-liner to custom image and size. You understand the supporting resources that the CLI provisions behind the scenes, how to connect via SSH, and how to avoid common pitfalls. You also learned how to compare the CLI with PowerShell and the portal, and when to prefer IaC templates.

Your next lesson in this Azure Tutorial track is Deploy an Azure Function App. That extends your VM knowledge into serverless territory—where you don’t manage any infrastructure at all. You’ll use the same CLI pattern (az functionapp create) but skip the VM entirely. The mental model you built here—resource groups, regions, and command-line provisioning—will carry over seamlessly.

As a preview, here’s a taste of what’s coming:

# Create a function app (requires a storage account and plan first)
az functionapp create \
  --resource-group myFunctionAppResourceGroup \
  --consumption-plan-location eastus \
  --runtime python \
  --functions-version 4 \
  --name myUniqueFunctionAppName \
  --storage-account mystorageaccount123

Now go create a VM—and then destroy it after you’re done to avoid charges (hint: az vm delete --resource-group myVmResourceGroup --name myFirstVm).

Practice recap

Try creating a second VM with a different size and image (e.g., Debian) and connect via SSH. Then run az vm show --resource-group myVmResourceGroup --name myFirstVm --query '{powerState:powerState, location:location}' -o table to inspect its state. Finally, clean up by deleting both VMs and the resource group.

Common mistakes

  • Forgetting to set the destination resource group when reusing a name, causing a conflict or unexpected placement — always pass --resource-group explicitly.
  • Using --admin-username root — Azure requires a non-root user; use azureuser or a similar name.
  • Overlooking the VM size cost — free-tier sizes like Standard_B1s are fine for dev, but production VMs need larger sizes.
  • Assuming the VM is reachable on port 22 — if you customize the NSG, re-open the inbound rule.
  • Not deleting the VM after testing — leaving it running racks up billing; delete the resource group when done.

Variations

  1. Use az vm create with --password instead of SSH keys for quick non-production tests.
  2. Use a pre-existing network and subnet by passing --vnet-name and --subnet to reuse infrastructure.
  3. Wrap the CLI command in Bicep or Terraform for full infrastructure-as-code with drift detection.

Real-world use cases

  • Spinning up a temporary Linux build server for a CI pipeline, then deleting it after the job completes.
  • Deploying a staging VM with a custom image to test configuration management and application updates.
  • Automating VM creation for a training lab where each participant gets an isolated Ubuntu environment via a script.

Key takeaways

  • The Azure CLI provisions a VM and all its dependencies in a single, repeatable command.
  • SSH keys are the recommended authentication method; passwords are a fallback for non-production.
  • Always specify a resource group and region to avoid surprises.
  • Review the output JSON for the public IP and SSH command — that's how you connect.
  • Compare CLI, PowerShell, and portal to choose the right tool for the task.
  • Destroy the VM when done to avoid unnecessary costs.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.