Hub and Spoke Networking in Azure

Deploying a VNet per environment quickly creates a web of connections with shared services duplicated everywhere. The hub-and-spoke topology solves this by placing shared infrastructure — gateways, firewalls, DNS, Bastion — in a central hub VNet that all spoke VNets connect to. It is the most common enterprise network pattern in Azure.

The topology at a glance

In a hub-and-spoke network:

The hub VNet contains:

- Azure Firewall or a third-party NVA for traffic inspection

- VPN Gateway or ExpressRoute Gateway for on-premises connectivity

- Azure Bastion for secure administrative access to VMs

- Central DNS (Azure Private Resolver or custom DNS servers)

Each spoke VNet contains:

- Application workloads (VMs, AKS clusters, App Services)

- Subnets segmented by application tier

- No gateways, no firewalls — those are in the hub

Spokes connect to the hub through VNet peering with gateway transit enabled. Traffic between spokes or to the internet goes through the hub firewall.

Building the hub VNet

The hub VNet needs several reserved subnets for Azure services. Create them with the exact names Azure requires:

# Create the hub VNet with a /16 address space
az group create --name rg-hub-networking --location eastus

az network vnet create \
  --name vnet-hub-eastus \
  --resource-group rg-hub-networking \
  --location eastus \
  --address-prefixes 10.0.0.0/16

# Firewall subnet (Azure Firewall requires exactly this name and minimum /26)
az network vnet subnet create \
  --name AzureFirewallSubnet \
  --resource-group rg-hub-networking \
  --vnet-name vnet-hub-eastus \
  --address-prefixes 10.0.0.0/26

# Gateway subnet for VPN or ExpressRoute
az network vnet subnet create \
  --name GatewaySubnet \
  --resource-group rg-hub-networking \
  --vnet-name vnet-hub-eastus \
  --address-prefixes 10.0.1.0/27

# Bastion subnet (minimum /26)
az network vnet subnet create \
  --name AzureBastionSubnet \
  --resource-group rg-hub-networking \
  --vnet-name vnet-hub-eastus \
  --address-prefixes 10.0.2.0/26

# Management subnet for shared DNS, monitoring agents, etc.
az network vnet subnet create \
  --name snet-shared-mgmt \
  --resource-group rg-hub-networking \
  --vnet-name vnet-hub-eastus \
  --address-prefixes 10.0.3.0/24

Deploying Azure Firewall in the hub

# Create a public IP for Azure Firewall
az network public-ip create \
  --name pip-azfw-hub \
  --resource-group rg-hub-networking \
  --location eastus \
  --sku Standard \
  --zone 1 2 3

# Create Azure Firewall (Premium for IDPS and TLS inspection)
az network firewall create \
  --name azfw-hub-eastus \
  --resource-group rg-hub-networking \
  --location eastus \
  --sku AZFW_VNet \
  --tier Premium \
  --vnet-name vnet-hub-eastus \
  --public-ip-address pip-azfw-hub \
  --enable-dns-proxy true

Get the firewall’s private IP — you need this for route tables in the spoke VNets:

az network firewall show \
  --name azfw-hub-eastus \
  --resource-group rg-hub-networking \
  --query "ipConfigurations[0].privateIPAddress" \
  --output tsv

Connecting a spoke to the hub

Create a spoke VNet and peer it to the hub:

# Create spoke VNet
az group create --name rg-spoke-prod --location eastus

az network vnet create \
  --name vnet-spoke-prod-eastus \
  --resource-group rg-spoke-prod \
  --location eastus \
  --address-prefixes 10.10.0.0/16

# Create spoke subnets
az network vnet subnet create \
  --name snet-web \
  --resource-group rg-spoke-prod \
  --vnet-name vnet-spoke-prod-eastus \
  --address-prefixes 10.10.1.0/24

# Get VNet IDs for peering
HUB_ID=$(az network vnet show --name vnet-hub-eastus --resource-group rg-hub-networking --query id --output tsv)
SPOKE_ID=$(az network vnet show --name vnet-spoke-prod-eastus --resource-group rg-spoke-prod --query id --output tsv)

