Guide · AWS Amplify · Custom Domains

Amplify Custom Domain Setup for MCP Server Dashboards — ACM, Route 53, and External DNS

When you add a custom domain to an Amplify Hosting app, Amplify automatically requests an ACM certificate in us-east-1 (CloudFront requires us-east-1 regardless of your app's region), creates validation DNS records, and attaches the verified certificate to the CloudFront distribution behind your app. For MCP server teams, this means your admin dashboard at dashboard.yourmcpserver.com gets HTTPS with zero certificate management — Amplify handles renewal automatically. The key distinction: if your domain is in Route 53 in the same AWS account, Amplify can create and validate the certificate with zero manual steps. If your domain is at an external registrar (Cloudflare, Namecheap, GoDaddy), you must manually create two CNAME records: one for ACM validation and one pointing the subdomain to Amplify's CloudFront distribution. Root domain (apex) setup requires your DNS provider to support ALIAS or ANAME records — or you must delegate the zone to Route 53.

TL;DR

For Route 53 domains: aws amplify create-domain-association handles everything — certificate, validation, and DNS records. For external DNS: create two CNAMEs — the ACM validation CNAME (shown in ACM console under the certificate), and the subdomain CNAME pointing to the *.cloudfront.net domain shown in the Amplify domain association. Root domain apex records cannot be CNAME — use Route 53 ALIAS, or configure a redirect from the apex to www at your DNS provider. Wildcard subdomain (*.yourmcpserver.com) requires the wildcard to be listed explicitly as a sub-domain prefix in the domain association.

Domain association with Route 53 (automatic DNS)

When the domain's hosted zone is in Route 53 in the same AWS account as your Amplify app, Amplify calls Route 53 automatically to create the ACM validation CNAME and the subdomain's final CNAME or ALIAS record. The IAM role that Amplify uses must have route53:ChangeResourceRecordSets and route53:ListHostedZonesByName permissions on the hosted zone.

# Route 53 domain — Amplify handles all DNS automatically
aws amplify create-domain-association \
  --app-id d1abc23def456 \
  --domain-name yourmcpserver.com \
  --sub-domains \
    prefix=dashboard,branchName=main \
    prefix=staging,branchName=develop \
    prefix='',branchName=main   # root domain (zone apex)

# Check association status (wait for AVAILABLE)
aws amplify get-domain-association \
  --app-id d1abc23def456 \
  --domain-name yourmcpserver.com \
  --query 'domainAssociation.{status:domainStatus,certs:certificateVerificationDNSRecord}'

Amplify creates an ALIAS record (not a CNAME) for the zone apex in Route 53 — ALIAS records point to CloudFront distributions and do not break the DNS specification that prohibits CNAME at the zone apex. The validation typically completes in 2–10 minutes with Route 53 because Amplify creates the validation record immediately and Route 53 propagates it to ACM within seconds.

Domain association with external DNS (manual CNAME setup)

For domains managed by Cloudflare, Namecheap, or other external providers, you must create DNS records manually. Amplify gives you two sets of records: the ACM validation CNAME (for certificate issuance) and the app CNAME (where your subdomain should point after validation).

# Step 1: Create domain association (Amplify can't update external DNS)
aws amplify create-domain-association \
  --app-id d1abc23def456 \
  --domain-name yourmcpserver.com \
  --sub-domains prefix=dashboard,branchName=main

# Step 2: Get the DNS records you need to create
aws amplify get-domain-association \
  --app-id d1abc23def456 \
  --domain-name yourmcpserver.com

# Output (example):
# domainStatus: PENDING_VERIFICATION
# certificateVerificationDNSRecord: "_abc123.yourmcpserver.com. CNAME _def456.acm-validations.aws."
# subDomains:
#   - prefix: dashboard
#     dnsRecord: "dashboard.yourmcpserver.com. CNAME d1abc23def456.cloudfront.net."
#     verified: false

# Step 3: Create these two records at your DNS provider:
# Record 1 (ACM validation):
#   Type: CNAME
#   Name: _abc123.yourmcpserver.com
#   Value: _def456.acm-validations.aws
#
# Record 2 (app subdomain):
#   Type: CNAME
#   Name: dashboard.yourmcpserver.com
#   Value: d1abc23def456.cloudfront.net

After creating both records, ACM validates the certificate (5–30 minutes depending on DNS propagation) and the domain association status changes to AVAILABLE. The validation CNAME only needs to exist long enough for ACM to validate — you can delete it after the certificate is issued, but keeping it means auto-renewal works without manual action.

Root domain (apex) setup without Route 53

The DNS specification prohibits CNAME records at the zone apex (e.g., yourmcpserver.com without any subdomain prefix). CloudFront distributions have no fixed IP address — they use anycast, so you can't use an A record with a static IP. Your options for the apex without Route 53 ALIAS:

# Option 1: Use Cloudflare's CNAME flattening (Cloudflare-specific)
# Cloudflare "flattens" CNAME at apex — set a CNAME record for the apex zone:
#   yourmcpserver.com  CNAME  d1abc23def456.cloudfront.net
# Cloudflare resolves this to an A record automatically.

# Option 2: Redirect apex to www with an HTTP redirect at your DNS provider
# Create a URL redirect (Namecheap / GoDaddy / Netlify DNS):
#   yourmcpserver.com  → https://dashboard.yourmcpserver.com (301)

# Option 3: Delegate the apex zone to Route 53
# At your registrar, change the NS records to Route 53 nameservers:
# ns-123.awsdns-45.com, ns-678.awsdns-90.net, etc.
# Then manage all DNS in Route 53 and use ALIAS records for the apex.

# Route 53 ALIAS for apex (after delegation):
aws route53 change-resource-record-sets \
  --hosted-zone-id Z1234567890ABC \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "yourmcpserver.com",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "d1abc23def456.cloudfront.net",
          "EvaluateTargetHealth": false
        }
      }
    }]
  }'
