AWS
beginner
30-45 minutes

Route 53: Custom Domains & DNS

Register domains, configure DNS, and connect your custom domain to AWS services. Add professional URLs to your deployed applications.

What you'll accomplish

Your application accessible at yourdomain.com with HTTPS

Prerequisites

  • Application deployed on AWS (Lightsail, ECS, or App Runner)
  • AWS account with CLI configured

What is Route 53?

Route 53 is AWS's DNS (Domain Name System) service. It:

  • Registers new domain names
  • Routes traffic to AWS resources
  • Monitors health of your endpoints
  • Manages DNS records
User types: myapp.com
                ↓
Route 53 DNS: "myapp.com → 52.23.156.178"
                ↓
Browser connects to your server
Note

Route 53 costs $0.50/month per hosted zone plus $12-50/year for domain registration (varies by TLD).

Understanding DNS Records

Record TypePurposeExample
APoints domain to IPv4 addressmyapp.com → 52.23.156.178
AAAAPoints domain to IPv6 addressmyapp.com → 2001:db8::1
CNAMEPoints domain to another domainwww.myapp.com → myapp.com
ALIASAWS-specific, points to AWS resourcesmyapp.com → ALB DNS name
MXEmail server configurationmyapp.com → mail.myapp.com
TXTText records (verification, SPF)"v=spf1 include:_spf.google.com"
Note

ALIAS records are special to Route 53. Unlike CNAME, they work at the zone apex (naked domain like myapp.com, not www.myapp.com) and don't incur extra charges.

Option 1: Register a Domain with Route 53

Step 1: Search for Available Domains

  1. Go to Route 53 Console
  2. Click Registered domains → Register domains
  3. Search for your desired domain name
  4. Select a domain and click Proceed to checkout

Step 2: Complete Registration

  1. Enter registrant contact information
  2. Choose privacy protection (recommended, often free)
  3. Review and complete purchase

Step 3: Wait for Registration

Domain registration takes 15 minutes to several hours depending on the TLD.

bash
# Check domain status via CLI
aws route53domains get-domain-detail --domain-name yourdomain.com
Note

Route 53 automatically creates a hosted zone when you register a domain.

Option 2: Use a Domain from Another Registrar

If you have a domain from GoDaddy, Namecheap, Google Domains, etc.

Step 1: Create a Hosted Zone

bash
aws route53 create-hosted-zone \
  --name yourdomain.com \
  --caller-reference $(date +%s)

Or in console:

  1. Go to Route 53 → Hosted zones
  2. Click Create hosted zone
  3. Enter your domain name
  4. Select Public hosted zone
  5. Click Create hosted zone

Step 2: Note the Name Servers

After creating the hosted zone, you'll see 4 NS records like:

ns-123.awsdns-12.com
ns-456.awsdns-34.net
ns-789.awsdns-56.org
ns-012.awsdns-78.co.uk

Step 3: Update Name Servers at Your Registrar

Go to your domain registrar and update the nameservers to the 4 AWS nameservers.

GoDaddy:

  1. My Products → DNS → Manage
  2. Change nameservers to custom
  3. Enter the 4 AWS nameservers

Namecheap:

  1. Domain List → Manage
  2. Nameservers → Custom DNS
  3. Enter the 4 AWS nameservers

Google Domains:

  1. DNS → Custom name servers
  2. Enter the 4 AWS nameservers
Note

DNS propagation takes 15 minutes to 48 hours. Be patient!

Connect Domain to Lightsail

For a Lightsail Instance

bash
# Get your hosted zone ID
ZONE_ID=$(aws route53 list-hosted-zones-by-name \
  --dns-name yourdomain.com \
  --query "HostedZones[0].Id" \
  --output text | cut -d'/' -f3)

# Create A record pointing to your Lightsail static IP
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "yourdomain.com",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [{"Value": "YOUR_LIGHTSAIL_STATIC_IP"}]
      }
    }]
  }'

# Add www subdomain
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "www.yourdomain.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "yourdomain.com"}]
      }
    }]
  }'

Via Console

  1. Go to Route 53 → Hosted zones → yourdomain.com
  2. Click Create record
  3. Leave record name empty (for naked domain)
  4. Record type: A
  5. Value: Your Lightsail static IP
  6. Click Create records

Repeat for www:

  1. Record name: www
  2. Record type: CNAME
  3. Value: yourdomain.com

Connect Domain to ECS/Load Balancer

For ECS Fargate or any service behind an ALB:

Using ALIAS Record (Recommended)

bash
# Get your ALB's hosted zone ID and DNS name
ALB_ZONE_ID="YOUR_ALB_HOSTED_ZONE_ID"  # e.g., Z35SXDOTRQ7X7K for us-east-1
ALB_DNS="myapp-alb-xxxxx.us-east-1.elb.amazonaws.com"

aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "yourdomain.com",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "'$ALB_ZONE_ID'",
          "DNSName": "'$ALB_DNS'",
          "EvaluateTargetHealth": true
        }
      }
    }]
  }'

ALB Hosted Zone IDs by Region

RegionHosted Zone ID
us-east-1Z35SXDOTRQ7X7K
us-east-2Z3AADJGX6KTTL2
us-west-1Z368ELLRRE2KJ0
us-west-2Z1H1FL5HABSF5
eu-west-1Z32O12XQLNTSW2
eu-central-1Z215JYRZR1TBD5
ap-southeast-1Z1LMS91P8CMLE5
ap-northeast-1Z14GRHDCWA56QT

