- The
root domain
, akaapex domain
, is the naked domain (e.g., the root domain of https://www.example.com is example.com). - A CNAME cannot be placed at the root domain level.
- CNAME records must point to another domain name, not an IP address.
- CNAME records can point to other CNAME records, but this is not considered a good practice as it is inefficient.
- An
alias
is like a CNAME where the target is an AWS service (e.g., CloudFront, ELB, API Gateway). - When an
alias
is defined on theroot domain
, this is called anzone apex
(more about this topic in the Alias records section). hosted zone
is a container for DNS records. There are two types of hosted zones:public
: Stores DNS records to route traffic on the internet.private
: Stores DNS records to route traffic in your VPC.
- Can log DNS queries to CloudWatch (via a Log Group only in US East). Usefull for traffic analysis.
The DNS specification is quite old (1987) and its limitation created needs to innovate outside of the official standard. The main challenge of the standard specification is the inability to define a CNAME at the root domain (e.g., example.com pointing to anotherexample.com). The most popular solutions are proprietary:
- AWS Route 53's Alias: This is typically used to create a CNAME record with a root domain to an AWS service (e.g., CloudFront, ELB).
- Cloudflare's CNAME Flattening: https://blog.cloudflare.com/introducing-cname-flattening-rfc-compliant-cnames-at-a-domains-root/
The AWS documentation mentions that alias record can overcome the DNS specification limiting apex domain to A records only. When the alias is toggled on the apex domain, this A redord is not limited to Ipv4 or IPv6 and support the following URL types (making it worked as a CNAME):
- CloudFront URL
- S3 URL
- ELB URL
- Another record in the same hosted zone
Unfortunatelly, there is a big limitation on the last point (record in the same hosted zone). It only works if that record is NOT a CNAME. This means that it is not possible to configure a Route 53 apex domain to resolve to its www CNAME record which points to another domain. The alternative options are:
- Instead of configuring the Apex to resolve to www., configure www. to resolve to the Apex. This means that the Apex is configured using an Alias and that wwww. is configured as a standard CNAME record resolving to the Apex.
- If that other domain is a CloudFront distribution (even if that's one from another AWS account), you can simply point the apex domain to the CloudFront URL (e.g., 12345567.cloudfront.net) using the alias option as exlained in the next section Configuring custom domain on any CloudFront distribution.
- Create a new S3 bucket and configure it to redirect traffic. Then, configure the Alias using that S3 bucket.
- If the domain is not an AWS service, then you have no choice but configuring the APEX domain to point to a server that can perform a 301 redirect to the www CNAME record (e.g., CloudFront on an empty S3 bucket with forward rules).
- Backup the current DNS records:
dig +noall +answer +multiline YOURDOMAIN any > dns.backup.dns
Two components can be migrated:
Both of them can be migrated separately without causing an interuption of service. If the domain and the hosted zone are hosted in separate accounts, they will also have to be maintained in those separate accounts, which can lead to confusion. That's why I would recommend to migrate both in the same account.
- Setup your default AWS CLI profile to the account containing the domain.
- Get the account ID of the destinatin AWS Account.
- Run this command
aws route53domains transfer-domain-to-another-aws-account --region us-east-1 --domain-name <YOUR-DOMAIN> --account-id <YOUR-DESTINATION-ACCOUNT-ID>
- Save the response, which is similar to:
{
"OperationId": "9e75aaad-ef21-4b49-bd24-49eb3b15441a",
"Password": "1234567"
}
- When this is done, your new domain will appear in the destination account in the
Domains
section under thePending requests
link. The domain must be approved using the CLI. - Switch to the destination account in the AWS CLI profile.
- Test you are logged to the correct account:
aws sts get-caller-identity
- Run this command:
aws route53domains accept-domain-transfer-from-another-aws-account --region us-east-1 --domain-name <YOUR-DOMAIN> --password "<YOUR-PASSWORD>"
WARNING: The password may contain characters that must be escaped(i.e., add a
\
) to prevent your terminal to get confused. Those characters are:!
,`
.
NOTICE:
--region us-east-1
is required and hardcoded because Route 53 is a global service. Without this option, you'll receive aCould not connect to the endpoint URL: "https://route53domains.ap-southeast-2.amazonaws.com/"
error message.
WARNING: Do not delete the old hosted zone until you've confirmed the traffic is served by the new hosted zone. This means keeping the old hosted zone for at least 48 hours.
The workflow consists in steps:
- Connect to your AWS source account profile using the AWS CLI (tips: use
npx switch-profile
). - Import the records in a JSON file:
aws route53 list-resource-record-sets --hosted-zone-id <HOSTED ZONE ID> > YOUR-RECORDS.json
- Login to the AWS console for the account that hosts the new hosted zones and browse to
Route 53
. - Click on
Hosted zones
and then click on theCreate hosted zone
button. - Wrangle the
YOUR-RECORDS.json
obtained in step 2 and don't include theNS
andSOA
records as the new hosted zone uses it own. Be careful with alias(more details [here]https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-migrating.html#hosted-zones-migrating-edit-records). The output should be similar to this sample:
{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "cloudandbytes.com.",
"Type": "MX",
"TTL": 300,
"ResourceRecords": [
{
"Value": "1 ASPMX.L.GOOGLE.COM"
},
{
"Value": "5 ALT1.ASPMX.L.GOOGLE.COM"
},
{
"Value": "5 ALT2.ASPMX.L.GOOGLE.COM"
},
{
"Value": "10 ALT3.ASPMX.L.GOOGLE.COM"
},
{
"Value": "10 ALT4.ASPMX.L.GOOGLE.COM"
}
]
}
},
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "cloudandbytes.com.",
"Type": "TXT",
"TTL": 300,
"ResourceRecords": [
{
"Value": "\"v=spf1 include:_spf.google.com ~all\""
}
]
}
}
]
}
Trick, use this command to easily achieve the above outcome:
func() { node -e "console.log(JSON.stringify({ Changes:require('$1').ResourceRecordSets.filter(r => r.Type != 'NS' && r.Type != 'SOA').map(r => ({Action:'CREATE',ResourceRecordSet:r}))},null,' '))" > $2; };func <INPUT_PATH.json> <OUTPUT_PATH.json>
- Connect to your AWS target account profile using the AWS CLI (tips: use
npx switch-profile
). - Export the DNS records JSON file created in step 5:
aws route53 change-resource-record-sets --hosted-zone-id <NEW HOSTED ZONE ID> --change-batch file://<OUTPUT_PATH.json>
- Update the domain's name servers with the new name servers from the new hosted zone:
- Click on the
Registered domains
link under the Domains section. - Click on your domain.
- Click on the
Add or edit name servers
button under the Name servers section.
- Click on the
- Check until those changes have fully propagated. Use
dig <YOUR DOMAIN> NS
to monitor the name servers. - When the name servers appear to be associated with the new hosted zone, wait another 48 hours minimum before deleting the old hosted zone.
- Migrate the DNS first to avoid traffic interruption:
- Backup your current DNS records.
- Create a new hosted zone using the domain name in your AWS account.
- Open
AWS Route 53
. - In the left menu, select
Hosted zones
, then click on theCreate hosted zone
button.
- Open
- Copy your new NS records (excl. the DS record).
- (Optional but highly recommended) Decrease the NS records TTL in both your existing DNS and the newly created hosted zone to 1 minute (1).
- Configure the hosted zone with the same records than your existing DNS using the records backed up in step 1.
- (Optional) Copy the Delegation Signer (DS) record and remove it from the parent zone before you migrate your domain to Route 53 (2).
- Browse to your domain provider and replace the NS records with the new Route 53 NS records from step 3 (ignore the
dot
trailing dot on each NS record). Updating the NS records may take a while. To check whether that change is live, use this command:
dig YOURDOMAIN NS
- (Optional) When the NS records are live and traffic is managed by Route 53, re-add the DS record to Route 53.
- (Optional) Set the NS records TTL in Route 53 to a higher value if it was lowered in step 4 (recommended value: 172,800 seconds, i.e., 2 days).
(1) The typical TTL for NS records is around 2 days (172,800 seconds). If something goes wrong during your migration, your website could be down for 2 days. (2) If you've configured DNSSEC for your domain, remove the Delegation Signer (DS) record from the parent zone before you migrate your domain to Route 53.
Because it isn't currently possible to have DNSSEC signing enabled across two providers, you must remove any DS or DNSKEYs to deactivate DNSSEC. This temporarily signals to DNS resolvers to disable DNSSEC validation. In step 11, you can re-enable DNSSEC validation if desired, after the transition to Route 53 is completed.
In this scenario, you wish you can redirect all request to https://hello.com
to https://example.com/test
. This will not mask https://example.com/test
behind https://hello.com
. Instead, it is a real redirect in the browser.
- Create a new bucket (WARNING: Its name must match the domain name. For example,
example.com
orwww.example.com
(1)). - Select the
Properties
tab, scroll at the bottom to theStatic website hosting
section, then click theEdit
button. - Under the
Static website hosting
section, tick theEnable
option. - Under the
Hosting type
select theRedirect requests for an object
option. - Under the
Host name
input, enter the path to the redirect without the protocol (e.g.,example.com/test
). - Under the
Protocol
, select the protocol you need.
This above configure a 301 (permanent redirect) to https://example.com/test
(assuming that the configured protocol is https).
You can verify this by executing this command:
curl -I -L YOUR_S3_BUCKET_URL
(1) Hosting a static website on S3 does not support wildcard subdomains. Therefore, you must choose the exact subdomain you wish to configure as the bucket name. To support wildcard subdomain, you must configure CloudFront on top of the S3 bucket.
If the requirements must include redirect codes other than 301 (e.g., 302 for found or 307 for temporary redirect), then use an S3 bucket configured with redirect. If requirements also include support for wildcard subdomains, then add a CloudFront distribution on top of the S3 redirection.
In the example above, the HTTP code used was 301 (permanent redirect). To configure the status code to 302 or 307, step 4 in the previous section must be updated to use Host a static website
rather than Redirect requests for an object
. Once that's done, a new Redirection rules
section allows to configure the redirection. For example, to redirect to https://example.com/test
with 307, use this:
[
{
"Condition": {
"HttpErrorCodeReturnedEquals": "404"
},
"Redirect": {
"HostName": "example.com",
"HttpRedirectCode": "307",
"Protocol": "https",
"ReplaceKeyPrefixWith": "test"
}
},
{
"Condition": {
"HttpErrorCodeReturnedEquals": "403"
},
"Redirect": {
"HostName": "example.com",
"HttpRedirectCode": "307",
"Protocol": "https",
"ReplaceKeyPrefixWith": "test"
}
}
]
- Create an S3 bucket configured with the correct redirection rules as described in the previous sections.
- Create a new CloudFront distribution. WARNING: When setting up the
Origin domain
do not use the auto-completed S3 bucket. This would create anAccessDenied
error when browsing the distribution. Instead, get the HTTP public link of the S3 static website (e.g., http://BUCKETNAME.s3-website-REGION.amazonaws.com) and paste it. - Select the
General
tab and click on theEdit
button. - Under the
Alternate domain name (CNAME)
section, click on theAdd item
button and Add your wildcard domain (e.g.,*.example.com
). WARNING: Add 2 alternate domains, one for the root domain and one for the wildcard (e.g.,example.com
and*.example.com
). - Under the
Custom SSL certificate
section, click on theRequest certificate
link to create a new SSL certificate for that widlcard subdomain. Once the SSL has been provisioned, refresh the input and select that SSL. WARNING: Request an SSL certificate for the 2 domains (e.g.,example.com
and*.example.com
). This can be done by using a comma seperated list of domains under theFully qualified domain name
input by using theAdd another name to this certitifcate button
. - Save.
- In Route 53, create 2 new Alias records, one A record for
example.com
and another for*.example.com
to point to the CloudFront distribution.
That's because hosting a static website on S3 does not support wildcard subdomains. Therefore, you must choose the exact subdomain you wish to configure as the bucket name. To support wildcard subdomain, you must configure CloudFront on top of the S3 bucket.
- In CloudFront:
- Add as many custom domains under the
alias
(e.g.,example.com
,app.example.com
). The special case of www. resolving to the Apex domain is covered later. - Add an ACM SSL that was created to include all the domains defined in the previous step.
- Add as many custom domains under the
- In Route 53, add a new CNAME record (or an A record configured as Alias(1) if the domain is the Apex domain). The record's value is the CloudFront URL (e.g., 12345567.cloudfront.net).
If the requirement is that www. must resolve to the Apex domain, then update step 2 above as follow:
In Route 53:
- Add an A record configured as Alias(1). Use the Apex domain for the the record's name and the CloudFront URL (e.g., 12345567.cloudfront.net) for the record's value.
- Add a standard CNAME record. Use the www. subdomain for the record's name and the Apex domain for the record's value.
(1) In Route 53, an A record configured with the Alias option is equivalent to a CNAME
Opening connections to an Amazon RDS database instance using your domain name
Please refer to the Migrating domains from one AWS account to another section.
- Login to
Route 53
- Click on the
Registered domains
link under the Domains section. - Click on your domain.
- Click on the
Add or edit name servers
button under the Name servers section.
This happens when you forgot to backup the original AWS nameservers. To figure out what it once was, we'll consult the CloudTrail history:
- Open CloudTrail.
- Select the
Event History
. - Search for
ChangeResourceRecordSets
.
aws route53 list-resource-record-sets --hosted-zone-id YOUR_HOSTED_ZONE_ID --output json > route53_records.json