← Back to project write-up

Route 53 + Custom Domain

A step-by-step tutorial for pointing a custom domain at an EKS app running behind an ALB.

This is something I hadn't done end to end before, so I'm documenting every step. The goal was to get app.jspoth.com and jspoth.com both pointing to a Go app running on EKS behind an AWS Application Load Balancer.

What you need before starting

If your domain is registered outside of AWS, you need to update the nameservers at your registrar to point to the Route 53 NS records. Route 53 → Hosted zones → your domain → NS record shows the 4 nameservers.

Step 1 — Request an ACM Certificate

You need an SSL cert for HTTPS. AWS Certificate Manager (ACM) issues public certs for free.

  1. Go to ACM → Request certificate → Request a public certificate
  2. Add your domains:
  3. Validation method: DNS validation
  4. Click Request
Gotcha: Make sure you're in the same AWS region as your ALB when requesting the cert. ACM certs are regional and must match the ALB's region. I made the mistake of creating mine in us-west-2 when the ALB was in us-east-2 — had to delete it and start over.

Validating the certificate

After requesting, the cert will show as Pending validation. ACM needs you to prove you own the domain by adding a CNAME record.

  1. Open the certificate in ACM
  2. Click "Create records in Route 53" — since your hosted zone is already there, it adds the CNAME automatically
  3. Wait a few minutes — the cert status will change to Issued
The *.jspoth.com and jspoth.com entries share the same CNAME validation record, so you only need to create it once.

Step 2 — Update the Kubernetes Ingress

Once the cert is issued, update your ingress to use HTTPS. Add these annotations to k8s/ingress.yaml:

alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/certificate-arn: <your-cert-arn>

Apply it: kubectl apply -f k8s/ingress.yaml

The LBC will update the ALB to add an HTTPS listener and redirect all HTTP traffic to HTTPS.

Gotcha: Don't hardcode the cert ARN in the file if it's in a public repo. Use a GitHub secret (ACM_CERT_ARN) and substitute it in CI before applying.

Step 3 — Add Route 53 DNS Records

Now point your domain at the ALB. Go to Route 53 → Hosted zones → jspoth.com → Create record.

For app.jspoth.com

  1. Record name: app
  2. Record type: A
  3. Toggle Alias on
  4. Route traffic to: Alias to Application and Classic Load Balancer
  5. Region: us-east-2 (must match the ALB region)
  6. Select your ALB from the dropdown — it shows the full DNS name
  7. Click Create records

For jspoth.com (apex)

Same steps as above but leave the record name blank. That creates the apex record.

Gotcha — apex record not committing: The first time I created the apex A record it showed up in the Route 53 console but dig jspoth.com @ns-1999.awsdns-57.co.uk kept returning ANSWER: 0. The record just wasn't saved properly. I deleted it and recreated it from scratch and it worked on the second attempt. If you see this, don't wait around — just delete and recreate.

Verify the record committed (before moving on)

Query Route 53's own nameserver directly after creating each record:

# Replace with one of your NS records from the hosted zone
dig app.jspoth.com @ns-1999.awsdns-57.co.uk
dig jspoth.com @ns-1999.awsdns-57.co.uk

You want to see ANSWER: 2 or more. If it's ANSWER: 0, the record didn't commit — delete and recreate.

Use alias records (not plain A records with IPs) for ALBs. Alias records are free, update automatically if the ALB IPs change, and have no TTL penalty.

Step 4 — Verify DNS propagation

After adding the records, verify they're resolving correctly:

dig app.jspoth.com @ns-1999.awsdns-57.co.uk

Query Route 53's own nameserver directly — this bypasses your local DNS cache and tells you immediately if the record is live. Look for ANSWER: 2 (or more) in the response.

Gotcha: If dig returns ANSWER: 0 even when querying Route 53 directly, the record wasn't saved properly. Go back to the console, delete it, and recreate it. This happened to me with the apex record — it showed in the UI but wasn't being served.

Step 5 — Test it

curl -I https://app.jspoth.com

You should get a 200 OK (or whatever your app returns at that path).

Gotcha: If dig resolves correctly but curl still fails with "Could not resolve host", your local DNS cache is stale. Flush it:
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

Summary