Introduction
Adaptability is the core of DevOps. After navigating subscription-level constraints in our previous VM setup, it became clear that understanding 'where' and 'how' you deploy is just as vital as the 'what.'
In this second part of our Azure CLI series, we apply those hard-won lessons to build a faster, more agile deployment workflow. From optimizing locations to selecting the right VM sizes on the fly, this guide provides a professional blueprint for mastering Azure resources through the command line.
Here, I skipped Install Azure CLI and headed straight to verification.
Step 1: Verify the installation.
To verify the installation, run the Azure CLI command: az --version command.
This gives details of the Azure version in use.
Run the Azure command az login. This opens a browser for interactive authentication and sets your active Azure subscription context.


Notice I selected my account and then Continue.

Note I did not have to sign in because the account was set in the previous exercise, using the az account set command.
Step 3: To confirm my active subscription, I entered 1, because it is the only active subscription I have. If you have more than one subscription, enter the number that corresponds to your subscription.
We can go ahead and provision the Resource Group now.
Create a Resource Group
In this section, we aim to create a resource group to act as the logical container for the entire lab environment.
Step 1: Set a variable for the resource group.
Store the resource group name and region in powershell variables. This is highly recommended to prevent typos throughout the rest of the lab and make the script easily reusable.
RG="azurecli-lab-rg"
This sets the shell variable RG so later commands can reference it with $RG.
LOCATION="eastus"
This sets the shell variable LOCATION so later commands can reference it with $LOCATION.
Step 2: Create the Resource Group
Create a named resource group in korea central this time around. All resources in this lab will be placed here for easy cleanup.
This is needed because Azure requires every resource to live inside a resource group. They make it easy to manage, monitor, and delete everything together at the end of the lab.
Operational Excellence — grouping related resources together is a best practice for manageability and cost tracking.
Run the command: az group create --name $RG --location $LOCATION.
This creates a resource group called "$RG" — a logical container for all the Azure resources in this lab.
Clearly, it was created because the properties are stated and Notice the ProvisioningState is "Succeeded".
Build a Virtual Network (VNet) & Subnet
This is aimed at creating a secure private network for your Azure resources to communicate on.
Step 1: Create the Virtual Network
Here, you will create a Virtual Network with a broad 10.0.0.0/16 IP address space.
This is necessary because VMs and other infrastructure need a secure, isolated private network to communicate with each other.
Creating an isolated network boundary is the foundational step of cloud security.
Run the command: az network vnet create --address-prefix 10.0.0.0/16 --resource-group $RG --name lab-vnet --location $LOCATION
It took just 4 seconds for this virtual network to provision. That's amazing!
Step 2: Create a Subnet
This would carve out a smaller 10.0.1.0/24 piece (subnet) of the VNet specifically for your VMs.
Why this is relevant
Segmenting networks allows you to apply different routing and firewall rules to different types of resources.
This aspect of security is known as network segmentation.
Run the CLI command: az network vnet subnet create --resource-group $RG --vnet-name lab-vnet --name lab-subnet --address-prefix 10.0.1.0/24
Step 3: Create a Network Security Group (NSG)
A Network Security Group acts as a virtual firewall.
This is important because without an NSG attached, Microsoft allows no inbound traffic but allows all outbound traffic. We need an NSG to poke specific holes in the firewall.
Controlling traffic flow with firewalls is a basic security requirement.
Run the command: az network nsg create --resource-group $RG --name lab-nsg
Step 4: Open port 22 (SSH) & 80 (HTTP)
Let's add inbound rules prioritizing SSH (port 22) and HTTP (port 80) access from the internet.
The reason for this action is that you'll need SSH to log in and configure the server, and HTTP so users can view the web page.
This explicitly defining inbound access using the principle of least privilege.
First ensure your terminal knows what $RG is by running this line first: $RG="azurecli-lab-rg"
Then create the SSH rule using this command:
az network nsg rule create
--resource-group $RG
--nsg-name lab-nsg
--name AllowSSH
--priority 1000
--destination-port-ranges 22
--access Allow
--protocol Tcp
--direction Inbound
Wait for the first command to finish.
Then create the HTTP Rule by running this separate block:
az network nsg rule create
--resource-group $RG
--nsg-name lab-nsg
--name AllowHTTP
--priority 1010
--destination-port-ranges 80
--access Allow
--protocol Tcp
--direction Inbound
Notice (`)serves as a line breaker because the command is long. Leave one space before the "backtick" and then enter.
Step 5:Attach NSG to Subnet
This enforces the firewall rules (NSG) at the subnet boundary.
It's needed because by applying the NSG to the subnet ensures that any VM created in that subnet automatically inherits those exact firewall rules, thereby protecting the entire subnet.
Security — subnet-level application of security controls.
Run this block of commands:
az network vnet subnet update
--resource-group $RG
--vnet-name lab-vnet
--name lab-subnet
--network-security-group lab-nsg
Remember to run the resource group variable first if you restart the terminal.
Provision a Linux Virtual Machine
Here, you will create an Ubuntu VM with a public IP inside your VNet.
Step 1: Allocate a Public IP
This allocates a static public IP address in Azure.
It's needed because without a public IP, the VM can only be accessed internally through the VNet or a VPN. You need this to reach your web server from your browser.
Reliability — using a Static IP ensures the address does not change upon reboot.
Run this command:
az network public-ip create
--resource-group $RG
--name lab-public-ip
--allocation-method Static
--sku Basic
Notice due to error, I had to switch to "standard". Pay attention to error messages.
Step 2: Create the VM
This creates a B1s Ubuntu VM with auto-generated SSH keys and connects it to the existing subnet and firewall.
It's necessary because this is the actual cloud compute instance that will run your web application code.
Performance Efficiency — selecting the appropriately sized VM for your workload (B1s for dev/test).
Run this command: az vm create
--resource-group azurecli-lab-rg
--name lab-vm
--image Ubuntu2204
--size Standard_B2s_v2
--location koreacentral
--admin-username azureuser
--generate-ssh-keys
--vnet-name lab-vnet
--subnet lab-subnet
--public-ip-address lab-public-ip
--nsg lab-nsg
Notice this time around, I did not have to change anything because am now aware of the limitations that come with the subscription and the Powerstate is running.
Step 3: Retrieve the public IP
This will filter the Azure API response to return just the IP address string.
It's important because you'll need this IP to SSH into the machine and to test the web application.
Operational Excellence — automated retrieval of resource attributes avoids manual portal lookups.
Run the command: az network public-ip show
--resource-group azurecli-lab-rg
--name lab-public-ip
--query ipAddress
--output tsv

Notice the error occurred because I mistakenly omitted the "-rg" suffix.
Step 4: Verify the VM is running
This queries the VM status and displays it in a clean table format.
It's needed because you always verify provisioning success before attempting connections.
Operational Excellence — verification and monitoring.
Run the command: az vm show
--resource-group azurecli-lab-rg
--name lab-vm
--show-details
--query '{Name:name, State:powerState, IP:publicIps}'
--output table
Step 5:SSH into your VM & install Nginx
It logs into the VM over the internet via SSH, installs the Nginx package using APT, and starts the service.
Why It's Needed
A fresh VM is blank. Nginx serves as the web server to test our HTTP port 80 firewall rule.
Pillar Connection
Operational Excellence — bootstrap scripts or userdata are typically used to automate this step.
You can go ahead to verify the resources' provision in your Azure Portal. This will help you appreciate resource creation via the Azure CLI. It's very fast and efficient.
Conclusion: Your Turn to Command the Cloud
Stepping out of the comfort zone of the Azure Portal and into the CLI is more than just a technical shift, it’s a mindset shift. By following this guide, you’ve moved from being a "user" of the cloud to someone who truly "architects" it.
Don't be discouraged if you hit errors along the way. Every SkuNotAvailable or InvalidParameter is just a signal that you're learning how the machine actually thinks. The more you practice, the more these commands will feel like a second language.
I’d love to hear from you! Let's go to the comment section👇👇


















Top comments (3)
The encouragement at the end.. much needed🥲❤️
This is Amazing 🔥
Awesome, weldone