DEV Community

Cover image for Multi-Region VNet Peering + Global Load Balancer on Azure, A Step-by-Step Guide
Ipadeola Taiwo
Ipadeola Taiwo

Posted on

Multi-Region VNet Peering + Global Load Balancer on Azure, A Step-by-Step Guide

What We're Building

A Nigerian fintech has two offices, Lagos and Abuja and wants:

  1. Both offices on the same private network, even though they sit in different parts of the world
  2. A web app running on a server in each office
  3. Traffic automatically routed to whichever office is closest to the user, with automatic failover if one office's server goes down

To simulate this on Azure, Lagos lives in East US and Abuja lives in South Africa North two genuinely different Azure regions, connected privately, with a global load balancer deciding where to send traffic.

By the end of this guide, you'll have a working multi-region setup you can test from your own terminal.

What you'll need

  • An Azure account (the free tier works fine)
  • Basic comfort with the Azure Portal
  • A terminal that can run ssh and curl (Git Bash, macOS/Linux terminal, or Cloud Shell)

Step 1: Create a Resource Group

A resource group is just a logical folder that holds everything we build, so it's easy to manage or delete later as one unit.

  1. In the Azure Portal, search "Resource groups"+ Create
  2. Resource group name: fintech-rg
  3. Region: pick any region for the resource group itself, it doesn't have to match the resources inside it
  4. Review + CreateCreate


Step 2: Create Two Virtual Networks (VNets)

A VNet is a private network inside Azure. We need one for each branch office, in two different regions.

VNet for Lagos (East US)

  1. Search "Virtual networks"+ Create
  2. Resource group: fintech-rg
  3. Name: lagos-vnet
  4. Region: East US
  5. Leave the default address space and subnet, or customize if you prefer
  6. Review + CreateCreate

VNet for Abuja (South Africa North)

Repeat the same steps:

  1. Name: abuja-vnet
  2. Region: South Africa North
  3. Review + CreateCreate


Step 3: Peer the Two VNets Together

VNet Peering connects the two networks so resources inside them can talk to each other using private IP addresses, as if they were on the same local network, no public internet involved.

Peering needs to be set up from both sides once from Lagos's VNet pointing to Abuja, and once from Abuja's VNet pointing to Lagos.

From the Lagos VNet

  1. Open lagos-vnet → left menu → Peerings+ Add
  2. This virtual network:
    • Peering link name: lagos-to-abuja
    • Allow traffic to remote virtual network: ✅ enabled
  3. Remote virtual network:
    • Peering link name: abuja-to-lagos
    • Virtual network: select abuja-vnet
    • Allow traffic to remote virtual network: ✅ enabled
  4. Add

This single step actually creates both sides of the peering at once.

Confirm the Peering Is Connected

  1. Go back to lagos-vnetPeerings
  2. You should see the peering listed with status: Connected
  3. Check abuja-vnetPeerings too — it should show Connected from its side as well


Step 4: Create a VM in Each VNet

VM for Lagos

  1. Search "Virtual machines"+ Create
  2. Resource group: fintech-rg
  3. VM name: lagos-vm
  4. Region: East US
  5. Image: Ubuntu Server (any recent LTS version)
  6. Size: the default/smallest size is fine for this project
  7. Authentication: SSH public key (recommended) or password
  8. Username: lagosvm (or whatever username you prefer, just stay consistent for the rest of the guide)
  9. Networking tab: Virtual network → select lagos-vnet
  10. Review + CreateCreate

VM for Abuja

Repeat with:

  1. VM name: abuja-vm
  2. Region: South Africa North
  3. Username: abujavm
  4. Virtual network: abuja-vnet

Once both VMs are created, note down:

  • Each VM's public IP (used to SSH in)
  • Each VM's private IP (used for the ping test later)

In this guide, the private IPs are:

  • Lagos VM private IP: 10.0.0.4
  • Abuja VM private IP: 10.1.0.4

