Building My First Azure Virtual Machine From the Ground Up π
In this post, I'll walk you through exactly how I went from an empty Azure subscription to a live Ubuntu VM running Apache, complete with every screen I clicked through. No skipped steps, no "and then magic happens."
By the end, you'll be able to do this yourself in under 20 minutes. Let's go! π
π¬ Heads up: This is a follow-along tutorial. Grab a coffee, open a second tab with your Azure portal, and build alongside me.
β What You'll Build
- [x] A Resource Group to hold everything together
- [x] A Virtual Network (VNet) with a custom address space
- [x] A Subnet inside that VNet
- [x] A Virtual Machine (Ubuntu 24.04 LTS) deployed into that subnet
- [x] SSH access into the VM from VS Code's terminal
- [x] A live Apache2 web server you can visit in your browser
- [x] A clean teardown so you don't get billed for forgetting it πΈ
π§° Prerequisites
- An Azure account (free tier works fine)
- A terminal β I used VS Code's integrated terminal (bash/Git Bash)
- 15β20 minutes and a bit of curiosity
πΊοΈ The Architecture (in plain English)
Resource Group (the folder that holds everything)
βββ Virtual Network (10.0.0.0/16)
βββ Subnet (10.0.0.0/24)
βββ Virtual Machine (Ubuntu 24.04, public IP, SSH + HTTP open)
Resource Group first, then network, then subnet, then the actual VM goes into that subnet. Let's build it top-down.
Step 1: Create a Resource Group π
A Resource Group is basically a folder in Azure β it keeps every resource for this project (network, VM, disks, IP) organized together so you can manage or delete them as one unit.
Firstly I login into the Azure Homepage via https://portal.azure.com/
From the Azure homepage, I searched for Resource Groups and hit Create.
I named mine VM-RG-Test and picked France Central as my region β pick whatever region is closest to you.
While on the Review + Create page, I clicked Create after reviewing the details of the Resource Group.
A few seconds later β done! β
π‘ Tip: Whatever region you pick here is the one you should use for every resource in this tutorial. Mixing regions adds latency and (sometimes) extra cost.
Step 2: Create a Virtual Network (VNet) π
Next, your VM needs a network to live in. I searched for Virtual networks
and clicked Create.
I assigned it to my VM-RG-Test resource group and named it VM-Virtual-Network, same region as before.
On the Address space tab, Azure gives you a default 10.0.0.0/16 range with a default subnet already attached. I deleted that default subnet β I want to create my own with a name that actually makes sense β then hit Review + create.
Validation passed, so I clicked Create.
Once the deployment finished, I clicked Go to resource.
Step 3: Add a Subnet π§©
A VNet without a subnet is just an empty container β the subnet is where your VM's network card actually attaches.
Inside the VNet, I went to Settings β Subnets.
And clicked Create on the subnet page.
I named it VM-Sub-Net, left the default 10.0.0.0/24 range (251 usable IPs β plenty for one VM), and clicked Add.
And there it is β one ready-to-use subnet.
Step 4: Create the Virtual Machine π₯οΈ
This is the main event. I searched for Virtual machines
And clicked Create, then selected the first option, which is Virtual Machine.
4.1 β Basics: name, region, resource group
I dropped this VM into my existing VM-RG-Test resource group and named it VM-Test.
4.2 β Image, size, and authentication
For the image, I went with Ubuntu Server 24.04 LTS - x64 Gen2, kept the size small (Standard_B1ls) to keep costs minimal, and chose SSH public key as the authentication method instead of a password β much safer.
4.3 β Username, SSH key, and inbound ports
I set my username to VM-David, let Azure generate a new SSH key pair for me, named the key VM-Test_key, and allowed inbound traffic on HTTP (80) and SSH (22) β HTTP so I can later view my website, SSH so I can connect and manage the server.
β οΈ Allowing SSH from "any IP" is fine for a quick test like this, but for production you'd lock it down to your own IP address using the Advanced networking controls.
4.4 β Disks
I kept the default Standard SSD for the OS disk β good enough for a test server, no need for Premium SSD here.
4.5 β Networking: plugging it into our VNet/Subnet
This is where everything we built earlier comes together β I selected my VM-Virtual-Network and VM-Sub-Net, let Azure create a new public IP, and chose HTTP (80), SSH (22) as the allowed inbound ports.
I also checked "Delete public IP and NIC when VM is deleted" β a small checkbox that saves you from leaving orphaned (and billable!) resources behind later.
4.6 β Review + Create
Validation passed (estimated cost: under $8/month for this tiny config π), so I hit Create.
Azure immediately prompted me to download the private key β this is your only chance to grab it, since Azure never stores the private half of the key pair.
And there's my .pem key, safely sitting in my Downloads folder.
π Don't lose this file. Without it, you can't SSH into your VM. Treat it like a password.
A minute or two later, the deployment finished.
Step 5: Confirm the VM Is Alive β
On the VM's overview page, I could see its public IP, private IP, region, and size β and the status read Running.
Step 6: SSH In and Install Apache π§
Time to actually log into the server. I opened VS Code's terminal then swicthed to Bash from Powershell(you can use Git-bash also), navigated to my Downloads folder (where the key lives), locked down the key's permissions, and connected.
# 1. Go to where the key was downloaded
cd Downloads
# 2. Restrict permissions on the key (required by SSH)
chmod 400 VM-Test_key.pem
# (chmod 600 also works on most systems)
# 3. Connect to the VM using the key, username, and public IP
ssh -i VM-Test_key.pem VM-David@98.66.137.84
# 4. Update package lists
sudo apt update
# 5. Install Apache2 web server
sudo apt install apache2
The first time you connect, SSH will ask if you trust the host's fingerprint β type yes to continue. Running whoami afterward confirmed I was logged in successfully.
After updating, I installed Apache2:
Step 7: See It Live in the Browser π
With Apache installed and running, I opened a browser and typed in the VM's public IP address. And there it was β the Apache2 default "It works!" page, served straight from my own Azure VM.
This was honestly the most satisfying part β seeing a page load from infrastructure I built myself, end to end. π
Step 8: Clean Up β Delete the Resource Group π§Ή
Azure bills you for running resources, so once I was done testing, I deleted the whole resource group. Because everything (VM, disk, NIC, public IP, SSH key, VNet) was inside VM-RG-Test, one deletion removes it all.
π Spot the extra one? There's also a NetworkWatcherRG sitting in that list. Azure creates this automatically the first time you use any network diagnostics feature in a region β I didn't make it on purpose. It doesn't cost anything by itself, but since I was cleaning house, I deleted it too.
Azure shows you exactly what's about to be deleted β 7 resources in my case β and makes you type the resource group's name to confirm. No accidental deletions here.
A couple minutes later, it was gone β clean slate, zero ongoing cost.
π― Recap
| Step | What Happened |
|---|---|
| 1 | Created a Resource Group (VM-RG-Test) |
| 2 | Created a Virtual Network (VM-Virtual-Network, 10.0.0.0/16) |
| 3 | Added a Subnet (VM-Sub-Net, 10.0.0.0/24) |
| 4 | Deployed an Ubuntu VM into that subnet with an SSH key |
| 5 | Connected via SSH from VS Code's terminal |
| 6 | Installed and ran Apache2 |
| 7 | Visited the live page in a browser |
| 8 | Deleted everything to avoid surprise charges |
π£οΈ Over to you
Drop a comment below π β and if this helped you, a like/follow goes a long way! π



































Top comments (0)