How to Set Up Multi-Region AWS Failover With Route 53
When your primary region goes down, DNS still points at it - so the site goes down too. AWS Route 53 failover fixes that with two A records sharing one name: a PRIMARY tied to a health check and a SECONDARY standby. When the health check crosses its failure_threshold of 3, Route 53 stops resolving to primary and serves secondary instead - no human at 3am.
Why single-region DNS is a single point of failure
A static site can be deployed in two regions - us-east-1 as primary,
us-west-2 as standby - but if the Route 53 record only points at the
primary, a region-wide outage takes the site down with it. The standby
is running and healthy; DNS just never sends anyone to it. Failover
routing closes that gap: Route 53 monitors the primary with a health
check and, when it fails, resolves the same DNS name to the secondary.
The whole thing is four Terraform resources plus an output. Below, the provider and both regional S3 buckets already exist - you add the DNS layer.
Step 1 - the hosted zone and health check
The zone is your authoritative DNS for the domain. The health check is what Route 53 polls to decide whether primary is alive.
resource "aws_route53_zone" "main" {
name = "example.com"
}
resource "aws_route53_health_check" "primary" {
type = "HTTP"
fqdn = "primary.example.com"
port = 80
resource_path = "/"
request_interval = 30
failure_threshold = 3
}
The health check hits http://primary.example.com:80/ every 30 seconds.
Three consecutive failures (failure_threshold = 3) mark the endpoint
unhealthy - roughly a 90-second window before Route 53 acts.
Step 2 - the PRIMARY and SECONDARY records
Both records share the same name (www.example.com) and type (A). What
distinguishes them is the failover_routing_policy block and a unique
set_identifier. The PRIMARY record references the health check; the
SECONDARY does not.
resource "aws_route53_record" "primary" {
zone_id = aws_route53_zone.main.zone_id
name = "www.example.com"
type = "A"
ttl = 60
records = ["1.2.3.4"]
set_identifier = "primary"
failover_routing_policy {
type = "PRIMARY"
}
health_check_id = aws_route53_health_check.primary.id
}
resource "aws_route53_record" "secondary" {
zone_id = aws_route53_zone.main.zone_id
name = "www.example.com"
type = "A"
ttl = 60
records = ["5.6.7.8"]
set_identifier = "secondary"
failover_routing_policy {
type = "SECONDARY"
}
}
output "zone_id" {
value = aws_route53_zone.main.zone_id
}
Two rules make this work: the records must share the same DNS name
(otherwise they are unrelated records, not a failover pair), and only the
PRIMARY carries health_check_id. While the health check passes, Route 53
answers with 1.2.3.4; once it fails, it answers with 5.6.7.8.
Step 3 - apply and verify
cd /workspace
terraform apply -auto-approve
aws route53 list-hosted-zones
aws route53 list-health-checks
aws route53 list-resource-record-sets \
--hosted-zone-id $(terraform output -raw zone_id)
The record set output should show both entries under www.example.com,
one with "Failover": "PRIMARY" and one with "Failover": "SECONDARY".
That is the proof the pair is wired correctly.
A low ttl (60 here) matters: resolvers cache the answer for the TTL, so
a long TTL slows real-world cutover even after Route 53 has switched. Keep
it short for failover records.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Declaring a Route 53 hosted zone and an HTTP health check in Terraform
- Building a PRIMARY/SECONDARY failover record pair that shares one DNS name
- Verifying failover routing with aws route53 list-resource-record-sets
FAQ
How does Route 53 failover routing work?
You create two records with the same name and type but different set_identifiers and a failover_routing_policy - one PRIMARY, one SECONDARY. The PRIMARY references a health check; while that check passes Route 53 resolves to it, and when the check fails it resolves to the SECONDARY instead.
How do I set up multi-region failover with Route 53 and Terraform?
Declare an aws_route53_zone, an aws_route53_health_check against your primary endpoint, then two aws_route53_record resources sharing one name: the PRIMARY with failover_routing_policy type PRIMARY and health_check_id set, and the SECONDARY with type SECONDARY. Apply with terraform apply -auto-approve.
Why must the primary and secondary Route 53 records have the same name?
Failover routing is a decision between records that answer the same query. If the PRIMARY and SECONDARY have different names they are unrelated records and Route 53 has nothing to fail over between - the pair must share the same DNS name and type.
How long does Route 53 take to fail over to the secondary region?
It depends on the health check request_interval and failure_threshold plus the record TTL. With a 30-second interval and a threshold of 3, Route 53 marks the endpoint unhealthy after about 90 seconds; resolvers then pick up the new answer once the cached TTL expires.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →