Deploy a Linux VM
Deploy a simple Linux VM on Azure in this hands-on tutorial. Learn core steps, troubleshooting tips, and what to study next in the Azure track.
Focus: deploy a simple linux vm
You've built APIs, configured storage, and secured secrets — but your application still runs somewhere ephemeral. Deploying a Linux VM on Azure feels like the final boss of the traditional cloud path: it's where your code becomes a living, breathing process with its own IP, disks, and network card. The good news? Azure's tooling has matured to the point where you can go from zero to a running Ubuntu server in under ten minutes — if you know the right commands and the mental model behind them. In this lesson, you'll deploy a simple Linux VM, connect to it with SSH, and learn the core pieces that make every VM tick, from resource groups to network security rules.
The problem this lesson solves
You've likely hit this wall before: your Python app works perfectly on your laptop, but the moment it must serve real users, you need a place to run it 24/7. Containers and serverless platforms are great, but sometimes you need full control — a custom kernel module, a legacy binary, or a database that just doesn't play well with managed services. A Linux virtual machine gives you that control: a complete operating system running on Azure's hardware, isolated from your machine, and reachable from anywhere.
Without understanding how to deploy a VM, you're stuck renting expensive managed services or fighting with your own hardware. This lesson removes that barrier. You'll learn the exact process to provision a VM, the network settings that make it accessible, and the security defaults that keep it safe. By the end, you'll have a real, SSH-able Linux box that you can use for development, testing, or hosting a small service.
Core concept / mental model
Think of an Azure VM as a rented computer in a data center. The machine itself is hardware you never see — but you get a virtual slice of it, with your own operating system, disks, and network interface. The Azure resource hierarchy stacks neatly like Russian dolls:
- Subscription — the billing boundary; everything you create belongs to it.
- Resource group — a folder that holds related resources (VM, disk, network interface, etc.).
- Virtual machine — the compute element, defined by a size (CPU/memory) and an image (Ubuntu, Red Hat, etc.).
- Networking — a virtual network with a public IP, a network interface, and a network security group (NSG) that acts as a firewall.
In other words: you don't just create a VM. You create a package of resources that work together. The VM's operating system lives on managed disks (Azure-managed storage attached to the VM), and the network lets you reach it over SSH.
Here's a minimal diagram in words:
Azure Subscription
└── Resource group: rg-demo-vm
├── Virtual network: vnet-demo
│ └── Subnet: default
├── Public IP: 52.186.25.33
├── Network interface: vm-nic
│ └── Network security group: nsg-demo (allows SSH)
├── Managed OS disk: 30 GB SSD
└── Virtual machine: vm-demo (Standard_B2s, Ubuntu 24.04)
This layered approach means you can destroy the VM while keeping the disk, or reshape the network without touching your data. Once you internalize the hierarchy, Azure's console becomes less mysterious and more like assembling Lego pieces.
How it works step by step
You can deploy a VM through the Azure portal, the Azure CLI, or infrastructure as code. This lesson focuses on the Azure CLI because it's scriptable, repeatable, and gives you the clearest cause-and-effect view of what you're creating. Here's the logical sequence:
- Authenticate — ensure you're logged into Azure and have an active subscription.
- Create a resource group — a container for all VM components.
- Create the VM — one command that juggles the VM itself, a public IP, a network interface, and an OS disk, all wired together.
- Verify and connect — check the VM is running and SSH into it.
- Clean up — delete the resource group to avoid ongoing costs.
Each step has a purpose. Step 3 is the magic moment: Azure accepts your parameters (image, size, credentials) and provisions the resources in under a minute. The network security group is configured automatically to allow SSH (port 22) from your IP — a cautious default that you'll later tighten.
Hands-on walkthrough
Let's get practical. You'll need the Azure CLI installed, an Azure account, and a resource group to work in. If you've followed previous lessons in this track, you already have those prerequisites.
Prerequisites
az --version # Ensure Azure CLI is installed (version 2.60+ recommended)
az login # Open browser login and authenticate
az account show --query name # Confirm you're in the right subscription
Expected output: a JSON object with your subscription details. If you see an error, run az account set --subscription <your-sub-id> to switch to the correct one.
Step 1: Create a resource group
az group create --name rg-demo-vm --location eastus
This creates rg-demo-vm in the East US region. Output confirms the provisioning state (Succeeded).
Step 2: Create the Linux VM
The core command. We'll use Ubuntu 24.04 LTS, a size Standard_B2s (2 vCPUs, 4 GB RAM — enough for most dev tasks), and disable auto-shutdown for demo simplicity. Change the admin username to something unique.
az vm create \
--resource-group rg-demo-vm \
--name vm-demo \
--image Ubuntu2404 \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys
Pro tip: Running
--generate-ssh-keyscreates an SSH key pair in~/.ssh/if none exists. This is far more secure than using a password. Never use a password for production VMs.
Expected output includes a JSON object with publicIpAddress and privateIpAddress. Note the public IP — you'll need it for the next step. In about a minute, your VM is fully provisioned and running.
Step 3: Connect via SSH
ssh azureuser@<public-ip>
You'll see a fingerprint prompt — accept it. Then you're in the Ubuntu shell. Run a quick sanity check:
cat /etc/os-release
free -h
Expected output shows Ubuntu 24.04 and your memory. You now have a functioning Linux VM in the cloud.
Step 4: Clean up
When done, delete the entire resource group to stop all associated resources and billing:
az group delete --name rg-demo-vm --yes --no-wait
This removes the VM, disks, network, and public IP. No dangling resources left behind.
Compare options / when to choose what
Azure offers several ways to run Linux, and each has trade-offs. Here's a comparison to help you decide:
| Option | Effort | Cost | Use case |
|---|---|---|---|
| Simple VM (what you created) | Medium | Moderate | Full control, legacy apps, dev/test |
| Azure App Service | Low | Low | Web apps, API endpoints, built-in scaling |
| Container Apps (ACA) | Medium | Low-medium | Microservices, Kubernetes-lite, auto-scaling |
| Azure Kubernetes Service (AKS) | High | High | Large-scale distributed systems |
For this lesson, the simple VM is perfect: it's a learning tool. But in production, think about your workload. If it's a stateless web app, App Service or ACA will likely save money and effort. If you need full OS control, a VM is the way. If you're operating a fleet of services, AKS might be justified.
Variations to consider:
- Image choice: Ubuntu is popular, but Debian, RHEL, or Oracle Linux might fit your organization's compliance needs.
- Size flexibility: Standard_B2s is burstable; for consistent CPU you might want Standard_D2s_v3 (more expensive but non-burstable).
- Infrastructure as code: The same CLI commands can be embedded in Terraform or Bicep templates for repeatability.
Troubleshooting & edge cases
SSH connection refused
- Cause: The network security group blocks port 22, or the public IP changed.
- Check:
az vm show -g rg-demo-vm -n vm-demo --query networkProfileand verify the NSG allows SSH. Re-runaz vm createwith--nsg-rule SSHif you didn't use defaults. - Fix: Add an NSG rule manually:
az network nsg rule create -g rg-demo-vm -n allow-ssh --nsg-name <nsg-name> --priority 1000 --destination-port-ranges 22 --access Allow.
VM created but not accessible
- Symptom: Ping fails (ICMP is blocked by default) — that's normal. SSH is the real test.
- Cause: You may be using a password that Azure disabled because SSH keys are enabled.
- Fix: Ensure you're using the private key:
ssh -i ~/.ssh/id_rsa azureuser@<public-ip>.
Cost overrun
- Problem: VM keeps running and you're billed hourly.
- Solution: Set auto-shutdown from the portal or CLI (
az vm auto-shutdown -g rg-demo-vm -n vm-demo --time 1800), or delete the resource group when done.
Subscription disabled or quota exceeded
- Error: “Quota exceeded” or “Subscription is disabled.”
- Fix: Request a quota increase in the portal, or verify billing activation.
Public IP changes after VM restart
- Cause: Default public IP is dynamic.
- Fix: Attach a static IP using
--public-ip-address-allocation staticwhen you create the VM, or use a DNS name.
What you learned & what's next
You now know how to deploy a simple Linux VM on Azure: how to create a resource group, provision a VM with an SSH key, connect to it, and tear it down. You understand the core mental model of Azure resources nesting — subscription → resource group → VM → networking. You also know when a VM is the right choice versus a managed service like App Service or Containers.
The next lesson in this track will likely explore scale sets or load balancing — how to run multiple VMs for high availability. With your VM foundation solid, you'll be ready to apply concepts like availability zones and virtual network peering.
Go ahead and deploy your own VM, connect, and experiment with installing Python and running a simple HTTP server. That hands-on time is what cements the knowledge.
Happy provisioning!
Practice recap
Go ahead and deploy a second VM with a different size (e.g., Standard_B1s), this time using a static public IP. Connect via SSH, install Nginx, and serve a static page. Then delete the resource group and confirm the resources are gone. This repetition will solidify the workflow and prepare you for advanced VM concepts.
Common mistakes
- Using a password instead of SSH keys — Azure may disable password auth, leaving you locked out.
- Forgetting to delete the resource group after testing, incurring persistent hourly charges.
- Assuming the VM's public IP is static; it changes on stop/deallocate unless you allocate a static IP.
- Opening SSH to 0.0.0.0/0 globally — always restrict to your own IP in the NSG.
- Pinging the VM to test connectivity — ICMP is blocked by default; use SSH or
nc -vzon port 22.
Variations
- Use Azure PowerShell instead of the CLI — same concept but cmdlet syntax.
- Deploy via Infrastructure as Code with Bicep or Terraform for environmental consistency.
- Try a different VM size like Standard_B1s for cost savings, or Standard_D2s_v3 for consistent CPU.
Real-world use cases
- Hosting a Django or Flask app that requires OS-level dependencies not available in PaaS.
- Running a CI/CD build agent that must spin up isolated environments for tests.
- Setting up a development sandbox for learning Linux administration or testing software.
Key takeaways
- An Azure VM is a collection of resources (VM, disk, NIC, NSG, public IP) all under a resource group.
- The CLI command
az vm createbundles networking, disk, and compute in one step. - SSH key authentication is more secure than passwords — use
--generate-ssh-keys. - Always clean up by deleting the resource group to stop billing.
- Choose a VM only when you need full OS control; otherwise consider managed services.
- The public IP is dynamic by default — allocate static when you need stability.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.