# Peer hub to spoke (with gateway transit)
az network vnet peering create \
  --name peer-hub-to-spoke-prod \
  --resource-group rg-hub-networking \
  --vnet-name vnet-hub-eastus \
  --remote-vnet $SPOKE_ID \
  --allow-vnet-access \
  --allow-forwarded-traffic \
  --allow-gateway-transit

# Peer spoke to hub (use remote gateways)
az network vnet peering create \
  --name peer-spoke-prod-to-hub \
  --resource-group rg-spoke-prod \
  --vnet-name vnet-spoke-prod-eastus \
  --remote-vnet $HUB_ID \
  --allow-vnet-access \
  --allow-forwarded-traffic \
  --use-remote-gateways

Route tables for forced tunneling through the firewall

Create a route table that forces all traffic from the spoke through the hub firewall. Replace 10.0.0.4 with your firewall’s actual private IP:

# Create the spoke route table
az network route-table create \
  --name rt-spoke-prod \
  --resource-group rg-spoke-prod \
  --location eastus \
  --disable-bgp-route-propagation true

# Default route to firewall (catches all internet and cross-spoke traffic)
az network route-table route create \
  --name route-default-to-fw \
  --route-table-name rt-spoke-prod \
  --resource-group rg-spoke-prod \
  --address-prefix 0.0.0.0/0 \
  --next-hop-type VirtualAppliance \
  --next-hop-ip-address 10.0.0.4

# Route to other spokes through the firewall
az network route-table route create \
  --name route-spokes-to-fw \
  --route-table-name rt-spoke-prod \
  --resource-group rg-spoke-prod \
  --address-prefix 10.0.0.0/8 \
  --next-hop-type VirtualAppliance \
  --next-hop-ip-address 10.0.0.4

# Attach the route table to the spoke subnet
az network vnet subnet update \
  --name snet-web \
  --resource-group rg-spoke-prod \
  --vnet-name vnet-spoke-prod-eastus \
  --route-table rt-spoke-prod
Tip

The —disable-bgp-route-propagation true flag prevents VPN gateway-learned routes from overriding your custom routes. Always enable this on spoke route tables when using a hub firewall.

Common mistakes

  1. Not planning hub subnet addresses carefully. AzureFirewallSubnet, GatewaySubnet, and AzureBastionSubnet all have minimum size requirements. If your hub VNet address space is too small or you didn’t reserve enough room, you cannot add these subnets later without rebuilding. Size the hub generously: /16 is typical.
  2. Forgetting that UseRemoteGateways requires the hub’s gateway to exist. The spoke peering flag useRemoteGateways=true will fail if the hub VNet does not yet have a VPN or ExpressRoute gateway. Either create the gateway first, or create the peering without the flag and update it after the gateway is deployed.
  3. Not adding Azure Firewall application and network rules. Creating Azure Firewall in the hub does not automatically allow traffic. The firewall’s default policy is deny-all. If you route traffic through the firewall without creating rules to allow it, all inter-spoke and internet traffic will silently drop. Add network rules and application rules before routing traffic through the firewall.

Frequently asked questions

What is the hub in a hub-and-spoke network?

The hub is a central VNet that contains shared infrastructure: the VPN or ExpressRoute gateway for on-premises connectivity, Azure Firewall for traffic inspection, Azure Bastion for secure VM access, and DNS services. Spoke VNets peer to the hub to use these shared resources.

How many spoke VNets can connect to a hub?

A single hub VNet can have up to 500 peering connections. In practice, most organizations use between 5 and 50 spokes. For very large environments with hundreds of spokes, Azure Virtual WAN provides a managed hub with higher scale limits.

Do spoke VNets need to peer with each other for east-west traffic?

No — and they usually shouldn't. Instead, configure route tables in each spoke to send all traffic (0.0.0.0/0 and specific prefixes) to Azure Firewall in the hub. The firewall routes and inspects the traffic, then forwards it to the destination spoke. This gives you a single inspection point for all east-west traffic.

Last verified: 19 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.