Create an Azure VM with the CLI
A comprehensive guide to creating Azure VMs with the Azure CLI, covering resource groups, images, networking, SSH, advanced configurations, and troubleshooting.
The Azure command-line interface (CLI) provides a powerful, scriptable, and efficient way to provision and manage Azure resources. While the Azure portal offers a graphical user interface, the CLI excels in automation, repeatability, and integration into CI/CD pipelines. This article details the process of creating an Azure Virtual Machine (VM) using the Azure CLI, exploring various configuration options for network, storage, and security.
Before proceeding, ensure you have the Azure CLI installed and authenticated. The minimum recommended version is 2.50.0. You can verify your version with az --version and log in using az login.
Prerequisites: Resource Groups and Locations
Every Azure resource must reside within a resource group, which acts as a logical container for related resources. VMs also require a specific Azure region (location) for deployment. Choosing the right location is crucial for latency, compliance, and cost considerations.
Creating a Resource Group
If you don't have an existing resource group, create one using the az group create command. This example creates a resource group named rg-stackvora-demo in the eastus region.
az group create --name rg-stackvora-demo --location eastus
Commonly used locations include eastus, westus2, westeurope, uksouth, and southeastasia. You can list all available locations with az account list-locations --output table.
Basic VM Creation
The simplest way to provision a VM involves specifying the resource group, VM name, and an operating system image. Azure CLI handles the creation of default virtual networks, subnets, public IP addresses, and network security groups (NSGs) for you.
Deploying an Ubuntu VM with SSH
This command creates an Ubuntu 22.04 LTS VM named vm-stackvora-01 in the rg-stackvora-demo resource group. It generates a new SSH key pair and places the private key in ~/.ssh/id_rsa (Linux/macOS) or %USERPROFILE%\.ssh\id_rsa (Windows) by default, and configures the public key for SSH access.
az vm create \
--resource-group rg-stackvora-demo \
--name vm-stackvora-01 \
--image Ubuntu2204 \
--admin-username azureuser \
--generate-ssh-keys
Upon successful execution, the output will include the public IP address of the VM. You can then connect via SSH: ssh azureuser@<PublicIPAddress>.
Opening a Port in the NSG
By default, Azure only allows SSH (port 22) or RDP (port 3389) traffic for Linux and Windows VMs, respectively, when using --generate-ssh-keys or --admin-password. To allow other inbound traffic, you must explicitly open ports in the Network Security Group (NSG) associated with the VM's network interface.
To allow inbound HTTP traffic (port 80):
az vm open-port \
--resource-group rg-stackvora-demo \
--name vm-stackvora-01 \
--port 80 \
--priority 1010 \
--access Allow \
--protocol Tcp \
--description "Allow HTTP Inbound"
--priority defines the rule processing order (lower numbers are processed first). The default for SSH/RDP rules created by az vm create is typically 1000. Ensure your custom rules have a unique priority.
Advanced VM Configuration
For production deployments, more granular control over networking, storage, and VM size is often required.
Specifying VM Size (SKU)
Azure offers a wide range of VM sizes (SKUs), each with different CPU, memory, and disk performance characteristics. You can list available sizes for a given location using az vm list-sizes --location eastus --output table.
To create a VM with a specific size, for example, Standard_B2s:
az vm create \
--resource-group rg-stackvora-demo \
--name vm-stackvora-02 \
--image CentOS9Stream \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys
Consider the workload requirements carefully when selecting a VM size to optimize performance and cost.
Custom Networking: VNet, Subnet, and Public IP
For more robust network designs, you'll typically create your own Virtual Network (VNet), subnets, and explicitly assign a public IP or use a private IP only.
Steps involved:
- Create a VNet:
az network vnet create -g rg-stackvora-demo -n vnet-stackvora-01 --address-prefix 10.0.0.0/16 -l eastus - Create a Subnet:
az network vnet subnet create -g rg-stackvora-demo --vnet-name vnet-stackvora-01 -n subnet-app-01 --address-prefix 10.0.1.0/24 - Create a Public IP (Optional):
az network public-ip create -g rg-stackvora-demo -n pip-vm-stackvora-03 --sku Standard --allocation-method Static - Create the VM with custom network components:
az vm create \
--resource-group rg-stackvora-demo \
--name vm-stackvora-03 \
--image Debian12 \
--vnet-name vnet-stackvora-01 \
--subnet subnet-app-01 \
--public-ip-address pip-vm-stackvora-03 \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--os-disk-name vm-stackvora-03-osdisk \
--os-disk-size-gb 64 \
--os-disk-sku Standard_LRS
Note the use of --ssh-key-values to specify an existing public SSH key path. If --generate-ssh-keys is used with custom networking, it will still generate a new key pair.
Managed Disks and Storage
Azure Managed Disks abstract the underlying storage, simplifying disk management. You can specify the OS disk name, size, and SKU (Standard_LRS, Premium_LRS, StandardSSD_LRS, UltraSSD_LRS) during VM creation. Data disks can be attached later or during creation using --data-disks.
- Standard_LRS: Cost-effective, suitable for development/test and infrequently accessed data.
- StandardSSD_LRS: Balanced performance for web servers, dev/test, and small-to-medium databases.
- Premium_LRS: High-performance, low-latency, suitable for I/O-intensive workloads like production databases.
- UltraSSD_LRS: Highest performance, flexible capacity/IOPS/throughput, for demanding enterprise applications.
Example for attaching a 128GB Standard SSD data disk:
az vm create \
--resource-group rg-stackvora-demo \
--name vm-stackvora-04 \
--image RHEL9-LVM \
--admin-username azureuser \
--generate-ssh-keys \
--data-disks 128 \
--attach-data-disks 128 \
--storage-sku StandardSSD_LRS
The --data-disks 128 creates an unformatted 128GB disk, and --attach-data-disks 128 ensures it's attached. You'd still need to format and mount it within the VM.
Common Pitfalls and Troubleshooting
- Location Mismatch: Ensure your resource group, VM, VNet, and other resources are in compatible Azure regions.
- SKU Availability: Not all VM sizes are available in all regions. Use
az vm list-sizes --location <location>to verify. - SSH Key Permissions: On Linux/macOS, ensure your private SSH key has correct permissions (
chmod 600 ~/.ssh/id_rsa). - Public IP Not Found: If connecting via SSH fails, verify the public IP address using
az vm show -g <resource-group> -n <vm-name> --query publicIps --output tsv. - NSG Rules: Check NSG rules if you cannot access services running on the VM. Use
az network nsg rule list -g <resource-group> --nsg-name <nsg-name> --output tableto inspect rules. The NSG name is usually derived from the VM name or VNet. - Resource Locks: If you encounter permission errors during deletion or modification, check if any resource locks are applied to the resource group or individual resources.
- Disk Quotas: Azure subscriptions have quotas for disk types and counts. If you hit a limit, you may need to request an increase.