Putting an AWS Service on a DNS domain apex
Co-authors: Aled Sage and Richard Downer
When your website runs in AWS, configuring your DNS zone apex record (sometimes called “naked domain”) can be a pain because it needs static IPs. There are a few options including switching to AWS Route 53 for DNS and using AWS Global Accelerator.
In more plain english, if your website is hosted in AWS (or another Cloud provider) at https://www.example.com, it can sometimes be painful to get https://example.com to also work. There are a few solutions but these vary depending on if you’re using an Application Load Balancer (ALB), classic Elastic Load Balancer (ELB), S3 bucket, CloudFront distribution, and/or Route 53.
Let’s explain some of the terminology, unpack that, and go through possible solutions.
DNS (domain name system) is how computers translate readily memorized domain names to the numerical IP addresses, e.g. example.com translates to 184.108.40.206. DNS can also do lots of other impressive things!
DNS records (sometimes called resource records or RR) say what those translations should be. An A record simply translates from a domain name to IPv4 address(es). A CNAME record is an alias - the domain name translates to another domain name.
A zone is a distinct, contiguous portion of the domain name space that has a single manager. A zone has a domain name (e.g. example.com), some administrative data, and a set of records for names within the zone. There can be multiple records with the same name - for example, to allow an IPv4 address and an IPv6 address (which are different types of record) to be on the same name.
The apex (sometimes known as the zone apex or domain apex) refers to records where the record name is the same as the zone’s domain name. In the zone for example.com, a record for example.com is said to be at the zone apex. In contrast, www.example.com is not at the apex. Often we want https://example.com to redirect to https://www.example.com. However, many DNS providers require that the apex is a DNS A-Record.
A static IP is one that doesn’t change - it always points at the same underlying logical resource. In contrast, the IP address behind some websites will change. That’s normally fine because DNS records have a “time to live” (TTL), which means computers should look up the address again.
A problem many will face is that DNS providers require that the apex does not have a CNAME record. This is a rule in the DNS specifications - RFC 1034, and clarifications in RFC 2181 - which requires that if a name in DNS has a CNAME record, that name cannot have any other records. Since it is also required that the zone apex has special records with the zone metadata, it follows that a CNAME record should never be applied to the zone apex.
Many AWS Services don’t have static IPs (this helps them to be incredibly elastic and fault-tolerant). Instead, they have a domain name that you use. For example, you might have an Application Load Balancer with a hostname of my-load-balancer-1234567890.eu-west1.elb.amazonaws.com.
To make that easier and safer for end-users to access, you’d configure www.example.com to be a CNAME for that long name. However, for the Apex record example.com, we’re in trouble - according to the rules above, we are not allowed to define a CNAME record here. Instead we’d need to provide an A record with an IPv4 address - and to do that we need to know the IP addresses that AWS has assigned to the service.
Anti-pattern: look up the service’s IP address(es) and copy those into an A Record
Before talking about solutions, a big warning about trying to look up the service’s IP addresses yourself.
AWS specifically advise against this approach for many of its managed services (there are some exceptions, which are described later). While this may appear to work, at least in the short term, there are a number of huge problems with this approach (number 1 is the absolute killer, but you may find the others interesting as well):
- The IP addresses are not guaranteed to remain stable. They may change at any time, causing an outage on your website!
- Services like elastic load balancer (ELB) will scale in response to demand, but doing this may require that AWS add new IP addresses or move your service to a different IP address. By hard-coding IP addresses, you cannot take full advantage of the ELB auto scaling, and you may overload the ELB address(es) that you have hard-coded.
- There may be multiple IP addresses in rotation. If you query the DNS server you may only get a subset of the IP addresses that handle your service.
- AWS may present different IP addresses in different circumstances. If you copy the IP address from a single location you may be giving your end users a sub-optimal IP address.
There are a few different solutions for this, outlined below.
Use AWS Route 53
The simplest solution is to use AWS Route 53 for your DNS with an Alias record. Note this does not require transfering the domain registration to Amazon Route 53. The domain registrar and the zone DNS hosting are two distinct and separate functions.
Route 53 offers the great feature of Alias records - this feels like a CNAME when you’re creating it (because it’s an alias), but when someone does a DNS lookup it behaves like an A Record (i.e. it returns the IP addresses rather than than the alias). For the Apex record example.com, we can use an Alias record.
Pricing for Route 53 is $0.50 per hosted zone per month and $0.40 per million queries.
But sometimes using Route 53 is just not practical. For example, we have customers who host websites on behalf of 100s of their customers - they can’t ask all their customers to use Route 53.
Use a DNS provider that supports “CNAME flattening”
Some DNS providers, such as CloudFlare, support “CNAME flattening” from zone apexes. Their service will regularly query the CNAME target and convert it into A records at the zone apex. The effect is similar to Route 53’s Alias records.
Ignore the Problem!
Do you really need the redirect? Could you live with end-users having to include the www? All links and google searches will work perfectly - it just affects existing links to the apex and affects people who type the URL into the address bar.
For some it’s essential (e.g. if the site was previously hosted at the apex, then links must continue to work and continuity is important for SEO). For others, it is to avoid risk of confusing/annoying end-users (pretty much all big sites do the redirect, so it has become the expected behaviour).
Use AWS Global Accelerator
AWS Global Accelerator is a relatively simple way to get two static IPs in front of your service, which you can then use in your A Record. The endpoints behind it can be any of Application Load Balancers, Network Load Balancers, EC2 instances, and Elastic IP addresses.
The Global Accelerator thus works for use-cases where your website runs on VMs or containers, such as hosting your own Wordpress, Magento, Drupal, etc.
However, (at time of writing) the AWS Global Accelerator cannot be put in front of CloudFront or an S3 website, nor in front of a classic ELB. This rules it out for such scenarios (a common use-case is to have a website’s static content in S3 behind CloudFront).
It also unfortunately rules out use of CloudFront in front of your Application Load Balancer for CDN caching. One way around that is to use the Global Accelerator for the apex (e.g. https://example.com) which then does a simple redirect (e.g. to https://www.example.com). The latter can then be served via CloudFront.
Pricing for the Global Accelerator is $0.025 per hour per Global Accelerator and about $0.015 per GB (depending on the source region). You also still have to pay for your EC2 Data Transfer Out (normally $0.09 per GB).
Global Accelerators give other big benefits (e.g. acceleration - the anycast IPs mean end-users connect to the nearest edge location so traffic is routed over the fast and reliable AWS network). They can also do a whole lot more (e.g. improving reliability by routing to different endpoints based on health, client location, and other policies that you configure). For more impartial information, including a comparison with CloudFront, see this Cloudonaut blog.
Use a different service for the apex redirect
You could host your apex site (e.g. https://example.com) using a different service/technology that has a static IP. Its responsibility would be to just give you a static IP and to return a 301 response code that redirects to https://www.example.com. Obviously, it would need to do this with a valid SSL certificate
However, it is a pain to set this up yourself to be high-availability (HA)! You could have a tiny VM with an elastic IP, but that is a single-point-of-failure. Making that HA would require some kind of load balancer in front (an AWS Network Load Balancer would still give you static IPs). If you care about DDoS then things will get even more complicated and harder to operate.
Use a Network Load Balancer
Network Load Balancers - NLBs - can use Elastic IP addresses. This gives you the option of having static IP addresses, so you can put A records at your domain apex.
However NLBs are complex and behave differently to the HTTP-based Application and Classic load balancers. Unless you already have a compelling case for using an NLB, you are probably better off with another solution
One could use an NLB in front of an Application Load Balancer (see this AWS blog). However, that is surprisingly complicated to implement and again you’re probably better off with another solution.
About the authors
Aled Sage is VP of Engineering and Richard Downer is a Principal Engineer at Cloudsoft, an AWS Advanced Consulting Partner and AWS Well-Architected partner. We love helping customers migrate to and use AWS. We find doing Well-Architected reviews is a great way to deep-dive into all aspects of your application architecture, best practices and concrete recommendations.