
August 29, 2026
14 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
When your application runs in more than one cloud—or more than one region—a regional load balancer inside AWS or Azure is not enough. Users in Kathmandu, London, and Sydney all hit the same hostname, and something upstream must decide which cloud and which region gets the request. That upstream layer is global load balancing across cloud providers: DNS-based routing, anycast edge networks, health checks, and failover rules that span AWS, Azure, GCP, or a mix of VPS providers. I've set up multi-region deployments for client projects where a single cloud outage would have taken the business offline; global load balancing is the mechanism that keeps traffic flowing. This guide walks through how it works, which patterns fit real budgets, and how to implement it without turning your ops stack into a science project. For broader context, see our multi-cloud architecture practical guide.
What is global load balancing across cloud providers?
Global server load balancing (GSLB) sits above regional load balancers. A regional Application Load Balancer on AWS, an Azure Application Gateway, or an Nginx instance on a Hetzner VPS handles traffic inside one datacenter footprint. GSLB answers a different question: which footprint should this user reach?
Three mechanisms dominate in 2026:
- DNS-based GSLB — Services like Amazon Route 53, Google Cloud DNS, Azure Traffic Manager, or Cloudflare Load Balancing return different IP addresses or CNAME targets based on policy (latency, geolocation, weighted round-robin, failover).
- Anycast edge routing — A CDN or edge network (Cloudflare, Akamai, Fastly, AWS CloudFront) advertises the same IP block from many PoPs; BGP sends the user to the nearest edge, which proxies to a healthy origin.
- Hybrid — Anycast CDN at the edge plus DNS failover to a secondary cloud when all origins behind the CDN fail.
On production Laravel applications I've maintained, the pattern is usually: Cloudflare or Route 53 at the DNS layer, regional Nginx or ALB behind it, and identical app releases deployed to each origin via GitLab CI and Deployer 7. The global layer does not run PHP; it only decides where the request lands.
How does global load balancing work across AWS, Azure, and GCP?
Each major cloud offers native GSLB primitives. You can mix them, but most teams pick one DNS authority and point it at origins in multiple clouds.
Amazon Route 53
Route 53 routing policies cover most multi-cloud cases:
- Latency-based routing — Returns the record set with lowest measured latency from the resolver's location.
- Geolocation routing — Sends users in Nepal to ap-south-1 (Mumbai), users in the EU to eu-west-1, and so on.
- Failover routing — Primary and secondary records; secondary activates when health checks fail.
- Weighted routing — Split traffic 70/30 during a migration or canary release.
Health checks can target HTTPS endpoints, TCP ports, or CloudWatch alarms. TTL on alias records can be as low as 60 seconds, though DNS caching at ISPs may stretch effective failover to a few minutes.
Azure Traffic Manager
Azure Traffic Manager is a DNS-based GSLB service (not a proxy). Profiles support priority, weighted, performance, geographic, and subnet routing. Point external endpoints at AWS ALB hostnames or bare IP addresses. Nested profiles let you combine geographic routing with failover inside a region group.
Google Cloud Load Balancing
Google's global external Application Load Balancer uses anycast IPs—one VIP announced from all Google edge locations. Multi-cloud setups typically use Cloud DNS with routing policies or place Cloud CDN in front of non-GCP origins via internet NEGs (network endpoint groups). For strict multi-cloud, Cloud DNS plus health-checked failover records is the more portable pattern.
Cloudflare Load Balancing
Cloudflare sits in a sweet spot for teams that want provider-agnostic GSLB without managing three different DNS APIs. Cloudflare proxies traffic through its anycast network, runs health monitors against each origin pool, and steers by geography or latency. I've used this approach on sites where Cloudflare CDN setup was already in place for caching and DDoS protection—adding load balancing is a natural extension. Pricing starts around USD 5/month per origin plus USD 0.50 per 500K queries; budget roughly Rs 700–2,000/month (~USD 5–15) for a small multi-origin setup.
Which global load balancing approach should you choose for multi-cloud?
Not every project needs five clouds and anycast. Match the pattern to traffic, budget, and operational capacity.
| Approach | Best for | Failover speed | Multi-cloud fit | Typical cost |
|---|---|---|---|---|
| DNS GSLB (Route 53, Azure TM, Cloud DNS) | Latency/geo routing, active-passive DR | 1–5 min (TTL + cache) | Excellent — vendor-neutral origins | USD 0.50–1/M queries |
| Anycast CDN proxy (Cloudflare, Fastly) | Static + dynamic at edge, DDoS protection | Seconds (health-based pool drain) | Excellent — origins anywhere | Rs 1,500–15,000/mo (~USD 11–110) |
| Cloud-native anycast LB (GCP GLB, AWS Global Accelerator) | Single-cloud multi-region first | Sub-minute | Poor alone — ties to one vendor's network | USD 18+/mo + data processing |
| Self-managed GSLB (NSD/PowerDNS + GeoIP) | Full control, large teams | Depends on TTL | Good — high ops burden | Infra + engineer time |
| Hybrid: CDN + DNS failover | Production SaaS, eCommerce | Seconds at edge; minutes for full cloud loss | Best practical balance | CDN plan + DNS health checks |
For a Nepal-based eCommerce store serving customers in South Asia and the Gulf—as I've seen on WooCommerce and Laravel projects—latency-based DNS to ap-south-1 (Mumbai) plus a weighted secondary on a Singapore or European VPS covers most cases without GCP and Azure both in the path. Reserve true multi-cloud active-active for revenue-critical systems where a single-provider outage has a documented business cost.
Compare hosting economics in our AWS vs DigitalOcean vs Hetzner for Laravel hosting breakdown before committing to three cloud bills.
How do you implement global load balancing across cloud providers step by step?
The following workflow assumes a Laravel 12 application on PHP 8.3, deployed to AWS ap-south-1 (primary) and a Hetzner VPS in Falkenstein (secondary), with Cloudflare as the global proxy. Adapt the same steps for Azure, GCP, or a second AWS region.
Step 1: Standardise origins
Both origins must serve identical code and compatible configuration. Use the same Git tag, the same .env keys (different values for region-specific settings), and a shared database strategy:
- Active-passive — Primary RDS in Mumbai; read replica or delayed standby on secondary. Failover promotes replica or restores from backup.
- Active-active (harder) — Multi-region MySQL/PostgreSQL with conflict-aware writes, or region-scoped data partitions. Most Laravel apps I work on are not ready for this on day one.
- Session handling — Store sessions in Redis (ElastiCache or self-hosted Redis 7.x) reachable from both origins, or use database sessions, or stateless Sanctum tokens for APIs.
Step 2: Expose a health endpoint
Global load balancers need a lightweight check that proves the app and its dependencies are alive:
// routes/web.php — Laravel 12
Route::get('/health', function () {
$checks = [
'db' => fn () => DB::connection()->getPdo() !== null,
'redis' => fn () => Cache::store('redis')->put('health', 1, 10),
];
foreach ($checks as $name => $fn) {
if (! $fn()) {
return response('fail: '.$name, 503);
}
}
return response('ok', 200);
}); Return 503 when any dependency fails. Do not cache this route at CDN. Keep the response body small and fast—under 50 ms on a warm PHP-FPM worker.
Step 3: Configure origin pools in Cloudflare
In the Cloudflare dashboard (or via Terraform), create a load balancer monitor and pool:
# cloudflare_load_balancer.tf (provider cloudflare ~> 4.x)
resource "cloudflare_load_balancer_monitor" "app" {
account_id = var.cloudflare_account_id
type = "https"
method = "GET"
path = "/health"
expected_codes = "200"
interval = 60
retries = 2
timeout = 5
}
resource "cloudflare_load_balancer_pool" "aws_primary" {
account_id = var.cloudflare_account_id
name = "aws-ap-south-1"
monitor = cloudflare_load_balancer_monitor.app.id
origins {
name = "aws-alb"
address = "primary-alb.ap-south-1.elb.amazonaws.com"
enabled = true
}
}
resource "cloudflare_load_balancer_pool" "hetzner_secondary" {
account_id = var.cloudflare_account_id
name = "hetzner-fsn1"
monitor = cloudflare_load_balancer_monitor.app.id
origins {
name = "hetzner-nginx"
address = "secondary.example.com"
enabled = true
}
}
resource "cloudflare_load_balancer" "app" {
zone_id = var.zone_id
name = "app.example.com"
fallback_pool_id = cloudflare_load_balancer_pool.hetzner_secondary.id
default_pool_ids = [cloudflare_load_balancer_pool.aws_primary.id]
steering_policy = "geo"
region_pools {
region = "SASIA"
pool_ids = [cloudflare_load_balancer_pool.aws_primary.id]
}
} Manage multi-cloud DNS and LB resources through Terraform as described in our manage multi-cloud state with Terraform guide. Use separate state files per cloud provider to limit blast radius.
Step 4: Add DNS failover as a safety net
Cloudflare handles edge failover quickly. Add Route 53 failover records pointing directly at origin IPs for the rare case the CDN itself is unreachable:
# route53_failover.tf
resource "aws_route53_health_check" "primary" {
fqdn = "app.example.com"
port = 443
type = "HTTPS"
resource_path = "/health"
failure_threshold = 3
request_interval = "30"
}
resource "aws_route53_record" "primary" {
zone_id = aws_route53_zone.main.zone_id
name = "direct.app.example.com"
type = "A"
set_identifier = "primary"
failover_routing_policy { type = "PRIMARY" }
health_check_id = aws_route53_health_check.primary.id
records = [var.aws_eip]
ttl = 60
} Document this hostname for emergency use. Do not expose it in normal user flows.
Step 5: Deploy identically to every origin
On projects using Deployer 7 and GitLab CI, the pipeline deploys the same release artefact to both targets:
- CI builds frontend assets with Vite 6.x and runs PHPUnit/Pest tests.
- Composer install with
--no-dev --optimize-autoloaderon PHP 8.3. - Deployer runs
dep deploy production-awsthendep deploy production-hetznersequentially. - Post-deploy:
php artisan config:cache,php artisan route:cache, PHP-FPM reload for opcache invalidation. - Smoke test
/healthon each origin before marking the pipeline green.
Step 6: Test failover deliberately
Schedule a quarterly game day. Block the primary origin in a firewall rule or stop PHP-FPM, confirm Cloudflare drains the pool within one monitor interval, and verify the secondary serves traffic. Log results. Pair this with the restore-testing practices in our backup and disaster recovery strategy article.
What are common mistakes when running global load balancing across cloud providers?
Global load balancing looks straightforward in a diagram. Production tells a different story. These failures show up repeatedly.
Treating DNS failover as instant
Even with TTL 60, resolvers cache records. Some ISPs ignore low TTLs. Budget 1–5 minutes for DNS-only failover. If you need sub-minute recovery, proxy through an anycast CDN that holds the DNS name and shifts pools internally—users never see the IP change.
Health checks that lie
A /health route that returns 200 without checking the database gives false confidence. I've debugged incidents where the load balancer kept sending traffic to an app that could render static pages but could not write orders. Check every dependency that blocks core workflows.
Session stickiness across regions
Default PHP file sessions break the moment a user's second request lands on another origin. Move sessions to Redis 7.x, use Laravel's database session driver, or go stateless for API-first apps with Sanctum bearer tokens. For Livewire or admin panels, sticky sessions at the CDN (Cloudflare cookie-based affinity) are a stopgap—not a substitute for shared session storage.
Split-brain databases
Active-active writes to two independent MySQL primaries without conflict resolution corrupts data. Active-passive with a promoted replica, or a managed multi-region database (Aurora Global, Azure Cosmos DB for specific workloads), or region-partitioned tenants are safer patterns. Read our multi-region deployment for global sites article for data-layer options before enabling weighted routing to two write-capable origins.
Ignoring SSL and origin certificates
Cloudflare and similar proxies need valid TLS on each origin. Use Let's Encrypt on every VPS, or ACM on AWS. Match TLS versions (TLS 1.2 minimum in 2026). Full (strict) SSL mode on Cloudflare validates the origin cert—do not use flexible SSL in production.
Operational drift between clouds
AWS runs PHP 8.4; Hetzner still on 8.2; one origin has an extra Nginx buffer tweak—the next deploy works on one side and 502s on the other. Pin PHP versions in Ansible playbooks or cloud-init scripts. Run the same HAProxy or Nginx load balancing config template on both origins where applicable.
Cost surprises
Cross-cloud data transfer is expensive. Replicating MySQL binlogs from AWS Mumbai to a Hetzner box in Germany adds egress charges on the AWS side (roughly USD 0.09/GB to internet). Keep DR replicas in the same region when possible, or use a provider with cheaper peering. Monitor with FinOps basics—unexpected cross-cloud bandwidth often exceeds the load balancer subscription fee.
How should you plan global load balancing for Nepal and South Asia traffic?
Latency from Kathmandu to ap-south-1 (Mumbai) is typically 30–60 ms; to eu-central-1 it is 180–250 ms. For a legal-tech portal or eCommerce checkout, that difference affects conversion. Route South Asia traffic to Mumbai or Singapore; keep a European or US origin purely for DR unless you have users there.
Nepal-specific constraints matter too: international payment gateways (eSewa, Khalti) callback to a fixed URL—ensure failover does not change the public hostname users and webhooks share. Use one stable app.example.com at the GSLB layer; never expose region-specific subdomains to payment providers unless each is registered separately.
Smaller teams in Nepal often run primary on a single AWS EC2 with RDS and keep a cold or warm standby on DigitalOcean or Hetzner costing Rs 3,000–8,000/month (~USD 22–59). That is enough for many B2B sites. Scale to active-active multi-cloud when uptime SLAs are contractual, not aspirational.
Ready to build resilient global load balancing across cloud providers?
Global load balancing across cloud providers is not about running on every cloud—it is about routing users to a healthy origin fast, with a data and session strategy that survives the switch. Start with identical deploys, a honest /health endpoint, one CDN or DNS GSLB provider, and a tested failover path to a secondary origin. Add complexity only when traffic, compliance, or SLA requirements demand it.
If you want help designing multi-region Laravel architecture, Cloudflare or Route 53 setup, and Deployer-based pipelines for production, get in touch or review our development services. I work with Nepal-based businesses and remote clients worldwide on infrastructure that stays up when a single cloud does not.

