How Azure NSGs Allow or Deny a Packet: 6 Real Packets, Rule by Rule
▶ Watch on YouTube & subscribe to The Stack Underflow
A packet arrives at a server in Azure. Which rule lets it in, or stops it, and can you predict the answer before you deploy anything? The video follows six packets through a real Azure network, Microsoft’s quickstart template nsg-dmz-in-vnet, and checks every network security group (NSG) rule in order. This page is the written version: the network, the rules, every packet’s path and verdict, and the Microsoft documentation behind each step.
The one-line version: an NSG reads its rules lowest number first, and the first rule that matches all five fields decides. Whatever you didn’t write a rule for falls to the default rules, and inside a virtual network they allow it.
Last verified against Microsoft Learn: 1 October 2026.
The network in one paragraph
A virtual network (VNet) is your private network in Azure, split into subnets. 10.0.1.0/24 means the 256 addresses from 10.0.1.0 to 10.0.1.255. Azure reserves five addresses in every subnet (the first four and the last), so the first address a server can get is .4.
The template creates one VNet, 10.0.0.0/16, with three subnets, each with its own NSG:
| Subnet | Range | Server used in the video | NSG |
|---|---|---|---|
| Front end (FE) | 10.0.0.0/24 | 10.0.0.4 | FE NSG |
| App | 10.0.1.0/24 | 10.0.1.4 | App NSG |
| Database (DB) | 10.0.2.0/24 | 10.0.2.4 | DB NSG |
The template deploys no VMs, so the video uses the first usable address in each subnet as the server.
The five facts every packet carries
Every NSG rule checks the same five fields, which Microsoft calls the five-tuple: source address, source port, destination address, destination port, protocol. The destination port names the service: 3389 Remote Desktop, 22 SSH, 443 HTTPS, 1433 SQL Server.
How an NSG reads its rules
- Custom rules have a priority from 100 to 4096. Lower numbers are processed first.
- Once traffic matches a rule, processing stops. Nothing below it is read.
- A rule matches only if all five fields match. A rule that fails on one field is skipped, and the check moves on.
- You can’t create two rules with the same priority and direction.
- NSGs are stateful: the reply to an allowed connection is allowed without its own rule.
The rules you didn’t write
Every NSG ends with default rules. You can’t remove them, but you can override them with rules that have a lower number.
| Direction | Priority | Name | Source → Destination | Access |
|---|---|---|---|---|
| Inbound | 65000 | AllowVNetInBound | VirtualNetwork → VirtualNetwork | Allow |
| Inbound | 65001 | AllowAzureLoadBalancerInBound | AzureLoadBalancer → any | Allow |
| Inbound | 65500 | DenyAllInbound | any → any | Deny |
| Outbound | 65000 | AllowVnetOutBound | VirtualNetwork → VirtualNetwork | Allow |
| Outbound | 65001 | AllowInternetOutBound | any → Internet | Allow |
| Outbound | 65500 | DenyAllOutBound | any → any | Deny |
VirtualNetwork is a service tag, not just your VNet’s range: it also covers connected on-premises address spaces, peered VNets and a few other ranges. AzureLoadBalancer covers only the load balancer’s health probes, not real traffic.
The three NSGs in the lab
| NSG | Rule | Direction | Matches | Access |
|---|---|---|---|---|
| FE NSG | 100 rdp_rule | In | TCP 3389 from Internet | Allow |
| FE NSG | 101 web_rule | In | TCP 80 from Internet | Allow |
| App NSG | 100 Allow_FE | In | TCP 443 from 10.0.0.0/24 | Allow |
| App NSG | 101 Block_RDP_Internet | In | TCP 3389 from Internet | Deny |
| App NSG | 200 Block_Internet_Outbound | Out | anything to Internet | Deny |
| DB NSG | 100 Allow_App | In | TCP 1433 from 10.0.1.0/24 | Allow |
| DB NSG | 101 Block_FE | In | anything from 10.0.0.0/24 | Deny |
| DB NSG | 102 Block_App | In | anything from 10.0.1.0/24 | Deny |
| DB NSG | 200 Block_Internet | Out | anything to Internet | Deny |
FE NSG has no outbound rules of its own, so only the default outbound rules apply to it.
Six packets, step by step
Each packet first gets a route lookup (no subnet here has a route table, so only Azure’s system routes apply), then the source subnet’s NSG checks it outbound, then the destination subnet’s NSG checks it inbound.
Packet 1: the app server queries the database. 10.0.1.4 → 10.0.2.4, TCP 1433.
Three system routes contain 10.0.2.4: 10.0.0.0/16 (the virtual network), 0.0.0.0/0 (Internet) and 10.0.0.0/8 (a reserved range with next hop None, which drops traffic). The /16 is the most specific, so the packet stays in the VNet. App NSG outbound: rule 200 is for Internet traffic, so no match; the default AllowVnetOutBound (65000) allows it. DB NSG inbound: rule 100 Allow_App matches all five fields. Allowed by DB NSG rule 100. This is exactly the traffic the rule was written for.
Packet 2: the front end tries the database directly. 10.0.0.4 → 10.0.2.4, TCP 1433. FE NSG has no outbound rules, so AllowVnetOutBound (65000) allows it. DB NSG inbound: rule 100 needs a source in 10.0.1.0/24, and 10.0.0.4 isn’t, so no match. Rule 101 Block_FE matches. Denied by DB NSG rule 101. An allow rule only helps when all five fields match.
Packet 3: Remote Desktop from the Internet to the front end. 203.0.113.10 → 10.0.0.4, TCP 3389. The template gives the server no public IP, so the video checks the NSGs as if the packet reached 10.0.0.4. FE NSG inbound: rule 100 rdp_rule matches. Allowed. RDP from the whole Internet is how this sample is written; in a real network you’d limit the source or use Azure Bastion.
Packet 4: Remote Desktop from the Internet to the app server. 203.0.113.10 → 10.0.1.4, TCP 3389. App NSG inbound: rule 100 is for port 443, not 3389, so no match. Rule 101 Block_RDP_Internet matches. Denied by App NSG rule 101.
Packet 5: SSH that nobody allowed, allowed anyway. 10.0.0.4 → 10.0.1.4, TCP 22. FE NSG outbound: AllowVnetOutBound (65000). App NSG inbound: rule 100 is for 443, rule 101 is for 3389, so neither matches port 22. The default rules decide, and AllowVNetInBound (65000) allows traffic from inside the virtual network. Allowed by App NSG rule 65000. To allow only 443, add your own deny rule with a priority number below 65000.
Packet 6: the app server tries the Internet. 10.0.1.4 → 198.51.100.20, TCP 443.
The only matching system route is 0.0.0.0/0, next hop Internet. App NSG outbound: rule 200 Block_Internet_Outbound matches. Denied by App NSG rule 200. Outbound rules protect you too.
| # | Packet | Verdict | Decided by |
|---|---|---|---|
| 1 | App → DB, TCP 1433 | Allowed | DB NSG 100 Allow_App |
| 2 | FE → DB, TCP 1433 | Denied | DB NSG 101 Block_FE |
| 3 | Internet → FE, TCP 3389 | Allowed | FE NSG 100 rdp_rule |
| 4 | Internet → App, TCP 3389 | Denied | App NSG 101 Block_RDP_Internet |
| 5 | FE → App, TCP 22 | Allowed | App NSG 65000 AllowVNetInBound |
| 6 | App → Internet, TCP 443 | Denied | App NSG 200 Block_Internet_Outbound |
What to remember
- A rule checks five facts, and all five must match.
- Lowest number first; the first full match decides.
- Whatever you didn’t write a rule for falls to the default rules, and inside a virtual network they allow it.
- A packet needs every NSG on its path to allow it.
Pause & Prove: the questions from the video
1. The pinned question
The app subnet’s NSG has two inbound rules: 100 allows TCP 443 from the front-end subnet, 101 denies RDP (3389) from the Internet. The front end opens SSH (port 22) to the app server. Allowed or denied, and by which rule?
Allowed, by 65000 AllowVNetInBound. Rule 100 fails on the port (443, not 22). Rule 101 fails on the port and the source (it’s for the Internet). With no custom match, the default rules decide, and traffic from inside the VNet is allowed. To block it, add your own deny with a number below 65000.
2. The Community poll
Two VMs in the same Azure VNet. The NSG has no rule for port 22. SSH from one VM to the other is…
- Denied by default. Tempting, but DenyAllInbound (65500) only catches what the rules above it didn’t. AllowVNetInBound (65000) is checked first.
- Allowed by a default rule. ✓ 65000 AllowVNetInBound allows VNet-to-VNet traffic.
- Dropped by routing. The system route for the VNet’s own range delivers it inside the VNet.
- Allowed only with a public IP. Traffic between two VMs in the same VNet doesn’t need a public IP.
Related Shorts
- Why Azure let SSH in when no rule allowed it (packet 5)
- An Allow rule at 100 and the packet is still denied (packet 2)
- Your Azure VM can’t reach the Internet? Check the outbound rules (packet 6)
Before / after this video
- This is video 1 of 4 in the series. Start here.
- After: Azure Route Tables and NVAs: Why the Reply Took a Different Path (video 2)
- Then: Azure Subnet NSG vs NIC NSG (video 3) and How Azure Firewall Decides (video 4)
Sources
Read on 1 October 2026:
- Azure network security groups overview: priority 100–4096, first match stops processing, five-tuple, same-priority rule, default rules table, “can’t remove… but can override”, stateful flow records, NAT before inbound NSG processing
- How network security groups filter network traffic: order of NSG evaluation
- Azure service tags overview: what VirtualNetwork, Internet and AzureLoadBalancer contain
- Azure virtual network traffic routing: system routes (VNet, 0.0.0.0/0 Internet, 10.0.0.0/8 None) and longest prefix match
- Private IP addresses: five reserved addresses per subnet
- Network template: “nsg-dmz-in-vnet” from Azure/azure-quickstart-templates (MIT License)
Change notes
- 1 Oct 2026: first published.
Not affiliated with or endorsed by Microsoft. Found a mistake? Tell us in the video’s comments and we’ll correct this page.
Found this useful? The deep version lives on YouTube — new breakdowns of how AI dev tools actually work, weekly.
Subscribe on YouTube →Prefer email? Get the free newsletter: one failure, traced step by step, about once a week.