(Yours may be different — always use the actual IP shown in your VM's Overview or Networking tab.)


Step 5: Secure SSH Access and Connect to Each VM

If you're using an SSH key pair, make sure your private key file has the correct permissions before connecting, otherwise SSH will refuse to use it:

chmod 700 lagosvm_key.pem
Enter fullscreen mode Exit fullscreen mode

(Do the same for the Abuja key if you're using a separate one.)

Connect to the Lagos VM:

ssh -i lagosvm_key.pem lagosvm@<lagos-vm-public-ip>
Enter fullscreen mode Exit fullscreen mode

Connect to the Abuja VM in a separate terminal tab:

ssh -i abujavm_key.pem abujavm@<abuja-vm-public-ip>
Enter fullscreen mode Exit fullscreen mode


Step 6: Install and Start a Web Server on Each VM

Run this on both VMs:

sudo apt update && sudo apt upgrade -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo systemctl enable apache2
Enter fullscreen mode Exit fullscreen mode
  • apt update && upgrade refreshes the package list and applies any pending updates
  • apache2 is the web server that will respond to HTTP requests
  • enable makes sure Apache automatically restarts if the VM ever reboots

Confirm Apache is running on each VM:

sudo systemctl status apache2
Enter fullscreen mode Exit fullscreen mode

You should see active (running) in green.


Step 7: Test the Private Network Connection (Ping Test)

This is the moment that proves the VNet peering actually works — two VMs, in two different regions, reaching each other over a private connection.

From the Lagos VM, ping Abuja's private IP:

ping 10.1.0.4
Enter fullscreen mode Exit fullscreen mode

From the Abuja VM, ping Lagos's private IP:

ping 10.0.0.4
Enter fullscreen mode Exit fullscreen mode

If peering is working correctly, you'll see successful replies on both sides, something like:

64 bytes from 10.1.0.4: icmp_seq=1 ttl=64 time=142 ms
Enter fullscreen mode Exit fullscreen mode

Press Ctrl + C to stop the ping.

⚠️ Note: If you don't get replies, double check that each VM's Network Security Group (NSG) allows inbound traffic from the peered VNet (the default AllowVnetInBound rule usually covers this automatically).


Step 8: Customize Each Web Page So You Can Tell Them Apart

To visually confirm which server is responding later (especially once the load balancer is involved), give each VM a distinct homepage.

On the Lagos VM:

echo "<h1>Hello from Lagos Server</h1>" | sudo tee /var/www/html/index.html
Enter fullscreen mode Exit fullscreen mode

On the Abuja VM:

echo "<h1>Hello from Abuja Server</h1>" | sudo tee /var/www/html/index.html
Enter fullscreen mode Exit fullscreen mode

Test it directly using each VM's public IP in a browser:

http://<lagos-vm-public-ip>
http://<abuja-vm-public-ip>
Enter fullscreen mode Exit fullscreen mode

You should see the matching "Hello from..." message for each one.


Step 9: Open Port 80 on Both VMs

Apache runs on port 80, so each VM's NSG needs to allow inbound HTTP traffic — otherwise external requests (including from the load balancer) won't be able to reach it.

  1. Open each VM → Networking tab → Add inbound port rule
  2. Settings:
    • Destination port: 80
    • Protocol: TCP
    • Action: Allow
    • Give the rule a name (anything descriptive works, e.g. Allow-HTTP)
  3. Add
  4. Repeat for the other VM

Step 10: Create the Regional Load Balancer for Lagos

Since Lagos and Abuja are in different regions, we can't use one single load balancer to cover both — a standard Azure Load Balancer only operates within a single region. We need one regional load balancer per region, and later, a Global Load Balancer sitting on top of both.

10.1 — Create the Public IP

  1. Search "Public IP addresses"+ Create
  2. Give it a name (e.g. lagos-lb-ip)
  3. SKU: Standard
  4. Tier: Regional
  5. Region: East US
  6. Assignment: Static
  7. Review + CreateCreate

10.2 — Create the Load Balancer

  1. Search "Load balancers"+ Create
  2. Give it a name (e.g. lagos-lb)
  3. Region: East US
  4. SKU: Standard
  5. Type: Public
  6. Tier: Regional
  7. Frontend IP configuration: add a frontend IP, give it a name, and select the public IP you just created (lagos-lb-ip) — this becomes your regional frontend IP, in this guide 20.121.242.74
  8. Skip backend pools and rules for now — we'll add them after creation for a cleaner setup
  9. Review + CreateCreate

10.3 — Add the Backend Pool

  1. Open your Lagos load balancer → Backend pools+ Add
  2. Give it a name
  3. Virtual network: select lagos-vnet
  4. Backend pool configuration: NIC
  5. Click + Add under the IP configurations table → select lagos-vm
  6. Save

10.4 — Add a Health Probe

  1. Health probes+ Add
  2. Give it a name
  3. Protocol: HTTP
  4. Port: 80
  5. Path: /
  6. Interval: 5–15 seconds
  7. Add

10.5 — Add the Load Balancing Rule

  1. Load balancing rules+ Add
  2. Give it a name
  3. Frontend IP: select the frontend IP you created
  4. Backend pool: select the backend pool you created
  5. Health probe: select the probe you created
  6. Protocol: TCP, Port: 80, Backend port: 80
  7. Add

10.6 — Test the Lagos Load Balancer

From your terminal:

curl http://20.121.242.74
Enter fullscreen mode Exit fullscreen mode

(replace with your actual Lagos load balancer frontend IP)

You should see the "Hello from Lagos Server" response.


Step 11: Create the Regional Load Balancer for Abuja

Repeat all of Step 10, but for the Abuja region:

  • Public IP: give it a name, Region: South Africa North → in this guide, the resulting frontend IP is 20.87.39.70
  • Load Balancer: give it a name, Region: South Africa North
  • Backend pool: Virtual network → abuja-vnet, add abuja-vm
  • Health probe and rule: same settings as before (HTTP/80//, TCP/80→80)

Test it:

curl http://20.87.39.70
Enter fullscreen mode Exit fullscreen mode

You should see "Hello from Abuja Server."

⚠️ Important: Don't move to the next step until both regional load balancers pass this test independently. The Global Load Balancer depends on both of these already working correctly.


Step 12: Create the Global Load Balancer

The Global Load Balancer sits above both regional load balancers and decides which region to send each user's request to, based on which one is geographically closest and healthy.

12.1 — Create the Global Public IP

  1. Search "Public IP addresses"+ Create
  2. Give it a name (e.g. global-lb-ip)
  3. SKU: Standard
  4. Tier: Global
  5. Region: must be one of Azure's supported home regions for global resources, examples include East US 2, West Europe, Southeast Asia, West US, North Europe, Central US
  6. Assignment: Static
  7. Review + CreateCreate

In this guide, the resulting global IP is 20.15.1.61.

12.2 — Create the Global Load Balancer

  1. Search "Load balancers"+ Create
  2. Give it a name (e.g. global-lb)
  3. Region: the same home region you used for the global IP (e.g. East US 2)
  4. SKU: Standard
  5. Tier: Global ⚠️ this is the setting that matters most here — don't select Regional
  6. Frontend IP configuration: add a frontend IP, give it a name, and select your global-lb-ip
  7. Skip backend pools and rules in the wizard
  8. Review + CreateCreate

12.3 — Add the Backend Pool

  1. Open your Global load balancer → Backend pools+ Add
  2. Give it a name
  3. Under the configuration table, click + Add
  4. Type: Load Balancer (not NIC, not IP address)
  5. Add your Lagos load balancer
  6. Click + Add again and add your Abuja load balancer
  7. Confirm both regional load balancers now appear in the table
  8. Save

12.4 — Add the Load Balancing Rule

  1. Load balancing rules+ Add
  2. Give it a name
  3. Frontend IP: your global frontend IP
  4. Backend pool: your global backend pool
  5. Protocol: TCP, Port: 80, Backend port: 80

The backend port here must match the frontend port used in both regional load balancer rules — in this case, both use port 80, so we're consistent.

  1. Add

Step 13: Test the Global Load Balancer

curl http://20.15.1.61
Enter fullscreen mode Exit fullscreen mode

(replace with your actual global load balancer IP)

You should get back a response from whichever region is closest to you, for example, "Hello from Lagos Server."

This is expected behavior: the Global Load Balancer uses geo-proximity routing, not round robin. It always routes you to the closest healthy region, not a random alternating split.


Step 14: Test Automatic Failover

To prove the system can actually fail over between regions, we'll simulate one region going down.

SSH into the Lagos VM and stop Apache:

sudo systemctl stop apache2
Enter fullscreen mode Exit fullscreen mode

Now curl the global load balancer again:

curl http://20.15.1.61
Enter fullscreen mode Exit fullscreen mode

This time, the response should switch to "Hello from Abuja Server" Azure detected that the Lagos region's health probe failed, removed it from rotation, and automatically routed traffic to the healthy Abuja region instead.

Once you're done testing, restart Apache on the Lagos VM so it's back in rotation:

sudo systemctl start apache2
Enter fullscreen mode Exit fullscreen mode

Recap: What We Actually Built

Client
  ↓
Global Load Balancer (home region, e.g. East US 2)
  ↓                              ↓
Regional LB - Lagos          Regional LB - Abuja
(East US)                    (South Africa North)
  ↓                              ↓
lagos-vm                     abuja-vm
  ↳ peered privately with abuja-vm via VNet Peering
Enter fullscreen mode Exit fullscreen mode

This setup demonstrates three real-world cloud concepts at once:

  • Private cross-region connectivity (VNet Peering)
  • Regional high availability (each region's own load balancer and health probe)
  • Global resilience and failover (the Global Load Balancer routing around an unhealthy region automatically)

If you build this yourself, try the failover test a few times — watching traffic automatically reroute in real time is genuinely satisfying, and it's the same underlying pattern real fintechs use to stay online across regions.

Got stuck somewhere or have a question about a specific step? Drop a comment below 👇

Top comments (0)