How to do it...

  1. Go ahead and create a new CloudFormation template. We'll add some Parameters for the items we've mentioned previously:
      Parameters: 
DomainName:
Description: Your domain name (example.org)
Type: String
LoadBalancerDNSNameRegionA:
Description: The DNS name of your ELB in region A
Type: String
LoadBalancerHostedZoneRegionA:
Description: The Hosted Zone ID of your ELB in region A
Type: String
LoadBalancerDNSNameRegionB:
Description: The DNS name of your ELB in region B
Type: String
LoadBalancerHostedZoneRegionB:
Description: The Hosted Zone ID of your ELB in region B
Type: String
  1. The first Resource we want is the HostedZone resource for our domain name. Add it to your template as follows:
      Resources: 
DNSHostedZone:
Type: AWS::Route53::HostedZone
Properties:
Name: !Ref DomainName
  1. In order to have failover happen automatically, we're going to need to set up some health checks. We want health checks on the ELBs in both regions:
        RegionAHealthCheck: 
Type: AWS::Route53::HealthCheck
Properties:
HealthCheckConfig:
FailureThreshold: 3
FullyQualifiedDomainName: !Ref LoadBalancerDNSNameRegionA
Port: 80
RequestInterval: 30
ResourcePath: "/"
Type: HTTP
HealthCheckTags:
- { Key: Name, Value: Region A Health Check }
RegionBHealthCheck:
Type: AWS::Route53::HealthCheck
Properties:
HealthCheckConfig:
FailureThreshold: 3
FullyQualifiedDomainName: !Ref LoadBalancerDNSNameRegionB
Port: 80
RequestInterval: 30
ResourcePath: "/"
Type: HTTP
HealthCheckTags:
- { Key: Name, Value: Region B Health Check }
  1. We're now going to create four record sets for your domain:
    • a.<your-domain>-PRIMARY
    • b.<your-domain>-PRIMARY
    • a.<your-domain>-SECONDARY (failover to b)
    • b.<your-domain>-SECONDARY (failover to a)
  1. These records correspond to ELB A and ELB B (or site A and B, if that term makes more sense to you), and they will allow each region to fail over to the other if the health check fails.
  2. Let's start with the primary records for both ELBs:
        RegionAPrimary: 
Type: AWS::Route53::RecordSet
Properties:
Name: !Join [ ., [ a, Ref: DomainName ] ]
Type: A
HostedZoneId: !Ref DNSHostedZone
AliasTarget:
HostedZoneId: !Ref LoadBalancerHostedZoneRegionA
DNSName: !Ref LoadBalancerDNSNameRegionA
Failover: PRIMARY
SetIdentifier: primary-region-a
HealthCheckId: !Ref RegionAHealthCheck
RegionBPrimary:
Type: AWS::Route53::RecordSet
Properties:
Name: !Join [ ., [ b, Ref: DomainName ] ]
Type: A
HostedZoneId: !Ref DNSHostedZone
AliasTarget:
HostedZoneId: !Ref LoadBalancerHostedZoneRegionB
DNSName: !Ref LoadBalancerDNSNameRegionB
Failover: PRIMARY
SetIdentifier: primary-region-b
HealthCheckId: !Ref RegionBHealthCheck
  1. Now add the secondary (failover) records:
        RegionAFailover: 
Type: AWS::Route53::RecordSet
Properties:
Name: !Join [ ., [ a, Ref: DomainName ] ]
Type: A
HostedZoneId: !Ref DNSHostedZone
AliasTarget:
HostedZoneId: !Ref LoadBalancerHostedZoneRegionB
DNSName: !Ref LoadBalancerDNSNameRegionB
Failover: SECONDARY
SetIdentifier: secondary-region-a
RegionBFailover:
Type: AWS::Route53::RecordSet
Properties:
Name: !Join [ ., [ b, Ref: DomainName ] ]
Type: A
HostedZoneId: !Ref DNSHostedZone
AliasTarget:
HostedZoneId: !Ref LoadBalancerHostedZoneRegionA
DNSName: !Ref LoadBalancerDNSNameRegionA
Failover: SECONDARY
SetIdentifier: secondary-region-b
  1. Now we're going to add the root/apex record for our domain. For the purposes of this recipe, we're going to send requests originating from North America to region/ELB A, and requests from the rest of the world to region/ELB B:
        NorthAmericaGeolocation: 
Type: AWS::Route53::RecordSet
Properties:
Name: !Ref DomainName
Type: A
HostedZoneId: !Ref DNSHostedZone
AliasTarget:
HostedZoneId: !Ref DNSHostedZone
DNSName: !Join [ ., [ a, Ref: DomainName ] ]
GeoLocation:
ContinentCode: NA # North America
SetIdentifier: geolocation-region-a
RestOfWorldGeolocation:
Type: AWS::Route53::RecordSet
Properties:
Name: !Ref DomainName
Type: A
HostedZoneId: !Ref DNSHostedZone
AliasTarget:
HostedZoneId: !Ref DNSHostedZone
DNSName: !Join [ ., [ b, Ref: DomainName ] ]
GeoLocation:
CountryCode: "*" # Rest of world
SetIdentifier: geolocation-region-b
  1. That's it! You can now run this CloudFormation template in the AWS web console or via the CLI, as follows:
      aws cloudformation create-stack \
--stack-name geolocation-failover \
--template-body file://07-routing-based-on-location.yaml \
--parameters \
ParameterKey=DomainName,ParameterValue=gitrepository.com \
ParameterKey=LoadBalancerDNSNameRegionA,ParameterValue=<elb-a> \
ParameterKey=LoadBalancerHostedZoneRegionA, \
ParameterValue=<elb-zoneid-a> \

ParameterKey=LoadBalancerDNSNameRegionB,ParameterValue=<elb-b> \
ParameterKey=LoadBalancerHostedZoneRegionB, \
ParameterValue=<elb-zoneid-b>