Azure Route Tables and NVAs: Why the Reply Took a Different Path

September 30, 2026 · Azure Networking, Packet by Packet: NSGs, Route Tables, ASGs and Azure Firewall (part 2)

▶ Watch on YouTube & subscribe to The Stack Underflow

Before any rule allows or denies a packet, Azure has to decide where it goes next. The video follows five packets through Microsoft’s quickstart template userdefined-routes-appliance, where a route table sends traffic through a network virtual appliance (NVA), and shows what happens on the way back. This page walks the same five packets with the routes, the rules and the documentation behind every step.

The one-line version: routes decide the path, NSGs decide the verdict. The most specific route wins, and routes belong to the subnet a packet leaves from, so the reply can take a different way back.

Last verified against Microsoft Learn: 1 October 2026.

How Azure picks a route

Every subnet has a list of effective routes: an address prefix plus a next hop. Azure adds system routes for you:

PrefixNext hopMeaning
The VNet’s own address spaceVirtual networkDelivered inside the VNet
0.0.0.0/0InternetEverything else goes out
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10 (and a few more)NoneDropped

A route table adds your own user-defined routes (UDRs). Each subnet can have zero or one route table, and its routes apply to traffic leaving that subnet.

When several routes contain the destination:

  1. Longest prefix wins. A /24 beats a /16, because it describes a smaller, more specific range.
  2. Same prefix? Azure prefers a user-defined route, then a BGP route, then a system route. The overridden system route shows as Invalid in the effective routes.

What an NVA needs

A network virtual appliance is a VM that forwards traffic for others, often a firewall. A route with next hop Virtual appliance points at its private IP. Two things must be true for it to forward:

  • IP forwarding must be enabled on the appliance’s Azure network card. It lets the NIC receive traffic not addressed to any of its own IPs, and send traffic with a different source IP. It’s off by default.
  • The software inside the VM must forward too. Microsoft is explicit: IP forwarding is an Azure setting, and the VM must also run an application that forwards the traffic.

The lab

One VNet, 10.1.0.0/16, three subnets, one VM each:

VMRoleSubnetAddress
vm0Front endFrontend10.1.0.4
vm1Appliance (NVA), IP forwarding onNVA10.1.1.4
vm2Back endBackend10.1.2.4
  • Route table “Basic NVA”, attached only to the Frontend subnet, has one route: 10.1.2.0/24 → virtual appliance 10.1.1.4.
  • Default NSG, shared by all three subnets, has one inbound rule: 100 rdp_rule allows TCP 3389 from the Internet. No outbound rules, so the default outbound rules apply. No VM’s network card has its own NSG.

vm0 and vm2 get dynamic private addresses; the video shows them as .4, the usual first address. Azure normally assigns the next available address, but doesn’t guarantee it.

Five packets, step by step

Packet 1: the front end connects to the back end. vm0 10.1.0.4 → vm2 10.1.2.4, TCP 3389. Four routes contain 10.1.2.4: your 10.1.2.0/24, the VNet’s 10.1.0.0/16, 0.0.0.0/0, and the reserved 10.0.0.0/8. The /24 is the most specific, so the packet goes to vm1, the appliance. Default NSG checks it leaving Frontend (AllowVnetOutBound 65000) and entering the NVA subnet: rule 100 is for Internet traffic, so no match, and AllowVNetInBound 65000 allows it. vm1 has IP forwarding on, so Azure hands it a packet addressed to someone else, and it sends it on. The NVA subnet has no route table, so the system route for 10.1.0.0/16 delivers it to the Backend subnet, where 65000 allows it again. Allowed, last allowed by Default NSG 65000 AllowVNetInBound. The route table, not the NSG, decided the path.

The way back: the reply leaves the Backend subnet, which has no route table, so it goes straight to vm0, not through the appliance. The NSGs don’t need a rule for it: they’re stateful.

(The video’s model checks the NVA subnet’s NSG against the packet’s original source and destination. That follows from NSGs matching on the five-tuple; Microsoft doesn’t state this case explicitly.)

