Deploy and Troubleshoot an Azure VM
Deploy a Linux VM on Azure and fix a broken NSG rule using the CLI.
Introduction
30 Second Summary
When something breaks in the cloud, the first person who gets paged is a support engineer. Their job is to diagnose and fix the problem fast. The most common issues involve network connectivity, and the fastest way to prove you can handle them is to build and break a network yourself.
In this project, you will deploy a Linux Virtual Machine on Azure with custom networking, then intentionally break its connectivity by misconfiguring a security rule. You will diagnose and fix the issue using the same approach cloud support engineers use daily.
What You'll Build
A fully configured Azure Virtual Machine running Ubuntu, deployed inside a custom Virtual Network with a Network Security Group you build and troubleshoot entirely through the Azure CLI in Cloud Shell.
By the end of this project, you'll have:
- A Resource Group containing a Virtual Network, Subnet, Network Security Group, and a running Linux VM you can connect to via SSH.
- Hands-on experience creating and modifying Network Security Group rules to control traffic flow using the Azure CLI.
- A completed troubleshooting scenario where you break, diagnose, and fix a network connectivity issue caused by an NSG rule priority conflict.
- Secret Mission: Set up an Azure Monitor metric alert that notifies you when your VM's CPU usage exceeds 80%.
Are there any prerequisites?
You need an existing Azure account (free or pay-as-you-go). No local tools are required because you will use Azure Cloud Shell, which runs directly in your browser.
Open Cloud Shell and Create a Resource Group
Every Azure project starts with a terminal and a place to organize your resources. You will use Azure Cloud Shell, a browser-based terminal that comes pre-loaded with the Azure CLI. No local installation required.
In this step, you will open Cloud Shell, confirm your subscription is active, and create a Resource Group. A Resource Group is a container that holds all the related resources for your project in one place.
In this step, get ready to:
- Open Azure Cloud Shell in Bash mode.
- Verify your Azure CLI connection.
- Create a Resource Group for your project.
Open Azure Cloud Shell in Bash mode
Cloud Shell is Azure's built-in terminal that runs directly in your browser. It is already authenticated with your Azure account, so you can start running commands immediately.
- Open your browser and navigate to https://portal.azure.com.
- Sign in with your Azure account credentials.
- In the top navigation bar, look for the Cloud Shell icon in the global controls area (top-right of the page header). Click it.
- When prompted to choose a shell, select Bash.
- In the Getting started pane, select No storage account required for an ephemeral session.
- Using the dropdown, select your subscription, then click Apply.
What is an ephemeral session?
An ephemeral session means Cloud Shell starts without creating a storage account. This is the fastest way to get started. Any files you create during the session are deleted when you close the window, but that is fine for this project since all your resources live in Azure, not in local files.
A Bash terminal should now appear at the bottom of your browser window.
Cloud Shell not opening?
Make sure you are clicking the Cloud Shell icon in the top navigation bar, not searching for it in the services menu. If it still does not open, try refreshing the page or opening the Azure Portal in an incognito window.
help me troubleshoot why Azure Cloud Shell is not opening in my browser
Run your first Azure CLI commands
Cloud Shell comes pre-authenticated. Your first task is to confirm that the CLI recognizes your subscription so you can safely create resources.
- Verify you are logged in by running this command:
az account show --output table
You should see a table with your subscription name, subscription ID, and state showing as Enabled.
Seeing an error or empty output?
If you see a message about not being logged in, close Cloud Shell, refresh the Azure Portal page, and reopen Cloud Shell. It should re-authenticate automatically.
help me fix my Azure CLI authentication in Cloud Shell
- Check if you have any existing resource groups by running:
az group list --output table
This may return an empty table if you have never created resources before. That is perfectly fine.
- Explore the available CLI command groups by running:
az --help
You will see a long list of command groups like vm, network, and group. These are the building blocks you will use throughout this project.
Create your project Resource Group
A Resource Group acts as a folder for all the Azure resources in your project. When you are done, you can delete the entire group to clean up everything at once.
- Create a Resource Group called myVMProject in the eastus region by running:
az group create --name myVMProject --location eastus
What does this command do?
- az group create tells the Azure CLI to create a new Resource Group.
- --name myVMProject sets the name of your group. You will reference this name in every command for the rest of the project.
- --location eastus places all resources in the East US datacenter region.
- Verify the Resource Group was created by running:
az group list --output table
You should see myVMProject listed with a location of eastus and a provisioning state of Succeeded.
Resource Group not showing as Succeeded?
Double-check that you typed the command exactly as shown, with two dashes before name and location. If you see a permission error, your Azure subscription may have restrictions. Confirm your subscription is active by re-running az account show --output table.
help me troubleshoot why my Azure Resource Group creation failed
Your environment is ready and your resources have a home. Next up, you will build the network infrastructure that your Virtual Machine will live inside.
Build the Network
You have a Resource Group ready to hold your project resources. Now you need a network for your Virtual Machine to live inside.
Every VM in Azure needs a Virtual Network to communicate with other resources and the internet. In this step, you will build that network from scratch using the Azure CLI, then lock it down with a Network Security Group that only allows SSH traffic.
In this step, get ready to:
- Create a Virtual Network with a Subnet.
- Create a Network Security Group with an SSH allow rule.
- Associate the NSG with your Subnet to protect it.
Create a Virtual Network with a Subnet
A Virtual Network defines a private address space where your Azure resources can talk to each other. A Subnet is a subdivision of that address space that groups related resources together.
- Create a Virtual Network called myVNet with a subnet called mySubnet by running this command in Cloud Shell:
az network vnet create --resource-group myVMProject --name myVNet --address-prefix 10.0.0.0/16 --subnet-name mySubnet --subnet-prefix 10.0.1.0/24
What does this command do?
This single command creates both the VNet and a subnet inside it at the same time.
- --address-prefix 10.0.0.0/16 defines the overall address space for the VNet (65,536 possible addresses).
- --subnet-prefix 10.0.1.0/24 carves out a smaller range (256 addresses) for your subnet.
- Verify your VNet was created by running:
az network vnet show --resource-group myVMProject --name myVNet --output table
You should see myVNet listed with a location of eastus and a Succeeded provisioning state.
Not seeing your VNet?
- Double check that you typed --resource-group myVMProject exactly. Resource group names are case-sensitive.
- Make sure the az network vnet create command finished without errors before running the show command.
Help me troubleshoot why my VNet was not created in Azure Cloud Shell.
Create a Network Security Group and add an SSH rule
A Network Security Group acts as a virtual firewall for your subnet. It contains rules that allow or deny network traffic based on port, protocol, and direction.
- Create the NSG by running this command:
az network nsg create --resource-group myVMProject --name myNSG
- Add a rule that allows inbound SSH traffic on port 22 by running:
az network nsg rule create --resource-group myVMProject --nsg-name myNSG --name AllowSSH --protocol tcp --priority 1000 --destination-port-range 22 --access allow
What does this rule do?
- --protocol tcp targets TCP traffic (the protocol SSH uses).
- --destination-port-range 22 specifies port 22, the standard SSH port.
- --priority 1000 sets the rule's priority. Azure processes rules from lowest priority number first, so lower numbers take effect before higher ones.
- --access allow means matching traffic is permitted through.
- Verify your rules by running:
az network nsg rule list --resource-group myVMProject --nsg-name myNSG --output table
You should see the AllowSSH rule listed with priority 1000, access Allow, and protocol Tcp.
Rule list is empty?
- The az network nsg rule list command only shows custom rules you created. If you see nothing, the nsg rule create command may have failed. Scroll up in Cloud Shell to check for error messages.
- Confirm that --nsg-name myNSG matches exactly what you used in the nsg create command. Names are case-sensitive.
Help me figure out why my NSG rule is not showing up.
Associate the NSG with your Subnet
Creating an NSG does not protect anything by itself. You need to attach it to a subnet so its rules apply to all resources inside that subnet.
- Associate myNSG with mySubnet by running:
az network vnet subnet update --resource-group myVMProject --vnet-name myVNet --name mySubnet --network-security-group myNSG
What does this command do?
This updates the existing subnet to reference your NSG. From this point on, any resource deployed into mySubnet will have its traffic filtered by the rules in myNSG.
The command returns a JSON response showing the subnet details. You should see myNSG referenced in the output under the network security group field.
Seeing an error about the subnet or NSG not found?
- Make sure --vnet-name myVNet and --name mySubnet match exactly what you created in the first substep.
- Confirm --network-security-group myNSG matches the NSG name from the second substep.
Help me fix the subnet update command that cannot find my resources.
Your network is built and locked down. Next up, you will deploy a Linux VM inside this network and connect to it using SSH.
Deploy the Virtual Machine
Your network infrastructure is ready. You have a Virtual Network, a Subnet, and a Network Security Group controlling traffic.
Now it's time to deploy the actual Virtual Machine that lives inside this network. You'll create a Linux VM running Ubuntu, connect to it remotely using SSH, and confirm everything is working.
In this step, get ready to:
- Deploy a Linux VM inside your custom VNet using the Azure CLI.
- Connect to the VM via SSH from Cloud Shell.
- Verify the VM is running and has internet connectivity.
Create the VM
The az vm create command provisions a Virtual Machine along with its supporting resources (a network interface, OS disk, and public IP address). You'll point it at the VNet and Subnet you already built.
- Create your VM by running this command in Cloud Shell:
az vm create --resource-group myVMProject --name myVM --image Ubuntu2204 --vnet-name myVNet --subnet mySubnet --size Standard_B1s --admin-username azureuser --generate-ssh-keys --output json
What does this command do?
- --image Ubuntu2204 deploys an Ubuntu Server 22.04 LTS image.
- --vnet-name myVNet --subnet mySubnet places the VM inside the network you already created (instead of Azure generating a new default network).
- --size Standard_B1s selects the smallest general-purpose VM size, which is included in the Azure free tier (750 hours/month for 12 months).
- --generate-ssh-keys creates an SSH key pair for you automatically so you can connect securely without a password.
- Wait 1-2 minutes for the command to finish. When it completes, you'll see JSON output.
- Find the publicIpAddress value in the output and note it down. You'll need this to connect via SSH.
What should I see?
The JSON output includes a publicIpAddress field with a value like 20.85.123.45. Your IP address will be different. This is the address you use to reach your VM from the outside world.
Command taking too long or erroring?
If Cloud Shell disconnects due to inactivity, reopen it and run the command again. Azure will either resume the creation or report that the VM already exists.
If you see a quota error, your subscription may not have capacity for the selected VM size in eastus. Try a different region by deleting the resource group and starting fresh with a new location.
Help me troubleshoot my az vm create error
Connect via SSH
SSH lets you open a terminal session on your VM from Cloud Shell. Because your NSG allows inbound traffic on port 22, the connection should go straight through.
- Connect to your VM by running this command (replace the IP with your own):
ssh azureuser@[[PUBLIC_IP="your VM's public IP address from the previous output"]]
- When prompted with "Are you sure you want to continue connecting?", type yes and press Enter.
Why does it ask about a fingerprint?
The first time you connect to any new server via SSH, your client asks you to verify the server's identity. Typing yes saves the server's fingerprint so it won't ask again.
You are now inside your VM. Your terminal prompt changes to show azureuser@myVM.
- Confirm you're on the VM by running:
hostname
- You should see myVM printed in the output.
- Verify your VM has internet connectivity by running:
curl -s ifconfig.me
- You should see your VM's public IP address printed back to you.
- Return to Cloud Shell by running:
exit
SSH connection timed out?
If the connection hangs or times out, your NSG may not have the AllowSSH rule configured correctly. Run az network nsg rule list --resource-group myVMProject --nsg-name myNSG --output table from Cloud Shell and confirm you see a rule allowing TCP on port 22.
Also double-check that you copied the correct public IP address from the az vm create output.
Help me fix my SSH connection to the Azure VM
Verify your deployment
Now that you're back in Cloud Shell, confirm the full state of your VM using the Azure CLI.
- Check your VM's details by running:
az vm show --resource-group myVMProject --name myVM --show-details --output table
What should I see?
The table output shows your VM's key properties. Look for two things:
- PowerState shows VM running.
- PublicIps and PrivateIps columns display the IP addresses assigned to your VM.
VM not showing as running?
If the power state shows something other than VM running, the provisioning may still be in progress. Wait a minute and run the az vm show command again.
Help me check why my Azure VM isn't running
Your VM is live and reachable. Next up, you'll intentionally break network connectivity by misconfiguring an NSG rule, then diagnose and fix the problem like a cloud support engineer.
Break and Fix Network Connectivity
Your VM is deployed, connected to a custom network, and reachable over SSH. Now it's time to simulate a real-world support scenario.
Cloud support engineers frequently troubleshoot connectivity issues caused by misconfigured Network Security Group rules. In this step, you will intentionally break SSH access to your VM by adding a deny rule, diagnose why it broke, and fix it.
In this step, get ready to:
- Break SSH connectivity by adding a high-priority deny rule.
- Diagnose the NSG priority conflict that blocks traffic.
- Fix the issue by removing the blocking rule and confirming SSH is restored.
Break SSH access with a deny rule
NSG rules are processed by priority number, starting from the lowest number (highest priority). A deny rule with a lower priority number than your existing allow rule will block traffic before the allow rule ever gets evaluated.
- Add a deny-all rule at priority 100, which is higher priority than your AllowSSH rule at priority 1000, by running this command in Cloud Shell:
az network nsg rule create --resource-group myVMProject --nsg-name myNSG --name DenyAllInbound --protocol "*" --priority 100 --destination-port-range "*" --access deny
What does this command do?
This creates a new NSG rule called DenyAllInbound that blocks all inbound traffic on every port and every protocol.
The key detail is --priority 100. Azure evaluates NSG rules from the lowest priority number first. Since 100 is lower than 1000 (your AllowSSH rule), Azure hits the deny rule first and never reaches the allow rule.
- Try to SSH into your VM to confirm it is now blocked:
ssh -o ConnectTimeout=10 azureuser@[[PUBLIC_IP="your VM's public IP address"]]
The connection will time out after 10 seconds. This confirms your deny rule is working.
Connection didn't time out?
If SSH still connects, the deny rule may not have been created successfully. Run az network nsg rule list --resource-group myVMProject --nsg-name myNSG --output table and check that DenyAllInbound appears with priority 100.
help me figure out why my deny rule isn't blocking SSH
Diagnose the priority conflict
In a real support scenario, you would not already know which rule is causing the problem. The first diagnostic step is always to list the active rules and inspect their priorities.
- List all NSG rules to see the full picture by running:
az network nsg rule list --resource-group myVMProject --nsg-name myNSG --output table
You should see two rules in the output table.
How to read the diagnosis
- DenyAllInbound has priority 100. It denies all protocols on all ports.
- AllowSSH has priority 1000. It allows TCP on port 22.
- Azure processes rules from the lowest priority number first. Priority 100 fires before priority 1000.
- The deny rule matches all traffic and drops it before the allow rule ever gets a chance to match.
Why does a lower number mean higher priority?
Azure NSG rules use priority values between 100 and 4096. The lower the number, the earlier the rule is evaluated. Think of it like a queue: rule 100 is first in line, and rule 1000 is much further back.
Fix the issue and restore SSH access
The fix is straightforward: delete the rule that is blocking traffic. Once removed, your AllowSSH rule at priority 1000 becomes the effective rule for port 22.
- Delete the deny rule by running:
az network nsg rule delete --resource-group myVMProject --nsg-name myNSG --name DenyAllInbound
- Verify the rule is gone by listing your NSG rules again:
az network nsg rule list --resource-group myVMProject --nsg-name myNSG --output table
You should now see only the AllowSSH rule listed in the output.
- Test that SSH access is restored by connecting to your VM:
ssh -o ConnectTimeout=10 azureuser@[[PUBLIC_IP="your VM's public IP address"]]
You should be connected to your VM within a few seconds. Run hostname to confirm you are inside the VM.
- Type exit to return to Cloud Shell.
SSH still timing out after deleting the rule?
Run az network nsg rule list --resource-group myVMProject --nsg-name myNSG --output table again and confirm DenyAllInbound no longer appears. If it still shows, the delete command may have failed. Re-run the delete command and check for typos in the rule name.
Also confirm your VM is still running with az vm show --resource-group myVMProject --name myVM --show-details --output table and check that the PowerState shows VM running.
help me fix my SSH connection to my Azure VM
Secret mission
Set Up a CPU Alert with Azure Monitor
Your VM is running, but how would you know if it started struggling under heavy load? In this secret mission, you will create an Azure Monitor metric alert that fires when your VM's average CPU usage exceeds 80%. This is exactly how cloud support engineers monitor production VMs.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Cost warning
The Standard_B1s VM is included in the Azure free tier (750 hours/month for 12 months). If you are past your free tier period, the VM costs approximately $0.012/hour while running.
If you are not planning to use these resources immediately, choose Pause or Delete below to avoid unexpected charges.
Resources you used:
- Resource Group myVMProject in eastus (contains all resources below).
- Virtual Network myVNet with Subnet mySubnet.
- Network Security Group myNSG with the AllowSSH rule.
- Linux VM myVM (Standard_B1s) with Public IP, Network Interface, and OS Disk.
- Azure Monitor metric alert HighCPUAlert.
Keep everything running
No action needed. Choose this if you are still actively experimenting with your VM and networking setup.
- Your VM will continue running and consuming free-tier hours (or be billed at approximately $0.012/hour if past the free tier).
- The metric alert is free for up to 10 alert rules per subscription.
- Cloud Shell requires no cleanup. It is browser-based and automatically times out after 20 minutes of inactivity.
Pause - I'll come back to this later
Shut down the VM to stop compute charges while keeping all your resources intact. You will still be charged for disk storage.
- Deallocate your VM by running this command in Cloud Shell:
az vm deallocate --resource-group myVMProject --name myVM
- This stops the VM and releases compute resources. You will not be charged for compute while deallocated, but the OS disk storage charge continues.
- To start the VM again later, run az vm start --resource-group myVMProject --name myVM in Cloud Shell.
Delete - I don't want to use this again
Remove all project resources permanently. This deletes the resource group and everything inside it (VM, VNet, NSG, Public IP, Network Interface, OS Disk, and metric alert).
- Delete the entire resource group by running this command in Cloud Shell:
az group delete --name myVMProject --yes --no-wait
What does this command do?
- az group delete --name myVMProject deletes the resource group and all resources within it.
- --yes skips the confirmation prompt.
- --no-wait returns immediately without waiting for the operation to complete. The deletion continues in the background.
- Verify the deletion has started by running:
az group list --output table
- myVMProject should no longer appear in the list (or may show as deleting).
Nice Work!
Nice Work!
Nice work! You just deployed a Linux Virtual Machine on Azure with a custom network configuration you built entirely from the command line. You also diagnosed and fixed a real-world connectivity issue using the same approach that cloud support engineers use every day.
You've learned how to:
- Built a Virtual Network, Subnet, and Network Security Group from scratch using the Azure CLI in Cloud Shell.
- Deployed a Linux VM and connected to it via SSH directly from Cloud Shell.
- Diagnosed and fixed a network connectivity issue caused by an NSG rule priority conflict.
- Secret Mission: Set up an Azure Monitor metric alert to monitor VM CPU usage.
Ready to quiz yourself?