Find more at AWS Documentation.

Connect Domain to App Runner

App Runner services have their own domain:

bash
# Get App Runner service URL
aws apprunner describe-service \
  --service-arn YOUR_SERVICE_ARN \
  --query "Service.ServiceUrl"

# Create CNAME record
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "app.yourdomain.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "xxxxx.us-east-1.awsapprunner.com"}]
      }
    }]
  }'

Then configure the custom domain in App Runner:

bash
aws apprunner associate-custom-domain \
  --service-arn YOUR_SERVICE_ARN \
  --domain-name app.yourdomain.com

Set Up SSL/HTTPS with ACM

Step 1: Request a Certificate

bash
# Request certificate (must be in us-east-1 for CloudFront, any region for ALB)
aws acm request-certificate \
  --domain-name yourdomain.com \
  --subject-alternative-names "*.yourdomain.com" \
  --validation-method DNS \
  --region us-east-1

Step 2: Validate with DNS

Get the validation records:

bash
aws acm describe-certificate \
  --certificate-arn YOUR_CERTIFICATE_ARN \
  --query "Certificate.DomainValidationOptions"

Add the CNAME record to Route 53:

bash
# The output gives you Name and Value - add them as a CNAME
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "_abc123.yourdomain.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "_xyz789.acm-validations.aws"}]
      }
    }]
  }'

Or use the automatic Route 53 integration in the console.

Step 3: Wait for Validation

bash
# Check status
aws acm describe-certificate \
  --certificate-arn YOUR_CERTIFICATE_ARN \
  --query "Certificate.Status"

# Should change from PENDING_VALIDATION to ISSUED

Step 4: Attach to Load Balancer

For ECS/ALB:

bash
# Create HTTPS listener
aws elbv2 create-listener \
  --load-balancer-arn YOUR_ALB_ARN \
  --protocol HTTPS \
  --port 443 \
  --certificates CertificateArn=YOUR_CERTIFICATE_ARN \
  --default-actions Type=forward,TargetGroupArn=YOUR_TARGET_GROUP_ARN

For Lightsail, use Let's Encrypt (covered in the Lightsail lessons).

Subdomains

Create records for subdomains:

bash
# API subdomain
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "api.yourdomain.com",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [{"Value": "YOUR_API_SERVER_IP"}]
      }
    }]
  }'

# Staging environment
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "staging.yourdomain.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "staging-alb.us-east-1.elb.amazonaws.com"}]
      }
    }]
  }'

Configure Email (MX Records)

If you're using Google Workspace, Microsoft 365, or other email services:

Google Workspace

bash
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "yourdomain.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"}
        ]
      }
    }]
  }'

Amazon SES

bash
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "yourdomain.com",
        "Type": "MX",
        "TTL": 300,
        "ResourceRecords": [
          {"Value": "10 inbound-smtp.us-east-1.amazonaws.com"}
        ]
      }
    }]
  }'

Test DNS Configuration

Using dig

Using Online Tools

Troubleshooting

Domain Not Resolving

  1. Check nameservers are correct at registrar
  2. Wait for propagation (up to 48 hours)
  3. Verify hosted zone has the records
bash
aws route53 list-resource-record-sets --hosted-zone-id $ZONE_ID

SSL Certificate Stuck in Pending

  1. Verify DNS validation record is correct
  2. Check the record exists:
bash
dig _abc123.yourdomain.com CNAME
  1. Wait up to 30 minutes for validation

Wrong IP Address

bash
# Update existing record
aws route53 change-resource-record-sets \
  --hosted-zone-id $ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "yourdomain.com",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [{"Value": "NEW_IP_ADDRESS"}]
      }
    }]
  }'

HTTPS Not Working

  1. Verify certificate is in ISSUED status
  2. Check certificate is attached to load balancer
  3. Ensure HTTPS listener exists on port 443
  4. Verify security group allows port 443

Cost Summary

ComponentCost
Hosted Zone$0.50/month
DNS Queries (1M queries)$0.40
Domain Registration (.com)$12-15/year
ACM CertificatesFree
Total~$1/month + domain

Quick Reference: Common Record Patterns

# Naked domain to server
yourdomain.com       A        52.23.156.178

# WWW to naked domain
www.yourdomain.com   CNAME    yourdomain.com

# Subdomain to load balancer
app.yourdomain.com   ALIAS    myapp-alb.us-east-1.elb.amazonaws.com

# API on different server
api.yourdomain.com   A        52.23.156.179

# Staging environment
staging.yourdomain.com CNAME  staging-alb.us-east-1.elb.amazonaws.com

What You've Accomplished

You now have a complete AWS deployment:

  1. AWS Account - Set up with billing alerts and IAM user
  2. AWS CLI - Configured on your local machine
  3. Application Deployed - Via Lightsail, ECS, or App Runner
  4. Custom Domain - Professional URL with Route 53
  5. SSL Certificate - HTTPS enabled with ACM
Note

Congratulations! Your application is now live at https://yourdomain.com. You've completed the end-to-end AWS deployment journey!

Next Steps

  • Set up monitoring with CloudWatch
  • Configure automated deployments with CodePipeline
  • Add a CDN with CloudFront for global performance
  • Implement blue-green deployments for zero-downtime updates