Packet 2: the back end connects to the front end. vm2 10.1.2.4 → vm0 10.1.0.4, TCP 3389. The Backend subnet has no route table, so 10.1.0.0/16 sends it straight to vm0. Default NSG allows it out (65000) and in (65000). Allowed, and it never touches the appliance. The way back: routing decides the reply separately. The reply leaves the Frontend subnet, whose route sends 10.1.2.0/24 to the appliance, so the reply goes through vm1, which the request never passed.

Packet 3: what if IP forwarding is off on the appliance? vm0 → vm2, TCP 3389, with IP forwarding turned off on vm1’s NIC. The route still points at 10.1.1.4, and the NSGs still allow it, as in packet 1. But without IP forwarding, Azure won’t hand vm1’s NIC a packet addressed to 10.1.2.4. Dropped at vm1. The route alone isn’t enough: the NIC setting and the forwarding software must both be in place.

Packet 4: Remote Desktop from the Internet to the front end. 203.0.113.10 → vm0’s public IP, TCP 3389. Azure translates the public address to the private one, 10.1.0.4, before any NSG sees it. Default NSG inbound: rule 100 rdp_rule matches. Allowed. The reply comes back the same way.

Packet 5: a web request from the Internet to the back end. 203.0.113.10 → vm2’s public IP, TCP 80. After translation to 10.1.2.4, Default NSG checks inbound: rule 100 is for 3389, not 80. Nothing else matches, so DenyAllInbound (65500) blocks it. Denied by Default NSG 65500.

#PacketPathVerdictDecided by
1vm0 → vm2, TCP 3389via vm1 (UDR /24); reply directAllowedDefault NSG 65000
2vm2 → vm0, TCP 3389direct; reply via vm1AllowedDefault NSG 65000
3vm0 → vm2, IP forwarding offto vm1, stopsDroppedIP forwarding off
4Internet → vm0, TCP 3389public IP → 10.1.0.4AllowedDefault NSG 100 rdp_rule
5Internet → vm2, TCP 80public IP → 10.1.2.4DeniedDefault NSG 65500 DenyAllInbound

Why asymmetric paths matter

In packets 1 and 2, one connection took two different paths. That’s fine for plain forwarding. But Microsoft notes that most stateful NVAs, such as firewalls, require traffic symmetry: an appliance that sees only one direction of a connection usually drops it. The usual fixes are route tables on both sides, so both directions pass the appliance, or SNAT on the appliance so replies come back to it.

The template today

The routing in the video works exactly as shown, but the template as published uses Basic public IP addresses, and Basic SKU public IPs were retired on 30 September 2025. Standard public IPs are static and closed to inbound traffic until an NSG allows it, which rule 100 does for RDP here. To deploy the lab yourself, use Standard static public IPs and a current VM size and image.

Pause & Prove: the questions from the video

1. The pinned question

Only the front-end subnet has the route “10.1.2.0/24 → appliance 10.1.1.4”. The back end opens a connection to the front end. Does the request go through the appliance? Does the reply?

The request goes straight; the reply goes through the appliance. The request leaves the Backend subnet, which has no route table, so the VNet system route applies. The reply leaves the Frontend subnet, whose UDR sends 10.1.2.0/24 to the appliance. Routes belong to the subnet a packet leaves from.

2. The Community poll

Two routes match a packet’s destination: 10.1.0.0/16 (the VNet) and your UDR 10.1.2.0/24 → appliance. Which one does Azure use?

  • The VNet route: system routes win. No: user-versus-system only breaks a tie between routes with the same prefix; here the prefixes differ, so the longest prefix decides.
  • The /24: the most specific route wins. ✓ Longest prefix match decides first.
  • Whichever was created first. Creation order plays no part in route selection.
  • Both: the packet is copied. Azure picks one route per packet.

For the same prefix, your UDR would beat the system route.

Before / after this video

Sources

Read on 1 October 2026:

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.