5. Domain, DNS and certificates
What it is
DNS turns names like api.example.com into addresses. A hosted zone in AWS
Route 53 holds the DNS records for one domain or subdomain. We put the main zone in the
prod account and give each other environment its own subdomain zone in its own account,
linked by delegation (an NS record that says "ask that other zone"). Certificates
from AWS Certificate Manager (ACM) make https:// work, free, and renew themselves.
Why we do it
- Each environment manages its own names without touching prod.
- Predictable names: anyone can guess
api.staging.example.com. - ACM certificates renew automatically as long as the DNS validation record stays.
Before you start
- Access to the domain's registrar (where it was bought: GoDaddy, Namecheap, Route 53).
- The list of existing records the client uses, especially email (
MX) and website records. Export them before changing anything. - AWS SSO access to prod, staging and dev from step 4.
The naming plan
| What | prod | staging | dev |
|---|---|---|---|
| Zone | example.com (prod account) | staging.example.com (staging account) | dev.example.com (dev account) |
| API | api.example.com | api.staging.example.com | api.dev.example.com |
| Web app | app.example.com | app.staging.example.com | app.dev.example.com |
| Admin | admin.example.com | admin.staging.example.com | admin.dev.example.com |
| Email sending | mail.example.com |
How it fits together
Steps
1. Create the main zone in prod
Route 53, Hosted zones, Create hosted zone, name example.com, type Public.
Note the four NS values it shows.
If the domain already has records elsewhere, copy every existing record into the new
zone first (website, MX, TXT for email and verification). Then:
2. Point the registrar at Route 53
At the registrar, replace the domain's nameservers with the four NS values from step 1.
This can take up to 48 hours to spread, usually less than one. Do it on a weekday
morning, never before a launch.
3. Create the environment zones and delegate them
In the dev account: create a public hosted zone dev.example.com and note its four
NS values. In the prod account's example.com zone, add a record:
| Name | Type | Value |
|---|---|---|
dev | NS | the four values from the dev zone |
Repeat for staging. Do it in two Terraform applies: create the zone, then add the
delegation, because the second needs the first's output.
4. Request certificates
In each account, Certificate Manager, Request a public certificate:
| Account | Names | Region |
|---|---|---|
| prod | example.com, *.example.com | main region (for load balancers) and us-east-1 (for CloudFront) |
| staging | *.staging.example.com | same two |
| dev | *.dev.example.com | same two |
Choose DNS validation, then Create records in Route 53. The status turns to Issued within minutes. Leave the validation records in place forever; renewal uses them.
A wildcard (*.dev.example.com) also means individual host names are not listed in
public certificate logs, which scanners watch.
Check it worked
dig NS example.com +short # the four Route 53 nameservers
dig NS dev.example.com +short # the dev zone's nameservers
dig api.dev.example.com +short # an address, once the load balancer exists
In ACM every certificate shows Issued.
If it goes wrong
| You see | It means |
|---|---|
| Email stopped working after step 2 | The MX records were not copied into the new zone |
| Certificate stuck in "Pending validation" | The validation CNAME is missing, or delegation is not working yet |
| CloudFront will not accept the certificate | It must be in us-east-1 |
dig answers differ between laptops | Old answers are cached. Wait for the TTL |
Rules
Export and copy every existing record before you change nameservers. Losing the client's email records stops their company email.
Never delete an ACM validation record. The certificate silently fails to renew a year later.
Done when
-
example.comzone in prod with all existing records copied. - Registrar points at Route 53.
-
devandstagingzones delegated. - Wildcard certificates issued in the main region and
us-east-1, per environment.