An Azure VM running a VPN appliance sits inside two independent decision systems. Azure decides where a packet leaves a subnet, using route tables and the NIC's forwarding setting. The appliance's own operating system decides whether it forwards the decrypted packet onward. A tunnel that comes up perfectly can still fail on the second system, and that is where most of these deployments stop.

Three owners of one path

Take a branch network of 192.168.50.0/24 and a workload subnet of 10.0.10.0/24, with the appliance at 10.0.0.4 in its own subnet. A single request touches three separate configurations.

DecisionConfigured inHow it fails
Where the workload subnet sends branch trafficAzure route table entryTraffic leaves the subnet and never reaches the appliance
Whether a NIC may accept traffic not addressed to itAzure NIC IP forwardingPackets arrive and disappear at the interface
Whether the guest forwards decrypted trafficGuest OS or vendor appliance policyTunnel is up, workload is unreachable
Whether the workload accepts the sourceNSG and service policyRequests delivered, replies refused

Each row is owned by a different team in most organisations, which is why this failure usually arrives as three tickets instead of one.

The route that points at the appliance

Associate a route table with the workload subnet and give the branch prefix a next hop of type Virtual appliance with 10.0.0.4 as the address. Use the appliance's reachable private address, never its public VPN entry point. The next hop has to be an address the workload subnet can already reach. Leave the rest of the workload's routing alone unless you have deliberately decided to replace the default route.

Keep the appliance in its own subnet, and make sure the route that sends branch traffic to the appliance does not also capture the appliance's own outbound path. That loop looks like a healthy tunnel with zero replies, which is a miserable thing to debug at 2am.

The NIC flag everyone forgets

Azure has a per-NIC IP forwarding setting, and it is off by default. It exists because a forwarding NIC receives packets addressed to something other than itself, and dropping those silently is the safe default for everyone else.

az network nic update --resource-group rg-net --name appliance-nic --ip-forwarding true turns it on for one interface. Microsoft's NIC forwarding guidance requires the setting on each attached NIC that forwards traffic, so a single-NIC appliance still needs it set on that one NIC.

The flag is not a route and it is not a firewall rule. Turning it on grants permission and nothing else.

What the guest does with the decrypted packet

Once the tunnel terminates, the appliance's own stack makes the next decision. On a Linux guest, IPv4 forwarding is a runtime setting, and sysctl -w net.ipv4.ip_forward=1 lasts until the next boot. Persist it in a file under /etc/sysctl.d/ instead. A vendor appliance has its own equivalent, and Linux instructions pasted into a vendor platform usually do nothing at all.

Guest firewall policy is separate again, and so is the workload's network security group. Allowing UDP 500 and 4500 to the VM's public address protects the tunnel; it says nothing about whether a decrypted branch request may reach a workload port.

Follow one request and its reply

Pick one permitted flow and trace it end to end. The branch needs a route for 10.0.10.0/24 over the site connection, the appliance needs a delivery path to the workload subnet, and the workload subnet needs a return route toward the branch.

Decide early whether the design preserves the branch source address or translates it. NAT changes what the workload sees, so its access rules should describe the model you actually chose rather than a guessed gateway address.

A successful handshake proves one link of that chain. The path is complete when the reply returns through the same appliance and the workload's own policy permits it.

Pennadoù liammet