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
| Failure | Symptom | Fix |
|---|---|---|
| ACM certificate stuck in PENDING_VALIDATION | Domain association shows PENDING_VERIFICATION for more than 30 minutes | For 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 Amplify | Subdomain resolves to CloudFront but returns 403 or blank page | The 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 working | Apex domain returns NXDOMAIN or resolves to wrong IP | CNAME at apex violates DNS spec — use Cloudflare flattening, Route 53 ALIAS, or redirect the apex to www |
| Certificate region mismatch | Amplify shows "certificate not valid for this domain" or can't find certificate | ACM certificates for CloudFront must be in us-east-1 — verify with aws acm list-certificates --region us-east-1 |
| Multiple subdomain CNAME updates not reflected | Domain association update appears to succeed but only one subdomain is mapped | update-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 setup | PR preview links in GitHub don't resolve | PR previews always use the amplifyapp.com domain — custom domain mapping does not affect them; share the amplifyapp.com PR URL directly |