JSTGTECH
← Back to blog

Service spotlight: cheap DNS-level failover with Route 53 health checks

3 min read

Multi-region failover has a reputation for requiring a global load balancer, cross-region routing infrastructure, and a meaningful engineering lift. For a lot of workloads — a static site with a backup origin, an API with a standby region, anything where “route traffic away from the broken endpoint” is the whole requirement — Route 53 health checks and failover routing get you most of the way there with nothing more than DNS records.

What it actually is

A Route 53 health check polls an endpoint (HTTP, HTTPS, or TCP) on an interval (default 30 seconds, or 10 seconds for the “fast” option) from a distributed set of AWS health checker locations worldwide, and marks the endpoint healthy or unhealthy based on a configurable failure threshold — requiring multiple consecutive failures across multiple checker locations before flipping status, which avoids a single flaky network path in one region triggering an unnecessary failover.

Failover routing policy then ties DNS answers to that health check status: you create a primary record pointing at your main endpoint and associate it with the health check, and a secondary record pointing at a backup endpoint. While the primary’s health check passes, Route 53 answers DNS queries with the primary record. The moment the health check fails, Route 53 stops returning the primary record and starts answering with the secondary — no load balancer, no application-level failover logic, just DNS resolving to a different answer once the health check trips.

Where it earns its keep

  • Static or largely static sites with a backup origin. A CloudFront distribution normally in front of an S3 bucket, with a health check on the S3 origin and a failover record pointing at a backup S3 bucket in another region (or even a “we’re down” static page hosted elsewhere) — cheap insurance against a regional S3 outage with no compute involved.
  • API failover across regions without a global load balancer. For workloads where eventual consistency of DNS propagation is acceptable (see the TTL caveat below), pointing a primary record at a region-A API Gateway/ALB and a secondary at region B, health-checked on each, is meaningfully simpler to set up and reason about than Global Accelerator or a multi-region Application Load Balancer setup, if anycast-level failover speed isn’t required.
  • Health checks that inspect more than “is it up.” A health check can match on a specific string in the response body, not just a 200 status — useful for catching an endpoint that’s returning 200 with a degraded/error payload, which a naive load balancer health check sometimes misses.
  • Composable with other routing policies. Failover pairs with weighted, latency-based, and geolocation routing at the record level (e.g., latency-based routing across regions, each of which has its own failover pair underneath), so you’re not limited to a single global primary/secondary if the topology is more complex.

The catch: DNS TTL and caching

DNS failover is only as fast as clients actually re-resolve the record. A record with a 300-second TTL means some fraction of clients — and, more unpredictably, any resolver or client that doesn’t strictly honor TTL — keep hitting the now-dead primary for up to that TTL after failover triggers, sometimes longer with misbehaving caching resolvers. Set a low TTL (30-60 seconds) on records used for failover well before you need it — TTL changes themselves take time to propagate, since resolvers that already cached the old TTL keep using it until their current cache entry expires, so this isn’t something you can fix in the moment of an actual outage.

Health check evaluation itself also isn’t instant: with the default 30-second interval and default failure threshold, detecting an outage and flipping DNS can take on the order of a minute or two end to end, which is well short of what many RTO targets actually need for a fully automated failover — model that latency into your DR plan rather than assuming “we have failover configured” means “we have sub-minute RTO.”

A practical tip

Create a calculated health check (one that aggregates the status of several child health checks with AND/OR/NOT logic) when “healthy” means more than one endpoint being reachable — e.g., requiring both the API and its database dependency’s health check to pass before Route 53 considers the primary healthy, instead of failing over on a symptom while the actual root cause goes undetected.

Related posts