# Note: Z2FDTNDATAQYW2 is the global hosted zone ID for CloudFront distributions

Cloudflare's CNAME flattening is the simplest option if you use Cloudflare DNS — it transparently handles the apex restriction. If you use Namecheap or GoDaddy, the redirect-to-www approach is most reliable. Route 53 delegation is the most flexible but requires updating nameserver records at your registrar and waiting for NS propagation (24–48 hours globally).

Branch subdomain mapping and wildcard patterns

Amplify allows multiple branches to serve different subdomains under the same domain. This is useful when you want dashboard.yourmcpserver.com for production and staging.yourmcpserver.com for the develop branch. You can also add a wildcard prefix to automatically route all PR preview subdomain patterns.

# Map multiple branches to different subdomains
aws amplify update-domain-association \
  --app-id d1abc23def456 \
  --domain-name yourmcpserver.com \
  --sub-domains \
    prefix=dashboard,branchName=main \
    prefix=staging,branchName=develop \
    prefix=beta,branchName=beta \
    prefix='*',branchName=main   # wildcard — all unmatched subdomains go to main

# For PR previews (auto-created by Amplify per PR):
# Preview URLs use the pattern:
# https://pr-{pr-id}.{branch-name}.{app-id}.amplifyapp.com
# They cannot be mapped to custom domain subdomains — they always use the amplifyapp.com domain

The wildcard prefix * catches any subdomain not matched by a more specific prefix. It's useful for routing all feature branch deployments to a known endpoint without creating explicit DNS records for each branch. However, wildcard DNS requires your DNS provider to support wildcard CNAME records (most providers do).

Certificate renewal and domain re-validation

ACM certificates issued for Amplify apps auto-renew 60 days before expiry. Auto-renewal requires the validation CNAME record to still exist in DNS. If you deleted the validation CNAME after initial setup, you'll need to re-add it when ACM attempts renewal — Amplify will show the domain association as PENDING_VERIFICATION again.

# Check certificate status
aws acm list-certificates \
  --query 'CertificateSummaryList[?DomainName==`yourmcpserver.com`]'

# Get the validation CNAME to re-add if renewal is pending
aws acm describe-certificate \
  --certificate-arn arn:aws:acm:us-east-1:123456789012:certificate/abc-def \
  --query 'Certificate.DomainValidationOptions[0].ResourceRecord'

# Output:
# {
#   "Name": "_abc123.yourmcpserver.com.",
#   "Type": "CNAME",
#   "Value": "_def456.acm-validations.aws."
# }

ACM certificates for CloudFront (and Amplify) must be in us-east-1 — even if your Amplify app is in us-west-2. The aws acm list-certificates command only returns certificates in the current region — always add --region us-east-1 when troubleshooting Amplify certificate issues.

Failure modes reference

FailureSymptomFix
ACM certificate stuck in PENDING_VALIDATIONDomain association shows PENDING_VERIFICATION for more than 30 minutesFor external DNS: verify the validation CNAME was created exactly as shown (name and value both include trailing dot — omit it when creating the record). Check dig _abc123.yourmcpserver.com CNAME to confirm propagation
Subdomain CNAME not serving AmplifySubdomain resolves to CloudFront but returns 403 or blank pageThe CNAME must point to the app-specific CloudFront distribution (d1abc23def456.cloudfront.net), not a generic Amplify URL. Get the exact value from aws amplify get-domain-association
Root domain with non-Cloudflare DNS not workingApex domain returns NXDOMAIN or resolves to wrong IPCNAME at apex violates DNS spec — use Cloudflare flattening, Route 53 ALIAS, or redirect the apex to www
Certificate region mismatchAmplify shows "certificate not valid for this domain" or can't find certificateACM certificates for CloudFront must be in us-east-1 — verify with aws acm list-certificates --region us-east-1
Multiple subdomain CNAME updates not reflectedDomain association update appears to succeed but only one subdomain is mappedupdate-domain-association replaces all sub-domains — include ALL subdomains you want in a single call, not just the new one
PR preview URLs broken after custom domain setupPR preview links in GitHub don't resolvePR previews always use the amplifyapp.com domain — custom domain mapping does not affect them; share the amplifyapp.com PR URL directly