Best Practices: Why AWS EC2 Elastic IPs Should Use CNAME Records Instead of A Records for Dynamic DNS Resolution


19 views

When configuring DNS for an EC2 instance, many developers face a dilemma: should they point their domain directly to the Elastic IP (using an A record) or use a CNAME to reference Amazon's DNS hostname? While using an A record might seem simpler, AWS explicitly recommends CNAME records for Elastic IPs in their documentation.

# Example of AWS EC2 public DNS format:
ec2-203-0-113-25.compute-1.amazonaws.com

The fundamental reason lies in how AWS manages network infrastructure. Even with Elastic IPs, the underlying IP address might change during:

  • Instance stop/start cycles
  • AZ failover events
  • Network interface reconfigurations
  • Account-level service migrations

AWS maintains an internal DNS system that dynamically updates to reflect current instance networking status. When you use:

# Recommended CNAME configuration
www.example.com.    CNAME   ec2-203-0-113-25.compute-1.amazonaws.com.

versus the problematic A record approach:

# Not recommended static A record
www.example.com.    A       203.0.113.25

I've encountered cases where A records caused outages:

  1. An EC2 instance was stopped for maintenance and resumed with the same Elastic IP but different underlying infrastructure
  2. DNS caching propagated the old IP while AWS routing tables updated
  3. Result: 30 minutes of downtime despite the IP appearing correct

Modern SSL/TLS implementations add another layer of complexity:

# Let's Encrypt certbot command showing DNS challenge
sudo certbot certonly --manual --preferred-challenges dns \
  -d example.com -d www.example.com

Using CNAME records ensures your certificates remain valid even if AWS internally changes networking components, as the public DNS name remains constant.

For production systems, I recommend this architecture:

# Route 53 configuration example (CloudFormation snippet)
Resources:
  MyRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: www.example.com
      Type: CNAME
      TTL: '300'
      ResourceRecords:
        - !GetAtt EC2Instance.PublicDnsName

The only exception would be legacy systems that:

  • Cannot follow CNAME chains
  • Require direct IP connections
  • Are in development environments

Even then, implement automatic monitoring to detect IP changes:

# Sample Python check using boto3
import boto3
ec2 = boto3.client('ec2')
response = ec2.describe_addresses(PublicIps=['203.0.113.25'])
if response['Addresses'][0]['InstanceId'] != 'i-1234567890abcdef0':
    # Trigger alert for DNS update

When deploying a single EC2 instance with an Elastic IP, many developers face a dilemma between DNS record types. While an A record mapping directly to the Elastic IP might seem straightforward, AWS's recommendation for CNAME records stems from deeper infrastructure considerations.

Here's why CNAME is preferred:

# Example DNS configuration (CNAME approach)
www.example.com.    IN  CNAME  ec2-111-111-111-111.compute-1.amazonaws.com.

Versus the problematic A record approach:

# Not recommended (A record approach)
www.example.com.    IN  A      111.111.111.111

Even if you're currently running a single instance, AWS's architecture assumes potential mobility:

  1. Elastic IPs can be remapped to different instances during failover
  2. Underlying IPs might change during maintenance events
  3. Instance replacement triggers IP changes unless using Elastic IP

Modern browsers enforce strict certificate validation. A CNAME pointing to AWS's hostname works seamlessly with ACM certificates:

# ACM certificate covering both domains
Certificate:
  - example.com
  - *.example.com
  - ec2-111-111-111-111.compute-1.amazonaws.com

Should you later add an ALB/ELB, CNAME records simplify migration:

# Future ALB integration
www.example.com.    IN  CNAME  my-load-balancer-1234567890.us-west-2.elb.amazonaws.com.

For Route 53 configuration:

# AWS CLI command to create CNAME record
aws route53 change-resource-record-sets \
--hosted-zone-id Z1PA6795UKMFR9 \
--change-batch '{
  "Changes": [{
    "Action": "CREATE",
    "ResourceRecordSet": {
      "Name": "www.example.com",
      "Type": "CNAME",
      "TTL": 300,
      "ResourceRecords": [{
        "Value": "ec2-111-111-111-111.compute-1.amazonaws.com"
      }]
    }
  }]
}'

Only consider A records if:

  • You require root domain hosting (though AWS now supports ALIAS records)
  • Working with legacy systems that don't follow CNAME properly
  • Operating in environments with strict DNS propagation requirements