You spun up your first Azure Virtual Machine ten minutes ago. The portal shows a reassuring green Running. You copy the public IP, open Remote Desktop (or a terminal), hit connect — and nothing. RDP spins for thirty seconds and dies with “can’t connect to the remote PC.” SSH sits silent, then prints Connection timed out or, worse, Connection refused. The VM is running, so why can’t you get in? This is, by a wide margin, the most common wall a beginner hits on Azure, and it is almost never the VM itself being broken. The VM is fine. Something on the path between your laptop and the VM’s login service is blocking you — and on Azure that path has five or six gates, any one of which closes the door.
The reason this feels so maddening is that “Running” only tells you the virtual hardware is powered on. It says nothing about whether a network security group (NSG) is allowing port 3389 (RDP) or 22 (SSH), whether the VM even has a public IP, whether the operating system’s own firewall is open, whether the login service inside the OS is listening, or whether the password/key you are typing is the one the VM expects. A connection has to pass all of those gates, in order, and the error you see (timeout vs refused vs an authentication prompt) is a clue to which gate slammed shut. Learn to read that clue and you stop randomly clicking and start diagnosing.
This is that checklist. We will treat “can’t connect” not as one bug but as a short, ordered list of layers — your network → Azure NSG → public IP/DNS → the OS firewall → the listener service → your credentials — and for each layer give you the exact thing to check, the precise az command or portal path that confirms it, and the fix. By the end you will work top-down: timeout? Suspect the network gates (NSG, IP, firewall). Refused or a login error? The VM is reachable and the problem is the service or your credentials. Knowing which half you are in takes the diagnosis from an hour of flailing to about five minutes.
What problem this solves
A blocked RDP/SSH connection is the single biggest source of “Azure is broken” support tickets from newcomers — and the overwhelming majority of them are self-inflicted configuration, not an Azure fault. Someone creates a VM, accepts a default that closes management ports (a good security default), and then cannot get in. Or they delete a public IP to save money and forget it was their only way in. Or they enable the Windows Firewall / Linux ufw inside the OS and lock out the very port they need. The VM keeps running and billing while they cannot touch it.
What breaks without this knowledge: you waste hours re-creating the VM (which often “fixes” it by accident, because the new VM gets the open default — teaching exactly the wrong lesson), you open a support ticket and wait, or you start opening ports far too wide (0.0.0.0/0 to the whole internet) just to make it work, which is how VMs get compromised within hours. The right move is almost never “rebuild it” — it is “walk the path, find the one closed gate, open just that gate for just your IP.”
Who hits this: every first-time VM user, and plenty of experienced ones after a change. It bites hardest right after creation (a closed-by-default NSG), after enabling an OS firewall, after deallocating and restarting (a dynamic public IP can change), after a network change (a route or NSG edit that removed your access), and after a forgotten password. The good news: every one of these is diagnosable from the portal or a single az command, and the fix is usually one line.
To frame the whole field before we dig in, here is every layer a connection must pass and the symptom you see when that specific layer is the one blocking you:
| Layer (in order) | What it controls | Typical symptom when THIS layer blocks | First place to check |
|---|---|---|---|
| Your local network | Outbound 3389/22 from your office/ISP | Timeout (often only from one network) | Try a phone hotspot; Test-NetConnection |
| NSG (subnet + NIC) | Inbound allow/deny on 3389/22 | Connection timed out | NSG inbound rules / effective rules |
| Public IP & DNS | Whether the VM is reachable at all | Timeout; or you’re using the wrong/old IP | VM Overview → public IP |
| Azure Firewall / route (advanced) | Forced tunneling, UDR, firewall in path | Timeout despite NSG allow | Effective routes; Network Watcher |
| OS firewall (Windows/Linux) | In-guest allow on the port | Refused or timeout after NSG is open | Serial console; Run Command |
| Listener service (RDP/sshd) | The login service running + on the right port | Connection refused | Run Command: check service/port |
| Credentials | Username + password/SSH key | Auth error (you connected!) | Reset via VMAccess extension |
Learning objectives
By the end of this article you can:
- Read the three connection outcomes — timed out, connection refused, and an authentication prompt/error — and immediately know which half of the path (network vs OS/credentials) to investigate.
- Check whether an NSG is allowing your port from your IP, using both the portal’s effective-rules view and
az network nic list-effective-nsg, and add a correct, narrow allow rule. - Confirm a VM has a reachable public IP, tell a dynamic IP that changed from a static one, and connect through Azure Bastion when there is no public IP at all.
- Diagnose an OS-level firewall (Windows Defender Firewall,
ufw/firewalld) blocking the port even when the NSG is open, using the serial console and Run Command (which need no working RDP/SSH). - Fix credential problems — reset a Windows password or repair an SSH public key — with the VMAccess extension and
az vm user update, without rebuilding the VM. - Use Azure’s built-in diagnostics — Connection troubleshoot (Network Watcher), the serial console, Run Command, and boot diagnostics — to confirm root cause when you cannot get a shell.
- Apply the secure defaults that prevent this whole class of problem: source-restricted NSG rules, just-in-time (JIT) access, and Bastion instead of public management ports.
Prerequisites & where this fits
You should already have created at least one VM and know the basics: a VM has a network interface (NIC), the NIC lives in a subnet inside a virtual network (VNet), and the VM may or may not have a public IP attached. You should be able to run az in Azure Cloud Shell (the browser terminal in the portal, no install needed) and read its output. Knowing that RDP uses TCP port 3389 and SSH uses TCP port 22 is the one fact this entire article rotates around.
This sits at the very start of the Compute & Troubleshooting track. If you have not created a VM yet, do the Deploy Your First Azure VM: Portal and CLI, Step by Step walkthrough first — it sets up exactly the VM we will be unblocking here. The networking gate that blocks you most often is the NSG; the mental model for VNets, subnets and NSGs is covered in Azure Virtual Network: Subnets and NSGs. When the problem turns out to be deeper in the network (a route or a firewall in the path, not just an NSG), graduate to Diagnosing Azure VNet Connectivity: NSGs, UDRs, Effective Routes & Network Watcher. And the secure way to avoid exposing 3389/22 to the internet at all is Azure Bastion, the managed RDP/SSH broker we reach in the security section.
Core concepts
Four ideas make every diagnosis below obvious.
“Running” is not “reachable.” The VM’s power state (Running, Stopped, Stopped (deallocated)) only describes the virtual hardware. A running VM with no open port, no public IP, or a firewall blocking the listener is completely unreachable — and perfectly healthy. The first mental shift is to stop trusting the green dot and start walking the path. Every gate on that path must say “yes” before you get a login prompt.
The error you get tells you where on the path it failed. This is the most useful diagnostic fact in the whole article. A timeout means your connection packets left your machine and never got an answer — they were dropped silently, which is what an NSG deny, a missing public IP, or a route black-hole does. A connection refused means something answered “no” on that port — the packet reached the VM (so the NSG and IP are fine) but nothing was listening on that port, or the OS firewall actively rejected it. An authentication prompt or error means you connected to the service successfully — the entire network path works and the only thing left is your username/password/key. So: timeout → network layers; refused → OS firewall or listener; auth error → credentials. Memorise that and you have already halved every future incident.
Two NSGs can be in the path, and the effective rules are what count. An NSG is a list of allow/deny rules for inbound and outbound traffic. You can attach one to the subnet and another to the NIC, and both apply — a packet must be allowed by both to get through. Reading one NSG in isolation lies to you. Azure computes the combined result as effective security rules, and that combined view (portal or az network nic list-effective-nsg) is the only one you should trust when diagnosing. Inbound NSG rules are also evaluated by priority (lower number wins), so a broad deny at priority 200 will beat your allow at priority 300.
You can always get in through the back door — without RDP/SSH. This is the beginner’s lifeline. Even when the front door (RDP/SSH over the network) is completely shut, Azure gives you two paths that bypass the network entirely: the serial console (a direct console connection to the OS, like plugging a keyboard into the machine, which works even with every port closed) and Run Command (which runs a script inside the VM through the Azure control plane, no network login needed). With those, you can inspect and fix the OS firewall, restart the listener, or reset the password from outside — so a locked-out VM is rarely a rebuild.
The vocabulary in one table
Pin down every moving part before the deep sections. The glossary at the end repeats these for quick lookup:
| Term | One-line definition | Why it matters to “can’t connect” |
|---|---|---|
| NSG (network security group) | Allow/deny rules on inbound & outbound traffic | Closed 3389/22 → timeout |
| Effective security rules | The combined result of subnet + NIC NSGs | The only NSG view you can trust |
| Public IP | The internet-facing address on the VM’s NIC | No public IP → unreachable from your laptop |
| Dynamic vs static IP | Whether the public IP can change on stop/start | A changed dynamic IP looks like “down” |
| RDP / port 3389 | Remote Desktop to Windows | The Windows front door |
| SSH / port 22 | Secure shell to Linux | The Linux front door |
| OS firewall | In-guest firewall (Defender / ufw / firewalld) |
Open NSG but closed OS firewall → refused |
| Listener / sshd / TermService | The service that answers on 22 / 3389 | Not running → connection refused |
| Serial console | Direct console to the OS, bypasses network | Fix the OS even with all ports shut |
| Run Command | Runs a script in the VM via Azure | Inspect/repair without a login |
| Azure Bastion | Managed RDP/SSH from the portal, no public IP | The secure way in; avoids open 3389/22 |
| VMAccess extension | Resets passwords / SSH keys from Azure | Recover credentials without rebuild |
How to read the symptom: the three outcomes
Before any commands, classify what you actually see. Almost every “can’t connect” falls into one of three buckets, and the bucket tells you which sections below to read. Spend ten seconds here and save an hour later.
| What you see | What it means | The path is… | Read these sections |
|---|---|---|---|
Spins, then timed out (RDP: “can’t connect”; SSH: Connection timed out) |
Packets left you and got no reply — silently dropped | Blocked at a network gate (NSG, IP, route, OS firewall set to drop) | NSG · Public IP · OS firewall |
Fast connection refused (SSH: Connection refused; RDP: immediate failure) |
Something answered “no” on that port | Network reaches the VM; service not listening or OS firewall rejecting | OS firewall · Listener service |
You get a login prompt but it fails (Permission denied, wrong password, CredSSP) |
You connected to the service | Path is fully open; only credentials are wrong | Credentials |
| DNS error (host not found) | The name doesn’t resolve | You’re using a bad/old DNS name or IP | Public IP & DNS |
Two quick reading notes that save the most time:
- Timeout vs refused is the master fork. Timeout = a gate is silently dropping you (the polite-but-firm bouncer who ignores you). Refused = a gate is actively saying no (the bouncer who looks at you and says “not here”). Drops come from NSG denies, missing IPs, black-holed routes, and OS firewalls in drop mode. Active refusals come from a port with no listener, or an OS firewall in reject mode. They point at different layers.
- An auth error is good news. If you reached a password prompt or got
Permission denied (publickey), congratulations — the network is perfect and you’ve skipped to the last section. Don’t touch the NSG.
The path, gate by gate
Now walk the gates in order. Top-down: fix the network gates first (they cause timeouts), then the OS/service gates (refused), then credentials (auth errors). For each gate: what it is, how to confirm it’s the problem, and the fix with the exact command.
Gate 1 — Your own network (the free first check)
Before blaming Azure, rule out your side. Many corporate and some home/ISP networks block outbound 3389 and 22. If RDP/SSH times out from your office but you can’t test elsewhere, you may be staring at Azure for a problem that lives on your firewall.
Confirm. The fastest test is to try from a completely different network — tether to your phone’s hotspot and retry. If it works on the hotspot but not the office, your network is the blocker. From Windows you can probe the port reachability directly:
# Does TCP 3389 to the VM's public IP even open from here?
Test-NetConnection -ComputerName 20.40.50.60 -Port 3389
# TcpTestSucceeded : True -> the path is open to here; problem is auth/service
# TcpTestSucceeded : False -> blocked somewhere (your net, NSG, IP, or OS firewall)
On macOS/Linux, nc -vz 20.40.50.60 22 does the same for SSH. Fix. If it’s your corporate firewall, ask IT to allow outbound to the VM, or use Azure Bastion (which connects over HTTPS/443, almost always open) instead of raw 3389/22. This single check is free and rules out an entire class of false alarms.
Gate 2 — The NSG (the number-one cause of timeouts)
The network security group is the gate that blocks first-time users most often, because secure-by-default templates do not open 3389/22 to the world. If your inbound NSG rules don’t allow your port from your source IP, your connection packets are dropped and you get a timeout — never a refusal, because nothing ever answers.
Confirm. Two ways. In the portal: VM → Networking → Inbound port rules shows the rules, but the truthful view (combining subnet + NIC NSGs) is VM → Networking → check the effective rules or, more directly, the NIC’s Effective security rules. Via CLI, pull the effective NSG so you see the combined result, not one NSG in isolation:
# The combined inbound rules actually applied to this VM's NIC
az network nic list-effective-nsg \
--name vm-web01VMNic --resource-group rg-lab \
--query "value[].effectiveSecurityRules[?direction=='Inbound' && (destinationPortRange=='3389' || destinationPortRange=='22' || destinationPortRange=='*')].{name:name, access:access, prio:priority, srcPrefix:sourceAddressPrefix, port:destinationPortRange}" \
-o table
Look for an Allow on your port whose source matches your IP and whose priority is lower (higher precedence) than any matching Deny. If you only see the default DenyAllInBound (priority 65500), there is no allow rule and that’s your problem.
Fix. Add a narrow inbound allow rule — for your IP only, never 0.0.0.0/0. First find your public IP (search “what is my IP” or curl ifconfig.me), then:
# Allow RDP (3389) from YOUR IP only. Use 22 for SSH on Linux VMs.
az network nsg rule create \
--resource-group rg-lab --nsg-name vm-web01-nsg \
--name Allow-RDP-MyIP --priority 300 \
--direction Inbound --access Allow --protocol Tcp \
--source-address-prefixes 203.0.113.25/32 \
--destination-port-ranges 3389
// The same rule in Bicep — note the /32 to lock it to a single source IP
resource rdpRule 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
parent: nsg
name: 'Allow-RDP-MyIP'
properties: {
priority: 300
direction: 'Inbound'
access: 'Allow'
protocol: 'Tcp'
sourceAddressPrefix: '203.0.113.25/32' // your IP, NOT '*' or '0.0.0.0/0'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '3389' // '22' for SSH
}
}
The NSG rule fields you must get right, and the trap in each:
| Field | What it means | Common mistake | Correct value |
|---|---|---|---|
direction |
Inbound vs outbound | Editing an outbound rule | Inbound for RDP/SSH |
access |
Allow or Deny | Leaving a higher-priority Deny in front | Allow |
priority |
100–4096; lower wins | Allow at 400 behind a Deny at 200 | Put the Allow below the Deny number |
protocol |
Tcp / Udp / * | Choosing Udp | Tcp (both 3389 and 22 are TCP) |
sourceAddressPrefix |
Who may connect | * / 0.0.0.0/0 (whole internet) |
Your IP /32 |
destinationPortRange |
The port opened | Typo (3399, 222) | 3389 (RDP) or 22 (SSH) |
A note that catches people: priority. NSG inbound rules are evaluated lowest-number-first, and the first match wins. If a template added a Deny at priority 200 and you add an Allow at 300, the Deny still wins. Either lower your Allow’s number or remove the broad Deny.
Gate 3 — The public IP and DNS
If the VM has no public IP, you simply cannot reach it from your laptop over the internet — there is no address to connect to. And if it has a dynamic public IP, that address can change when the VM is stopped (deallocated) and started again, so the IP you saved yesterday may now belong to someone else’s VM, giving you a timeout against a stranger.
Confirm. Check whether a public IP exists and what it is right now:
# Show the VM's current public IP (empty result = no public IP attached)
az vm list-ip-addresses --name vm-web01 --resource-group rg-lab \
--query "[].virtualMachine.network.publicIpAddresses[].{ip:ipAddress, alloc:?, fqdn:dnsSettings.fqdn}" -o table
In the portal, VM → Overview shows the public IP (or a blank where it would be). The allocation method (Static vs Dynamic) is on the public IP resource → Configuration. Fix. If there’s no public IP and you intended one, attach a static public IP; if it’s dynamic and keeps changing, convert it to Static so it stays put:
# Make the public IP static so it never changes on stop/start
az network public-ip update --name vm-web01-ip --resource-group rg-lab \
--allocation-method Static
The cleaner answer for production is to not expose a public IP at all and connect through Azure Bastion (next gate, and the security section). The public-IP states and what each means for connecting:
| Situation | What you see | Why you can’t connect | Fix |
|---|---|---|---|
| No public IP | Blank IP on Overview | No internet-facing address exists | Attach a public IP, or use Bastion |
| Dynamic IP changed | Old IP times out | The address moved on deallocate/start | Convert to Static, use the new IP |
| Using the DNS name, stale | Host-not-found | The FQDN points at an old/released IP | Re-check the current IP/FQDN |
| Private IP only by design | 10.x / 172.16-31.x / 192.168.x | It’s not internet-reachable on purpose | Connect via Bastion / VPN / jumpbox |
Gate 4 — The OS firewall (open NSG, still no entry)
Here is the gate that fools people who did open the NSG correctly. Inside the guest OS there is a second firewall — Windows Defender Firewall on Windows, ufw or firewalld on Linux — and it has its own rules. If the NSG allows 3389 but Windows Firewall blocks it (or you enabled ufw on Linux without allowing 22), the packet reaches the VM and is then dropped or rejected inside the OS. Depending on the firewall mode this shows as a timeout (drop) or a connection refused (reject).
Confirm. You usually can’t RDP/SSH in to check the firewall — that’s the whole problem — so use Run Command, which executes a script inside the VM through Azure with no network login:
# Windows: is the RDP firewall rule enabled and the port listening?
az vm run-command invoke --command-id RunPowerShellScript \
--name vm-web01 --resource-group rg-lab \
--scripts "Get-NetFirewallRule -DisplayGroup 'Remote Desktop' | Select DisplayName,Enabled; (Get-NetTCPConnection -LocalPort 3389 -State Listen -EA SilentlyContinue) | Select LocalAddress,LocalPort"
# Linux: is ufw blocking 22, and is sshd listening?
az vm run-command invoke --command-id RunShellScript \
--name vm-lin01 --resource-group rg-lab \
--scripts "ufw status verbose 2>/dev/null; ss -tlnp | grep ':22 ' || echo 'sshd NOT listening on 22'"
Fix. Re-enable the firewall rule (don’t disable the firewall — open the one port). Via Run Command:
# Windows: re-enable the built-in Remote Desktop firewall rules
az vm run-command invoke --command-id RunPowerShellScript \
--name vm-web01 --resource-group rg-lab \
--scripts "Enable-NetFirewallRule -DisplayGroup 'Remote Desktop'; Set-ItemProperty 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0"
# Linux: allow SSH through ufw (keeps the firewall on, opens only 22)
az vm run-command invoke --command-id RunShellScript \
--name vm-lin01 --resource-group rg-lab \
--scripts "ufw allow 22/tcp && ufw reload && ufw status"
The OS-firewall situations and how the symptom differs:
| OS | Tool | Symptom when it blocks | Confirm with | Fix |
|---|---|---|---|---|
| Windows | Defender Firewall | Timeout or refused on 3389 | Get-NetFirewallRule -DisplayGroup 'Remote Desktop' |
Enable-NetFirewallRule -DisplayGroup 'Remote Desktop' |
| Windows | fDenyTSConnections reg key |
Refused on 3389 | Read the registry key (above) | Set the key to 0 |
| Linux | ufw |
Timeout (default deny) on 22 | ufw status verbose |
ufw allow 22/tcp |
| Linux | firewalld |
Timeout/refused on 22 | firewall-cmd --list-all |
firewall-cmd --add-service=ssh --permanent && firewall-cmd --reload |
Gate 5 — The listener service (the cause of “connection refused”)
If you get a fast connection refused rather than a timeout, the packet is reaching the VM but nothing is listening on that port. The login service itself is down: on Windows that’s the Remote Desktop Services (TermService); on Linux it’s the SSH daemon (sshd). A crashed service, a service set to “Disabled,” or sshd configured to listen on a non-default port all produce refusals.
Confirm. Check the service and the listening port via Run Command:
# Windows: is the RDP service running?
az vm run-command invoke --command-id RunPowerShellScript \
--name vm-web01 --resource-group rg-lab \
--scripts "Get-Service TermService | Select Name,Status,StartType"
# Linux: is sshd active, and on which port?
az vm run-command invoke --command-id RunShellScript \
--name vm-lin01 --resource-group rg-lab \
--scripts "systemctl is-active sshd || systemctl is-active ssh; grep -E '^Port' /etc/ssh/sshd_config || echo 'Port 22 (default)'"
Fix. Start (and re-enable) the service:
# Windows: start RDP and set it to start automatically
az vm run-command invoke --command-id RunPowerShellScript \
--name vm-web01 --resource-group rg-lab \
--scripts "Set-Service TermService -StartupType Automatic; Start-Service TermService"
# Linux: restart sshd and ensure it starts on boot
az vm run-command invoke --command-id RunShellScript \
--name vm-lin01 --resource-group rg-lab \
--scripts "systemctl enable --now ssh 2>/dev/null || systemctl enable --now sshd; systemctl status ssh --no-pager 2>/dev/null | head -5"
If sshd was deliberately moved to a non-standard port, either connect to that port (ssh -p 2222 ...) and open it in the NSG, or move it back to 22. When even Run Command can’t fix it (e.g. the OS won’t boot far enough), the serial console is your last resort — see the diagnostics section.
Gate 6 — Credentials (you connected, but it won’t let you in)
If you reached a password prompt or got Permission denied (publickey) / a CredSSP error, the network is perfect — this is purely authentication. The most common causes: you forgot the local admin password (Windows), you’re using the wrong username, the SSH public key on the VM doesn’t match your private key, or your client is sending the wrong key.
Confirm. First, double-check the username you set at creation — it is not Administrator or root by default; it’s whatever you typed (e.g. azureuser). Then, for SSH, run the client in verbose mode to see which key it offered and why it was rejected:
# -v shows the auth handshake: which key was offered, and 'Permission denied (publickey)'
ssh -v azureuser@20.40.50.60
Fix. You do not need to rebuild the VM. Azure’s VMAccess extension resets the password (Windows) or repairs the SSH public key (Linux) from the control plane:
# Windows: reset the local admin password (creates the user if missing)
az vm user update --name vm-web01 --resource-group rg-lab \
--username azureuser --password 'N3wStr0ng!Pass2026'
# Linux: push a fresh SSH public key for the user (repairs key mismatch)
az vm user update --name vm-lin01 --resource-group rg-lab \
--username azureuser --ssh-key-value "$(cat ~/.ssh/id_rsa.pub)"
The credential failure modes and how to tell them apart:
| Symptom | Likely cause | Confirm | Fix |
|---|---|---|---|
| Wrong password (Windows) | Forgotten/incorrect admin password | You see the password prompt | az vm user update to reset it |
Permission denied (publickey) |
VM’s public key ≠ your private key | ssh -v shows key offered then denied |
az vm user update --ssh-key-value |
Too many authentication failures |
Client offering many wrong keys | ssh -v lists several keys tried |
ssh -i ~/.ssh/right_key -o IdentitiesOnly=yes ... |
| CredSSP / “authentication error” (RDP) | Client/host NLA patch mismatch | RDP error mentions CredSSP/Oracle | Patch both ends; or temporarily relax NLA |
| Wrong username | Using root/Administrator |
You guessed the name | Use the admin name set at creation |
Architecture at a glance
Picture the connection as a relay race where the baton (your TCP packet on port 3389 or 22) must be passed cleanly through six runners, in order, before you see a login screen. It leaves your laptop and crosses your local/ISP network (runner one — a corporate firewall can drop it here). It arrives at Azure and hits the VM’s public IP (runner two — if there’s no public IP, the baton has nowhere to go). It then meets the NSG, the combined subnet-plus-NIC rule set (runner three — the gate that most often drops first-timers, producing a timeout). Past the NSG, if any route or Azure Firewall sits in the path it must permit and forward the traffic (runner four — usually transparent, but a forced-tunnel route can black-hole it). The baton reaches the VM’s NIC and enters the operating system, where the in-guest firewall — Windows Defender Firewall or Linux ufw/firewalld — gets one more say (runner five — an NSG can be wide open and this still drops you). Finally it reaches the listener service, TermService for RDP or sshd for SSH (runner six — if that service isn’t running you get an instant connection refused). Only after all six hand off cleanly do your credentials get checked.
The whole diagnostic method falls out of this picture. A timeout means a runner dropped the baton silently — and that’s always a network-ish gate: the ISP, a missing IP, the NSG, a route, or an OS firewall in drop mode. A connection refused means the baton reached the finish but the last runner said “no one’s here” — the service isn’t listening, or the OS firewall actively rejected it. An auth error means the baton finished the race and only the final credential check failed. So the first question is never “is the VM broken?” — it’s “which runner dropped it?” — and the symptom (timeout vs refused vs auth) tells you whether to look at the first three gates, the OS gates, or just your password. Crucially, two of Azure’s tools — the serial console and Run Command — let you teleport past every runner straight into the OS, which is how you fix the inner gates when the front door is shut.
Real-world scenario
Nutio Labs is a four-person analytics startup in Bengaluru. A junior engineer, on day three, spins up a Windows Server 2022 VM (a B2s) in Central India to host a small internal reporting tool, using the portal’s recommended secure defaults — which, correctly, do not open RDP to the internet. He sets the admin user to nutioadmin, notes the public IP, and tries to RDP in from the office. It spins for thirty seconds and dies: “Remote Desktop can’t connect to the remote computer.” The VM shows Running. He restarts it. Same result. He deletes it and rebuilds it twice, burning an afternoon and a few hundred rupees of his trial credit, and is about to file a “Azure RDP is broken” ticket.
The lead architect walks over and asks one question: “Timeout, or refused?” It’s a timeout — so the problem is a network gate, not the VM. They open Cloud Shell and pull the effective NSG rules with az network nic list-effective-nsg. The output is damning in its simplicity: the only inbound rule matching 3389 is the default DenyAllInBound at priority 65500. There is no allow rule at all — the secure template never created one, by design. The VM was never reachable; restarting and rebuilding never could have helped, because every rebuild reproduced the same closed default.
The fix takes one command. They grab the office’s public IP (curl ifconfig.me → 203.0.113.25) and add a single narrow rule: az network nsg rule create ... --name Allow-RDP-Office --priority 300 --source-address-prefixes 203.0.113.25/32 --destination-port-ranges 3389. Thirty seconds later, RDP connects to a login prompt. The credentials (nutioadmin and the password set at creation) work first try — confirming the network really had been the entire problem.
But the architect doesn’t stop there, because an internal tool with RDP open to even one office IP is a habit she wants to break early. Over the next hour they do it right: they remove the public IP entirely, deploy Azure Bastion into the VNet, and from then on the team connects via the portal over HTTPS — no public RDP port anywhere, nothing for an internet scanner to find. For the rare case Bastion is overkill, she shows him just-in-time (JIT) VM access, which keeps 3389 closed and opens it for your IP for a fixed window only when you request it. The lesson she writes on the team wiki: “‘Running’ means powered on, not reachable. A timeout is a network gate — check the effective NSG before you ever rebuild. And don’t put 3389 on the internet; that’s what Bastion is for.” The afternoon’s painful rebuild loop became a five-minute diagnosis and a permanently safer pattern.
The incident as a timeline, because the order of moves is the lesson:
| Time | Symptom | Action taken | Effect | What it should have been |
|---|---|---|---|---|
| Day 3, 14:00 | RDP timeout, VM “Running” | Restart the VM | No change | Ask: timeout or refused? |
| 14:15 | Still timeout | Delete + rebuild VM (×2) | No change, credit burned | Don’t rebuild a network problem |
| 15:30 | About to file ticket | Architect: “timeout = network gate” | Reframed correctly | — |
| 15:35 | Root cause | az network nic list-effective-nsg |
Only DenyAllInBound matched 3389 |
This is the breakthrough |
| 15:37 | Fixed | Add Allow-RDP from office /32 | Login prompt appears | The actual one-line fix |
| 16:30 | Hardened | Remove public IP, deploy Bastion + JIT | No public 3389 anywhere | The right end state |
Advantages and disadvantages
Azure’s “secure by default, but diagnosable” posture both causes this beginner pain and makes it quick to solve. Weigh it honestly:
| Advantages (why Azure helps you here) | Disadvantages (why it bites a beginner) |
|---|---|
| Ports are closed by default, so a fresh VM isn’t instantly attacked | The closed default is the #1 “can’t connect” surprise — you must add a rule |
| Serial console and Run Command let you fix the OS even with every port shut | They’re unfamiliar; beginners don’t know the back door exists and rebuild instead |
| Connection troubleshoot (Network Watcher) pinpoints the exact blocking hop | It’s buried in a separate Network Watcher blade, not the VM’s error message |
| VMAccess resets passwords/keys without a rebuild | Easy to miss; people recreate the VM to “fix” a forgotten password |
| Effective security rules show the true combined NSG result | Reading one NSG in isolation misleads — two NSGs can both apply |
| Bastion + JIT remove the need to expose 3389/22 at all | Extra setup/cost; tempting to just open 0.0.0.0/0 instead |
| The error type (timeout/refused/auth) is a precise diagnostic clue | Only if you know to read it — otherwise every failure looks identical |
The model is right: closing management ports by default has saved countless VMs from being compromised within minutes of creation (internet scanners hit 3389/22 constantly). The cost is a learning curve — but it’s a small one, and every gate above is one command to inspect and one to fix. The disadvantages are all “you didn’t know the tool existed,” which is exactly what this article fixes.
Hands-on lab
Reproduce the classic “timeout because the NSG is closed,” diagnose it the right way, then fix it — all on a free-tier-friendly B1s Linux VM (delete at the end so it costs nothing). Run in Cloud Shell (Bash).
Step 1 — Variables and resource group.
RG=rg-connect-lab
LOC=centralindia
VM=vm-connect-lab
az group create -n $RG -l $LOC -o table
Step 2 — Create a small Linux VM, generating an SSH key.
az vm create -n $VM -g $RG \
--image Ubuntu2204 --size Standard_B1s \
--admin-username azureuser --generate-ssh-keys \
--public-ip-sku Standard -o table
# Note the publicIpAddress in the output.
Step 3 — Reproduce the bug: remove the SSH allow rule. A default az vm create opens 22, so we’ll close it to simulate the secure-template situation:
# Find the auto-created NSG and delete its SSH rule to break access
NSG=$(az network nsg list -g $RG --query "[0].name" -o tsv)
az network nsg rule delete -g $RG --nsg-name $NSG --name default-allow-ssh 2>/dev/null \
|| az network nsg rule list -g $RG --nsg-name $NSG -o table # list to find the SSH rule name
Step 4 — Watch it fail. Try to SSH (replace with your IP):
ssh azureuser@<publicIpAddress>
# Hangs ~30s then: "Connection timed out" <- a TIMEOUT = a network gate
A timeout, exactly as predicted — a network gate is dropping you.
Step 5 — Diagnose the right way: read the effective NSG.
NIC=$(az vm show -n $VM -g $RG --query "networkProfile.networkInterfaces[0].id" -o tsv)
az network nic list-effective-nsg --ids $NIC \
--query "value[].effectiveSecurityRules[?direction=='Inbound' && access=='Allow' && (destinationPortRange=='22' || destinationPortRange=='*')].{name:name,port:destinationPortRange,src:sourceAddressPrefix}" \
-o table
# Likely shows no Allow for 22 -> the SSH gate is closed. Confirmed root cause.
Step 6 — Fix it for your IP only.
MYIP=$(curl -s ifconfig.me)
az network nsg rule create -g $RG --nsg-name $NSG \
--name Allow-SSH-MyIP --priority 300 \
--direction Inbound --access Allow --protocol Tcp \
--source-address-prefixes ${MYIP}/32 --destination-port-ranges 22 -o table
Step 7 — Connect.
ssh azureuser@<publicIpAddress>
# You're in. The network gate was the whole problem.
Step 8 — Bonus: use Run Command to peek inside without SSH. Proves the back door works:
az vm run-command invoke --command-id RunShellScript -n $VM -g $RG \
--scripts "ss -tlnp | grep ':22 ' && echo 'sshd is listening'"
Step 9 — Teardown (so it costs nothing).
az group delete -n $RG --yes --no-wait
You just reproduced, diagnosed and fixed the single most common Azure connectivity problem — and proved you can inspect a VM with no working SSH at all.
Common mistakes & troubleshooting
This is the centerpiece — the playbook to keep open at the moment you can’t connect. Find your symptom, confirm the cause with the exact command/portal path, apply the fix. It spans the everyday beginner blockers and a few deeper ones. Work it top-down: the rows are roughly ordered by how often they’re the culprit.
| # | Symptom | Root cause | Confirm (exact command / portal path) | Fix |
|---|---|---|---|---|
| 1 | RDP/SSH times out, VM is “Running” | NSG has no allow rule for your port/IP | az network nic list-effective-nsg → only DenyAllInBound matches |
Add inbound Allow for your IP /32 on 3389/22 |
| 2 | Timed out; only the office network fails | Your corporate/ISP firewall blocks outbound 3389/22 | Works on a phone hotspot; Test-NetConnection -Port 3389 fails on office only |
Ask IT to allow outbound, or use Bastion (443) |
| 3 | Timed out; IP “worked yesterday” | Dynamic public IP changed on stop/start | az vm list-ip-addresses shows a different IP than you saved |
Use the new IP; convert to Static |
| 4 | Timed out; no IP to connect to | VM has no public IP | VM → Overview shows blank public IP | Attach a public IP, or connect via Bastion |
| 5 | NSG is open but still times out | OS firewall (Defender / ufw) dropping the port |
Run Command: Get-NetFirewallRule -DisplayGroup 'Remote Desktop' / ufw status |
Enable the RDP rule / ufw allow 22/tcp |
| 6 | Fast connection refused | Listener service (TermService / sshd) not running |
Run Command: Get-Service TermService / systemctl is-active ssh |
Start + enable the service |
| 7 | Refused; service is running | sshd moved to a non-standard port (not 22) |
Run Command: grep ^Port /etc/ssh/sshd_config |
Connect with -p <port> and open it in NSG, or revert to 22 |
| 8 | Connected, but wrong password (Windows) | Forgotten/incorrect admin password | You reach the password prompt | az vm user update --username <u> --password ... |
| 9 | Permission denied (publickey) (Linux) |
VM’s public key ≠ your private key | ssh -v shows key offered, then denied |
az vm user update --ssh-key-value "$(cat ~/.ssh/id_rsa.pub)" |
| 10 | Too many authentication failures |
Client offers many wrong keys before the right one | ssh -v lists several keys tried |
ssh -i <key> -o IdentitiesOnly=yes user@ip |
| 11 | RDP “authentication error” / CredSSP | NLA/CredSSP patch mismatch between client and host | RDP error text mentions CredSSP/Oracle Remediation | Patch both ends; temporarily relax NLA via Run Command |
| 12 | Wrong username rejected | Using root/Administrator instead of the admin you set |
You guessed the name | Use the admin username from VM creation |
| 13 | Timed out even with NSG + OS firewall open | A route/UDR or Azure Firewall black-holes the traffic | Network Watcher → Connection troubleshoot; effective routes | Fix the route; allow the flow on the firewall |
| 14 | Was working, suddenly times out | VM is Stopped (deallocated), or a recent NSG/route change | VM → Overview power state; Activity log for recent NSG edits | Start the VM; revert the offending change |
| 15 | RDP connects then drops instantly | RDP licensing / too many sessions, or NLA loop | Event log via serial console; quser via Run Command |
Free a session; check RD licensing; relax NLA |
When even Run Command isn’t enough, here are the error strings you’ll actually see and what each one points to:
| Error string you see | On | What it really means | First confirm | Fix |
|---|---|---|---|---|
Connection timed out |
SSH | Packets dropped somewhere in the path | Effective NSG / OS firewall | Open NSG for your IP; check ufw |
Connection refused |
SSH | Reached the VM; nothing listening on the port | systemctl is-active ssh; port in sshd_config |
Start sshd; fix the port |
Permission denied (publickey) |
SSH | Network fine; key mismatch | ssh -v; the VM’s authorized_keys |
az vm user update --ssh-key-value ... |
Host key verification failed |
SSH | Your known_hosts has a stale key for that IP |
The IP was reused/rebuilt | ssh-keygen -R <ip> then reconnect |
| “Remote Desktop can’t connect to the remote computer” | RDP | Generic — usually a timeout (network gate) | Effective NSG; public IP | Open NSG; verify IP |
| “An authentication error has occurred (CredSSP)” | RDP | NLA/CredSSP patch mismatch | RDP error detail | Patch both sides; relax NLA temporarily |
| “The logon attempt failed” | RDP | You connected; wrong credentials | The login prompt appeared | Reset password via az vm user update |
Per-symptom detail on the ones that fool everyone
The NSG you edited isn’t the NSG in the path. A VM can have an NSG on its NIC and another on its subnet, and people edit one while the other does the denying. Never reason from a single NSG — pull az network nic list-effective-nsg (or the portal’s effective security rules), which merges both and shows the rule that actually wins by priority. If your new Allow at priority 300 isn’t working, look for a Deny at a lower number in front of it.
OS firewall after the NSG is “open.” The maddening one: you fixed the NSG, the timeout persists, and you conclude Azure is broken. It isn’t — the in-guest firewall is dropping the packet after it passed the NSG. Because you can’t log in to check, use Run Command to inspect Windows Defender Firewall or ufw, then enable the single port. Don’t disable the firewall wholesale; open the one rule.
Forgotten password is not a rebuild. Beginners delete the VM to escape a forgotten Windows password. Never do that — az vm user update --username <name> --password <new> resets it through the VMAccess extension in under a minute, disk and data intact. Same on Linux with --ssh-key-value to push a fresh public key when your key stopped matching.
Best practices
- Read the error type before you do anything. Timeout → network gates (NSG, IP, route, OS firewall). Refused → OS firewall or the listener service. Auth error → credentials. This one habit prevents most wasted effort.
- Never open 3389/22 to
0.0.0.0/0. Scope every management rule to your IP /32 (or a small office range). The whole internet scans these ports continuously; a wide-open rule gets a fresh VM compromised in minutes. - Trust effective rules, not a single NSG. Always diagnose with
az network nic list-effective-nsg/ the portal’s effective security rules, because subnet and NIC NSGs both apply. - Make management public IPs static, or better, don’t have them at all. A dynamic IP that changes on stop/start looks exactly like an outage.
- Prefer Azure Bastion over public RDP/SSH for anything beyond a quick lab. It connects over HTTPS from the portal with no public 3389/22 anywhere — removing the entire attack surface and the “my office blocks 3389” problem at once.
- Use just-in-time (JIT) VM access when you do keep public ports: 3389/22 stay closed and open only for your IP, for a fixed window, only when you ask.
- Know the back door before you need it. Practise Run Command and the serial console once on a test VM so that, during a real lockout, you reach for them instead of the delete button.
- Treat NSG rules as code. Define them in Bicep/Terraform and review changes, so an accidental edit that locks everyone out is caught and revertible.
- Don’t disable the OS firewall to “fix” connectivity — open the single required port. A disabled firewall is a security regression that long outlives the incident.
- Tag and document your jump path. Note for each VM how you’re meant to reach it (public IP + JIT, Bastion, or via a jumpbox) so on-call doesn’t rediscover it at 2am.
Security notes
The reason RDP/SSH is closed by default is that exposing it is genuinely dangerous, so fix connectivity in a way that stays secure rather than punching a hole and forgetting it.
- Least exposure on the port. If you must use a public IP, the NSG rule’s source should be your IP /32 or a tight CIDR — never
Any/0.0.0.0/0. Each unnecessary source range is attack surface. Pair this with JIT access so the port is closed except during an approved window. - Bastion removes the port entirely. Azure Bastion brokers your session over TLS (port 443) from the portal to the VM’s private IP, so there is no internet-facing 3389/22 to attack. For most teams this is the correct default and it also sidesteps “my network blocks 3389.”
- Prefer SSH keys over passwords on Linux, and disable password authentication once keys work. Keys aren’t brute-forceable the way a password is, which is precisely what internet scanners attempt against open 22.
- Store keys and recovery secrets properly. Keep SSH private keys off shared drives, and if you store credentials or keys for automation, put them in Key Vault — see Azure Key Vault: Secrets, Keys & Certificates. The
--generate-ssh-keysflow writes your key to~/.ssh; protect that directory. - Don’t relax NLA permanently. Temporarily loosening Network Level Authentication to break a CredSSP deadlock is fine for the fix; re-enable it afterwards, because NLA forces authentication before a session is established, which blunts a class of pre-auth RDP attacks.
- Audit who changed the NSG. A sudden “everyone’s locked out” is often an NSG/route edit; the Activity log shows who changed what, and IaC-defined rules make such changes reviewable instead of silent.
Cost & sizing
Diagnosing connectivity is essentially free — the tools (NSG rules, effective rules, Run Command, serial console, boot diagnostics, Network Watcher Connection troubleshoot) cost nothing or a few paise. The real cost questions are about the VM you’re trying to reach and the secure-access pattern you choose.
| Item | What drives the cost | Rough figure (India/USD) | Free-tier / note |
|---|---|---|---|
The VM (e.g. B1s) |
Size + region + hours running | B1s ≈ ₹700–900 / ~US$8–11 per month |
Stopped (deallocated) VMs incur no compute charge |
| Static public IP | Standard SKU IP, billed hourly | ≈ ₹300–400 / ~US$3.6 per month | Dynamic Basic IPs are cheaper but can change |
| Azure Bastion | Hours + outbound data; Basic vs Standard SKU | Basic ≈ ₹12–14 / ~US$0.19 per hour (~₹9,000+/mo if left on) | No per-VM agent; one Bastion serves the whole VNet |
| NSG / Run Command / serial console | — | Effectively free | Use freely while diagnosing |
| Network Watcher | Connection troubleshoot checks | A few paise per check | First diagnostic to reach for |
Sizing guidance for the access pattern, not the VM: for a single lab VM you poke at occasionally, a static public IP + JIT + a narrow NSG rule is the cheapest secure option (you pay for the IP and the VM; JIT and the NSG are free). For a fleet of VMs, one Azure Bastion for the VNet is usually cheaper and safer than putting a public IP on every VM — Bastion’s hourly cost is fixed regardless of VM count, and you delete a whole category of risk. The biggest hidden cost is a VM left Running that you locked yourself out of: it bills 24/7 while you can’t use it — which is exactly why fixing access (not rebuilding) matters. And remember a VM in Stopped (deallocated) state stops compute charges entirely, so if you’re done for the day, deallocate it (az vm deallocate), accepting that a dynamic IP may change on the next start.
Interview & exam questions
Q1. A VM shows “Running” but RDP times out. What’s your first diagnostic step and why?
Pull the effective NSG rules for the VM’s NIC (az network nic list-effective-nsg or the portal’s effective security rules) and check for an inbound Allow on 3389 from your source IP. A timeout means packets are being silently dropped, and the NSG is the most common dropper; the effective view is authoritative because subnet and NIC NSGs both apply.
Q2. SSH returns Connection refused rather than Connection timed out. What does that distinction tell you?
Refused means the packet reached the VM and something answered “no” on that port — so the NSG, public IP and route are fine. The problem is inside the OS: sshd isn’t running (or is on a different port), or the OS firewall is actively rejecting. Timeout, by contrast, points at a network gate dropping the packet before it’s answered.
Q3. You opened the NSG for 3389 but RDP still times out. What’s the likely cause?
The in-guest OS firewall (Windows Defender Firewall) is dropping the port after it passes the NSG. Confirm and fix with Run Command (Get-NetFirewallRule -DisplayGroup 'Remote Desktop', then Enable-NetFirewallRule) since you can’t RDP in to check. An NSG allow and an OS-firewall allow are two separate gates.
Q4. How do you inspect or repair a VM when you have no working RDP/SSH at all? Use Run Command (runs a script inside the VM via the Azure control plane) for most checks/fixes, and the serial console (a direct console to the OS that bypasses all networking) when the OS won’t boot far enough for Run Command. Neither needs an open port or working credentials path.
Q5. A user forgot the Windows admin password. Do you rebuild the VM?
No. Use az vm user update --username <name> --password <new>, which drives the VMAccess extension to reset the local admin password in place, preserving the OS disk and data. On Linux, the same command with --ssh-key-value repairs a mismatched SSH public key.
Q6. What’s the difference between a dynamic and a static public IP for connectivity? A dynamic public IP can change when the VM is stopped (deallocated) and restarted, so a saved IP may stop working and look like an outage. A static IP is reserved and never changes. For anything you connect to regularly, use static — or remove the public IP and use Bastion.
Q7. Why shouldn’t you open 3389/22 to 0.0.0.0/0, even temporarily?
Internet scanners continuously probe 3389 and 22; a VM with those ports open to the whole internet is typically discovered and brute-forced within minutes. Scope the rule to your IP /32, and prefer JIT access (port closed until you request a time-boxed opening) or Bastion (no public port at all).
Q8. Two NSGs are attached — one to the subnet, one to the NIC. How is the result computed? Both NSGs apply, and a packet must be allowed by both to pass; within each NSG, rules are evaluated by priority (lowest number first, first match wins). The effective security rules view merges subnet and NIC NSGs into the single set that actually governs the traffic — always diagnose from that, not one NSG.
Q9. RDP fails with a CredSSP / “authentication error.” Is this a network problem? No — reaching a CredSSP error means you connected to the RDP service, so the network path is open. It’s an NLA/CredSSP patch-level mismatch between client and host. Patch both ends; if you must connect immediately, temporarily relax NLA via Run Command, then re-enable it.
Q10. Which Azure tool tells you the exact hop where a connection is blocked, and where does it live? Connection troubleshoot in Network Watcher tests connectivity from a source (e.g. a VM) to a destination and reports the blocking hop — NSG rule, route, or unreachable target. It lives under the Network Watcher resource, not the VM blade, which is why beginners miss it.
These map to the AZ-104 (Azure Administrator) objectives on configuring VM networking, NSGs and connectivity, and touch AZ-700 (Network Engineer) for the deeper routing/Network Watcher items.
Quick check
- RDP/SSH times out on a “Running” VM. Which half of the path do you investigate first — and name the most likely single cause.
- You get
Connection refusedon SSH. What does that prove about the network, and where do you look next? - You opened the NSG for 22 but SSH still times out. What’s the next gate to check, and which tool inspects it without logging in?
- The public IP that worked yesterday now times out. What’s the likely reason, and the permanent fix?
- A teammate forgot the Windows admin password. What’s the one-command fix, and what must you not do?
Answers
- The network gates (timeout = silently dropped packets). The most likely single cause is an NSG with no inbound Allow for your port/IP — confirm with
az network nic list-effective-nsgand add a narrow Allow for your IP /32. - It proves the packet reached the VM (NSG, public IP and route are all fine). Look inside the OS: the listener (
sshd) isn’t running or is on a non-standard port, or the OS firewall is rejecting — check via Run Command. - The OS firewall (Windows Defender Firewall /
ufw). Inspect it with Run Command (Get-NetFirewallRule -DisplayGroup 'Remote Desktop'orufw status) since you can’t log in, then enable the single port. - The public IP is dynamic and changed on a stop/start. Use the current IP from
az vm list-ip-addresses, and convert it to Static so it never moves again (or drop the public IP and use Bastion). az vm user update --username <name> --password <new>(it resets via the VMAccess extension, data intact). Do not delete and rebuild the VM.
Glossary
- NSG (network security group) — A set of inbound/outbound allow-deny rules applied to a NIC and/or subnet; the gate that most often blocks RDP/SSH by default.
- Effective security rules — The merged result of the subnet NSG and NIC NSG; the authoritative view of which rule actually governs a packet.
- Public IP — The internet-facing address attached to a VM’s NIC; without one, the VM isn’t reachable from the public internet.
- Dynamic vs static IP — Dynamic public IPs can change when a VM is deallocated and restarted; static ones are reserved and stable.
- RDP (port 3389) — Remote Desktop Protocol, the graphical login to Windows VMs, over TCP 3389.
- SSH (port 22) — Secure Shell, the terminal login to Linux VMs, over TCP 22.
- OS firewall — The in-guest firewall (Windows Defender Firewall, Linux
ufw/firewalld); a second gate that can block a port even when the NSG allows it. - Listener /
sshd/TermService— The service inside the OS that accepts connections on 22 (sshd) or 3389 (TermService); if it isn’t running you get “connection refused.” - Serial console — A direct, network-independent console to the VM’s OS in the portal; works even with every port closed.
- Run Command — Runs a script inside a VM through the Azure control plane, no network login required — the way to inspect/fix the OS when you can’t connect.
- Azure Bastion — A managed service that provides RDP/SSH from the portal over TLS to a VM’s private IP, removing the need for any public 3389/22.
- JIT (just-in-time) VM access — A Defender for Cloud feature that keeps management ports closed and opens them for your IP for a limited window on request.
- VMAccess extension — The Azure VM extension that resets local passwords (Windows) or repairs SSH public keys (Linux) from outside the VM.
- Boot diagnostics — A captured screenshot/serial log of the VM at boot; useful to see an OS that’s stuck before networking comes up.
- Stopped (deallocated) — A VM power state where the compute is released (no compute billing) and a dynamic public IP may change on next start.
Next steps
- Build the VM you’ll practise on with Deploy Your First Azure VM: Portal and CLI, Step by Step.
- Solidify the network model behind the NSG gate with Azure Virtual Network: Subnets and NSGs.
- Adopt the secure way in — no public management ports — by standing up Azure Bastion for the VNet, then keep PaaS off the public internet too with Azure Private Endpoint vs Service Endpoint: Secure PaaS Access.
- When the block is deeper than an NSG (routes, firewalls, effective routes), move up to Troubleshooting Azure VNet Connectivity with NSGs, UDRs and Network Watcher.
- Keep credentials and keys safe with Azure Key Vault: Secrets, Keys & Certificates.