Your Own Domain + HTTPS on AWS: CloudFront & Route 53 (2026)
Last time we built a real, working AWS project and left one thread hanging on purpose: its address was ab12cd34ef.execute-api.us-east-1.amazonaws.com, which is nobody’s idea of a short link and looks faintly like a phishing attempt on a poster. This post ties that thread off. By the end you will have your own domain, with a padlock, in front of your project — https://go.yourname.com/xK4b2n — using Route 53 for the address book, AWS Certificate Manager for the padlock, and CloudFront as the front door. And here is the fact that reorganizes the whole job: since November 2025, CloudFront’s $0-a-month Free plan bundles the CDN, a firewall, DDoS protection, the certificate, and your Route 53 hosted zone — so the entire "own domain with HTTPS" layer costs nothing per month. The only money that changes hands is the domain itself: $16 a year for a .com on Route 53 as of July 2026, or a few dollars for a less famous ending. Most guides still quote a $0.50 monthly DNS fee and a paid certificate. Both are now optional. Build time: 20 minutes for the short version, about an hour for the full one. Let’s go.
Jake lost a weekend to a sentence. He bought a domain, pointed it at his project the way a forum post told him to, opened the browser, and got the red page: Your connection is not private. Somewhere he had read that DNS "takes up to 48 hours to propagate," so he did the responsible thing and waited. Two days. Then he waited one more, because the forum said up to. On day four he sent me a screenshot, and the fix took four minutes: his certificate lived in the Mumbai region, and CloudFront only looks in Virginia, so his distribution had been quietly serving Amazon’s own default certificate for a domain it had never heard of. Nothing was propagating. Nothing was ever going to propagate. The most common diagnosis in the whole domain-and-HTTPS business — "just wait" — is also the one that is almost never right, and that is the thing this post most wants to spare you.
Ethan: "Think of opening a shop. The domain is the street address you buy. DNS is the city directory that tells the postman which building that address means — and if you move DNS to Route 53, you’re just choosing which directory the postman trusts. The certificate is the ID card in the window that proves the shop is really yours, so customers stop getting that ‘are you sure?’ warning. And CloudFront is a chain of franchise counters in every city, each holding a copy of your menu, so nobody has to travel to head office to be served. The trap everyone falls into is one dumb envelope: the counter forwards a customer’s letter to head office still addressed to the counter, and head office writes back ‘nobody here by that name.’ You’ll meet that envelope below. It has a checkbox."
The four things you are actually buying (and which are free)
"Get a domain with HTTPS" sounds like one purchase. It is four separate jobs, done by four separate systems, and every confusing error you will ever see comes from mixing up which one is failing. Here they are, priced honestly for August 2026 — and if you came here just asking what an AWS domain costs, the answer is the first row:
| Job | Who does it | What it costs | What it looks like when it’s the broken part |
|---|---|---|---|
The name — owning yourname.com | A registrar (Route 53 is one; so is any domain seller) | The only real money: $16/yr for .com or .org on Route 53, $17 for .net, $71 for .io; obscure endings from a few dollars | "This site can’t be reached" / DNS_PROBE_FINISHED_NXDOMAIN — the name doesn’t resolve at all |
| The directory — DNS: name → where to send traffic | Route 53 hosted zone | $0.50/month, or $0 attached to a CloudFront Free plan; queries to AWS aliases are free either way | Name resolves to the wrong place, or to nothing; the "48 hours" myth lives here |
| The ID card — the TLS certificate behind the padlock | AWS Certificate Manager (ACM) | $0, renews itself forever — as long as it stays inside AWS (an exportable copy costs $7) | "Your connection is not private" / NET::ERR_CERT_COMMON_NAME_INVALID |
| The front door — the thing that answers on your domain | CloudFront (full version) or API Gateway’s custom domain (short version) | $0/month on the Free plan; pay-as-you-go is $0.085/GB in the US and about a cent per 10,000 HTTPS requests, with its own always-free allowance | 403 Forbidden, 502 Bad Gateway, or your page loads but every short link 404s |
Read the third column again: three of the four jobs are free. The internet’s folk memory says HTTPS costs money and a CDN is for big companies; both were true in 2015, and tutorials written since then have been slow to notice the ground moving. What you pay for is the name. Everything that makes the name work — the directory, the padlock, the counters in every city — comes with the account.
Two build paths — pick before you click
There are two honest ways to put a domain on the link shortener, and the right one depends on what you want the domain to do. Path A uses a feature API Gateway already has: a custom domain name that points straight at your API. Twenty minutes, no CloudFront, and your short links become https://go.yourname.com/xK4b2n. The web page stays on its S3 address, which for a family shortener is completely fine — nobody types the page’s URL, they type the short link. Path B puts CloudFront in front of both the page and the API under one domain: the page at https://go.yourname.com/, the links beneath it. You get a firewall, DDoS protection, edge caching, and — my favorite side effect — the CORS wall you climbed last time ceases to exist, because page and API now share one origin and the browser has nothing to object to.
My suggestion: do Path A first regardless. It is the shape of the whole problem in miniature — domain, certificate, DNS record — and every concept transfers to Path B unchanged. If you finish A and want the one-domain, one-padlock version with the front door, keep going. If you stop at A, you have still shipped a real domain with HTTPS, and that is more than most people who "know AWS" have ever done by hand.
Before anything: the tripwire, and the one region rule
House rule, unchanged: if you don’t already have the $1 budget alarm from the billing post, make it now. Nothing in this build can run up a bill while idle, but a domain renews yearly and a hosted zone bills monthly, and the alarm is how you find out you left one behind. Two minutes, then never think about it again.
Now the rule that cost Jake four days, stated as plainly as I can: CloudFront only sees certificates that live in us-east-1. Not "prefers" — only. CloudFront is a global service that happens to keep its certificate cupboard in Virginia, and if you request the certificate anywhere else, the CloudFront console’s certificate dropdown will simply be empty, with no error, no hint, nothing. Your project from last time was built in us-east-1 anyway, so for this build the rule costs you nothing — but glance at the region name in the top-right corner before you request any certificate, and if it doesn’t say N. Virginia, change it first. The one exception: Path A’s API Gateway custom domain wants the certificate in the API’s own region, which for us is also us-east-1. So today, one region for everything, and the rule never bites.
Step 1 — Get a domain (or bring one)
If you don’t own a domain yet, the frictionless route is to buy it in Route 53: Route 53 → Registered domains → Register domains, search a name, pay. Route 53 raised prices on about 267 endings on July 1, 2026 — .com and .org went from $15 to $16, the third small rise in three years — while .net ($17), .dev ($17), .io ($71) and .co sat this round out. If the name is for posters and QR codes, remember the reader will never type it; a cheap, odd ending you can afford for a decade beats a .com you resent renewing. When you register in Route 53, it creates the hosted zone for you and points the domain at it automatically. That single automatic step is the whole reason I recommend buying here for a first build: it removes the one manual handoff where beginners get stranded.
If you already own a domain somewhere else — GoDaddy, Namecheap, Google’s old registrar now at Squarespace, anyone — you have a choice, and it’s worth understanding rather than guessing. A registrar does two separable jobs: it sells you the name, and by default it hosts your DNS. You can keep the first and move the second. Create a hosted zone in Route 53 for your domain (Route 53 → Hosted zones → Create; it costs $0.50/month, or $0 once attached to the Free plan in Path B), open it, and copy the four name servers from its NS record — they look like ns-123.awsdns-45.com. Then at your registrar, find "name servers" or "custom DNS" and paste those four in, replacing the registrar’s. That handoff is real propagation: registrars say up to 48 hours; in practice it is usually under an hour, and you can watch it happen with the check in Step 5. Everything after this point — every record you create — takes effect in about a minute, not two days. "Propagation" is a thing that happens once, when you move name servers. It is not what’s wrong with your padlock.
One more honest option: leave DNS at your registrar entirely and just add records there. It works for Path A if you use a subdomain like go.yourname.com. It gets awkward for a bare domain (yourname.com with nothing in front), because the DNS standard forbids the record type you’d need at the top of a domain, and only some registrars offer a workaround. Route 53 has a clean answer for that called an alias record, which is a large part of why this post uses it. If your registrar’s DNS is where you want to live, use a subdomain and skip the alias sections below; everything else still applies.
Step 2 — The certificate: free, automatic, and picky about one thing
Region check: us-east-1. Now open Certificate Manager → Request → Request a public certificate. For the domain name, enter the exact name you’ll use, say go.yourname.com. Click Add another name and add the bare domain yourname.com too, and, if you can see yourself wanting www or api or a dozen other subdomains later, add the wildcard *.yourname.com as well. A wildcard on an ACM certificate is free and it saves you a second certificate for every new idea. Choose DNS validation — not email; email validation involves a message to addresses like admin@yourname.com that you almost certainly can’t receive yet — and request.
The certificate now sits in Pending validation. ACM wants proof you control the domain, and it proves it the honest way: by asking you to publish a specific DNS record and then checking it exists. If your hosted zone is in Route 53, the certificate’s page has a button that does the whole errand: Create records in Route 53. Press it, confirm, and come back in a few minutes; the status flips to Issued, usually within five, occasionally thirty. If DNS lives at your registrar, copy the CNAME name and value ACM shows you and add them there by hand — the name ends in your domain and the value ends in acm-validations.aws, and the most common mistake is a registrar that appends your domain to the name automatically, giving you _abc.go.yourname.com.yourname.com. If validation sits pending for more than an hour, that doubled domain is the first thing to check.
And that is the last time you touch the certificate. ACM renews it before it expires, forever, for nothing, as long as the validation record stays in DNS (leave it there — that is what renewal checks). The one quiet catch, and the reason it’s free: the private key never leaves AWS. You cannot download this certificate to run it on a server in your living room. If you ever need one that travels, ACM sells exportable public certificates at $7 each ($79 for a wildcard) — a fair price, and irrelevant to us, because everything in this build lives where the free one works.
Path A — the 20-minute version: API Gateway’s own custom domain
The API Gateway post mentioned that the ugly invoke URL is replaceable; here’s the replacement. This path adds nothing to the bill — custom domain names are a free feature of the API — and it takes three clicks and one DNS record.
- Open API Gateway → Custom domain names → Create. Domain name:
go.yourname.com. Endpoint type: Regional (the only type HTTP APIs support). Certificate: pick the one you just issued — it’s in the list because it lives in this region. Create. - On the new domain’s page, open API mappings → Configure API mappings → Add new mapping. API:
shortener-api. Stage:$default. Path: leave empty — a path here would put your short links atgo.yourname.com/something/xK4b2n, which defeats the purpose. Save. - Still on that page, copy the API Gateway domain name — a long address like
d-abc123.execute-api.us-east-1.amazonaws.com. That is where your domain needs to point.
Now the DNS record. In Route 53 → your hosted zone → Create record: record name go, record type A, switch on Alias, route traffic to Alias to API Gateway API, region us-east-1, and pick the domain you just copied from the dropdown. Create. The alias is Route 53’s special trick: it behaves like a CNAME but is allowed anywhere, including the bare domain, and queries to it are free. If DNS is at your registrar instead — an API Gateway custom domain without Route 53 is perfectly normal — add a plain CNAME from go to that long address; identical result for a subdomain.
Give it a minute, then open https://go.yourname.com/xK4b2n with a code you made last time. It redirects, with a padlock, on your domain. Take a moment with that: a name you own, a certificate that renews itself, an address that will outlive every free shortener on the planet. One thing left, and it’s inside the Lambda from last time: the function builds the short URL from event["requestContext"]["domainName"], and behind a custom domain that value is now your domain — so new links come out as https://go.yourname.com/… automatically. Nothing to change. If you only wanted the short links on your domain, you can stop here; Jake’s cousin did, and the posters have been fine ever since.
Path B — the full version: CloudFront as the one front door
Path B is what production looks like: one domain, one certificate, one entrance, and a CDN in front of everything. What CloudFront actually is, in Ethan’s terms: hundreds of counters around the world, each able to hold a copy of anything cacheable (your web page) and to relay anything that isn’t (your API calls) to head office over Amazon’s private network instead of the public internet. Visitors talk to the nearest counter. Your S3 bucket and API Gateway become origins — the places counters fetch from — and the rules for which URL goes to which origin are called behaviors. Three concepts, and you’ll have used all three in the next ten minutes.
First, one tiny change to the Lambda, because behind CloudFront the domainName trick from Path A stops working — the counter talks to head office using head office’s address, so the function would mint links on the execute-api domain again. Give it the answer explicitly. In Lambda → shortener → Configuration → Environment variables, add SHORT_DOMAIN = go.yourname.com. Then edit two lines and redeploy:
import json, string, random, boto3, os
# ...unchanged...
domain = os.environ.get("SHORT_DOMAIN") or event["requestContext"]["domainName"]
return reply(200, {"short": "https://" + domain + "/" + code})
Now the distribution. Open CloudFront → Create distribution. The console has been redesigned more than once and asks its questions in a slightly different order each year, so here are the answers, which don’t change:
- Origin 1 — the API. Origin domain: paste your API’s invoke host,
ab12cd34ef.execute-api.us-east-1.amazonaws.com, with nohttps://and no path. Protocol: HTTPS only. Name itapi. - Origin 2 — the page. Add a second origin, choose your S3 bucket from the list (the bucket entry, not the website endpoint), and under origin access choose Origin access control → create a new OAC. CloudFront will offer to copy a bucket policy for you — say yes, and paste it into the bucket’s policy. Name it
site. - Default behavior (the catch-all, pattern
*): originapi. Viewer protocol: Redirect HTTP to HTTPS. Allowed methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE (the shortener needs POST). Cache policy: CachingDisabled. Origin request policy: AllViewerExceptHostHeader. Those last two are the two checkboxes that break everyone — keep reading for why. - Second behavior, path pattern
/index.html: originsite, viewer protocol Redirect to HTTPS, methods GET and HEAD, cache policy CachingOptimized. Order matters — specific patterns are checked before the default. - Settings: Alternate domain name (CNAME):
go.yourname.com. Custom SSL certificate: pick yours — and if the dropdown is empty, you have just met the us-east-1 rule; go back to Step 2 in Virginia. Default root object:index.html. Price class: All edge locations is fine; North America and Europe only is a touch cheaper on pay-as-you-go and irrelevant on the Free plan. Web Application Firewall: enable it if offered — the Free plan includes it. Create.
The distribution now says Deploying while CloudFront copies your configuration to every counter in the world. That genuinely takes a few minutes — it used to be fifteen, it is often under five now — and it is the one place in this build where "wait" is the right instruction. Meanwhile, do two small things. One: because the default root object only kicks in for the exact root URL, add a tiny CloudFront Function so that / reliably becomes /index.html before behaviors are matched — CloudFront → Functions → Create, paste this, publish, and attach it to the default behavior as a viewer request function:
function handler(event) {
var req = event.request;
if (req.uri === "/") { req.uri = "/index.html"; }
return req;
}
Two: go back into index.html and change the API constant at the top of the script from the execute-api address to an empty string — const API = ""; — and re-upload it to the bucket. The page will now call /links on its own domain, the same domain CloudFront routes to your API. This is the moment the CORS wall stops existing: there is no cross-origin request anymore, so there is nothing for the browser to block. Serverless architecture sometimes fixes things by deleting the problem, and this is one of those times.
Then the DNS record, exactly as in Path A but pointed at the front door: Route 53 → hosted zone → Create record, name go, type A, Alias on, Alias to CloudFront distribution, pick yours. Create a second identical record of type AAAA so IPv6 visitors get the same door. If you attached the bare domain too, make the same pair with an empty name. When the distribution reads Enabled, open https://go.yourname.com/ — there’s the page, padlocked, on your domain. Shorten a link. Click it. Watch the click count in DynamoDB tick up. Everything the project does now happens behind one name you own.
Lock the bucket back up — the part the last post couldn’t do
Remember the worried tone the S3 console took when we unchecked Block all public access last time? You can now give it what it wanted. With origin access control, CloudFront fetches from the bucket using its own signed identity, so the bucket itself no longer needs to be public. In S3 → your bucket → Permissions, delete the old public-read statement from the bucket policy (keep the one CloudFront gave you), turn Block all public access back on, and, under Properties, switch Static website hosting off — the website endpoint was the public door, and you have a better one now. Reload your page through CloudFront: still there. Try the old S3 website address: gone. That is the correct end state for a real site — storage private, CDN public — and it is worth knowing you got there in one build. If anything answers 403 in the process, the S3 403 untangler covers the OAC policy shape specifically.
The Free plan switch: how the DNS bill becomes $0 too
Here’s the reveal from the top of the post, with the details. In November 2025, AWS introduced flat-rate pricing plans for CloudFront: Free at $0, Pro at $15, Business at $200, Premium at $1,000 a month, each bundling the CDN with WAF, DDoS protection, a TLS certificate, CloudFront Functions, S3 storage credits, and Route 53 DNS — with no overage charges, ever, even during a traffic spike or an attack. The Free plan’s allowance is 100 GB of data and 1 million requests a month for one distribution, 5 WAF rules, a hosted zone with up to 50 records, and a 5 GB S3 storage credit. For a personal project that is not a starter tier; it is more than you will use.
To switch: open your distribution, find Manage plan (the console puts it on the distribution’s page), choose Free, and in the same panel attach your Route 53 hosted zone. Attaching is the step people miss, and it is the whole point: an attached zone’s $0.50 monthly fee, its records, and its query charges are covered by the plan. Unattached, it stays on pay-as-you-go and the 50 cents keeps arriving. The zone must be in the same account and must cover the domain the distribution serves, which yours does.
And the honest fine print, because a plan with "no overages" deserves a second look. If you blow past the allowance once — a link goes viral — AWS absorbs a spike of up to three times the allowance that month with no penalty and no bill. If you exceed it every month without upgrading, they don’t charge you; they may instead serve your traffic from fewer or more distant edge locations until you move up a tier. That is a slower site, not a surprise invoice, and for a hobby project the trade is entirely in your favor. Two features the plans don’t support are worth knowing before you need them: Lambda@Edge (the heavier cousin of CloudFront Functions) and, on the Free tier, access logging — Pro adds logs at $15. Neither matters for a shortener. If your project ever grows into a business, the moment to reconsider pay-as-you-go is when you’d be paying for a Business plan you don’t fully use.
Step 5 — Prove it works (without "just waiting")
Three commands replace every forum’s "wait 48 hours," and they run in PowerShell or any terminal. The first asks the internet what your name resolves to; the second asks who signed your certificate; the third asks your API, through your domain, for a redirect. If a step fails, the failure tells you which of the four jobs is broken — no guessing.
# 1. Does the name resolve, and to what? (Windows: nslookup go.yourname.com)
dig go.yourname.com +short
# 2. Is the certificate yours? Look for "subject=" with your domain, "issuer=" Amazon
curl -sv https://go.yourname.com/ -o /dev/null 2>&1 | grep -E "subject:|issuer:|HTTP/"
# 3. Does a short link redirect? Expect "HTTP/2 301" and "location: https://..."
curl -sI https://go.yourname.com/xK4b2n | grep -Ei "^HTTP|^location"
Command 1 empty? The name isn’t in DNS — the record is missing, in the wrong zone, or your registrar is still pointing at its own name servers (that one is propagation, and it’s the only case where waiting is correct). Command 2 shows a subject of *.cloudfront.net instead of your domain? CloudFront doesn’t know your name: the alternate domain name wasn’t added to the distribution, or the certificate wasn’t attached, or it lives outside us-east-1. Command 3 returns a 403 or a 404 where a 301 should be? The front door works and the origin behind it is unhappy — which brings us to the walls.
The seven walls — every error this build produces, and what each one means
First, the reassurance: if you hit one of these, your build is fine. Every one of them is a single setting, and they are so consistent across the years that I can list them like a menu. Find your symptom in the first column.
| What you see | What is actually happening | The fix |
|---|---|---|
| Certificate dropdown in CloudFront is empty | Certificate was requested outside us-east-1. CloudFront cannot see it and will not say so. | Switch region to N. Virginia, request again, validate, come back. (Jake’s four days.) |
| Certificate stuck in Pending validation for an hour+ | The validation CNAME isn’t published — never created, created in the wrong zone, or the registrar doubled your domain onto the record name. | Press Create records in Route 53, or check the record name at your registrar ends in exactly one copy of your domain. |
| CNAMEAlreadyExists when saving the distribution | That domain name is already attached to another CloudFront distribution — often an old test one, occasionally one in someone else’s account. | Remove it from the other distribution first. If you don’t own the other one, CloudFront has a DNS-based ownership check to move it; the docs walk through it. |
Page loads but every short link answers 403 Forbidden (JSON: {"message":"Forbidden"}) | Ethan’s envelope. CloudFront forwarded the visitor’s Host: go.yourname.com header to API Gateway, which only answers to its own execute-api name and refuses everything else. | Origin request policy on the API behavior: AllViewerExceptHostHeader. Not AllViewer. |
| Redirects work, but the click counter stops counting | CloudFront cached the 301. Counters are handing out the redirect from memory; your Lambda never hears about the clicks. The site looks perfect and your analytics silently die. | Cache policy on the API behavior: CachingDisabled. Redirects and API calls are not menu items; they must reach head office every time. |
| NET::ERR_CERT_COMMON_NAME_INVALID / "connection is not private" | DNS points at CloudFront, but the distribution doesn’t list your domain as an alternate name (or lists it with a certificate that doesn’t cover it), so it presents the default cloudfront.net certificate. | Add the alternate domain name and attach a certificate whose names include it — exact match or a wildcard at the same level. |
| Root URL answers 404 or an S3 "NoSuchKey"/"Route not found" | / is reaching the API (the default behavior) instead of the page, or the bucket has no index.html at its top level. | Default root object index.html, the tiny CloudFront Function above, and a behavior for /index.html pointing at the bucket. |
Two more that aren’t errors but feel like them. Changes to a distribution show Deploying for a few minutes and take effect gradually; refresh a couple of times before concluding something is broken. And if you re-upload index.html and still see the old page, that is CloudFront doing its job — the counters are holding the previous copy. CloudFront → your distribution → Invalidations → Create, path /*, clears them; the first thousand invalidation paths a month are free.
The bill, honestly: four traffic levels, priced
Same table format as last time, now with the domain layer added on top of the shortener’s own costs, us-east-1, August 2026. The shortener column comes straight from the project post; the new columns are what this post adds. A redirect is tiny — a few hundred bytes — so data transfer barely registers even at absurd click counts; the page itself is about 2 KB.
| Clicks this month | Shortener (from last post) | Domain (yearly ÷ 12) | CloudFront + Route 53 on the Free plan | Same, on pay-as-you-go instead | Total (Free plan) |
|---|---|---|---|---|---|
| Family & friends (hundreds) | $0.00 | ~$1.33 (.com at $16/yr) | $0.00 | $0.50 (hosted zone; CDN inside its always-free allowance) | ~$1.33 |
| 10,000 | ~$0.02 | ~$1.33 | $0.00 | $0.50 | ~$1.35 |
| 1,000,000 | ~$1.02 | ~$1.33 | $0.00 (right at the 1M-request allowance; a one-off spike to 3× is absorbed) | ~$1.50 (zone + ~$1 of HTTPS requests) | ~$2.35 |
| 10,000,000 | ~$12–19 | ~$1.33 | Free plan no longer fits every month — upgrade to Pro, $15 (10M requests, 50 TB, logging), still no overages | ~$10.50 (zone + ~$10 of requests; data still trivial) | ~$25–35 |
Two things to take from the last column. First, at every level a human being is likely to reach, the domain is the bill — $16 a year, and the cloud beneath it rounds to zero. Second, look at the crossover in the two CloudFront columns: below a million requests the Free plan wins outright; around ten million, honest pay-as-you-go ($10.50) is actually cheaper than Pro ($15), and Pro is buying you logging, more WAF rules, and the guarantee that a viral week cannot produce an invoice. That guarantee is worth $4.50 a month to most people who have ever read an AWS horror story, and worth nothing to someone who watches their budget alarm and doesn’t mind variability. Both are reasonable. What isn’t reasonable is the third option most tutorials quietly assume: paying for a certificate, a DNS service, and a CDN as three separate subscriptions, in 2026, for a site that fits in a free plan.
CloudFront vs Cloudflare: the other free front door, and when to pick it
Balance, as always. Cloudflare has offered a free DNS-plus-CDN-plus-certificate tier for a decade, sells domains at cost, and a great many small sites live there very happily — you could point a Cloudflare-hosted domain at your API Gateway custom domain from Path A and have a perfectly good result. The reason this post builds inside AWS is not that CloudFront is better in the abstract; it’s that your project is already here. CloudFront reaches your S3 bucket privately through origin access control, rides Amazon’s backbone to your API, attaches to the same IAM, the same budget alarm, the same console, and the Free plan now erases the one price advantage the other side had. One vendor, one bill, one set of permissions is a real simplification when you are learning. If you later run sites on several clouds, or want features like Cloudflare’s tunnels and workers, that’s a fine day to split DNS out. Today, keep the pieces together.
If you’re here for the certification
This post is unusually dense with exam material, so a signpost. Route 53 alias records versus CNAMEs, the reason the bare domain needs an alias, ACM’s us-east-1 requirement for CloudFront, origin access control for private S3, and cache versus origin-request policies are all core territory for the AWS Certified Solutions Architect – Associate, and the vocabulary (edge location, origin, distribution, hosted zone) shows up in Cloud Practitioner. If the AI side of the cloud is your target instead, the series hub holds the AI Practitioner and Machine Learning Engineer track that grew out of these tutorials. Either way, the difference between having read about an alias record and having created one at 11 p.m. because your padlock was red is the difference the exam is quietly testing for.
Tear it down — or keep it (this time there is one meter)
Last post ended with the rare line "keeping it costs the same as deleting it." This one has a small asterisk, and honesty means printing it: a domain renews once a year, and a hosted zone that isn’t attached to a Free plan bills $0.50 a month whether or not anything points at it. So if you’re done: disable the distribution, wait for it to finish deploying, delete it; delete the custom domain name in API Gateway; delete the hosted zone (Route 53 makes you delete every record except NS and SOA first — a stubbornness that has saved more domains than it has annoyed people); and, under Registered domains, turn auto-renew off if you don’t want the name next year. The certificate can stay; ACM charges nothing for it to exist. And the $1 alarm stays forever, as always.
If you’re keeping it — and a link shortener on your own domain is a genuinely useful thing to keep — the maintenance list is delightfully short: nothing. The certificate renews itself. The plan renews itself at $0. The domain renews at $16 and emails you first. Jake’s cousin has now printed a third batch of posters against a domain nobody can take away, and the whole operation costs her less per month than one of the posters.
Honest aside: what this build still doesn’t teach you
You clicked a firewall on; you did not write a single rule for it, and the Free plan’s five-rule limit means "block the obvious" is the ceiling. You enabled a CDN but cached exactly one file — the real art of CloudFront is deciding what to cache for how long, and a redirect service gives you no practice at it. You still have no logs on the Free tier, which means when something breaks at scale you are guessing; that is a Pro-plan feature or a CloudWatch story. And you are still clicking: every setting in this post is a thing a file could declare, and the day you have to rebuild this in a second account, you will wish it had. None of that shrinks what happened. You now own a name, understand which of four systems is failing when a padlock goes red, and have personally defeated the two checkboxes that account for most CloudFront-in-front-of-an-API support tickets ever filed. That is not beginner knowledge anymore.
The series’ next promise picks up the loudest gap in that list: you have built something real and put it on the internet, and you currently have no way of knowing when it breaks. Next stop: Amazon CloudWatch in plain English — the logs your Lambda has been writing all along, the metrics that show a problem before a user does, and the 2 a.m. alarm that costs $0. Priced honestly, as always, and linked from the hub the day it lands.
FAQ — custom domains and HTTPS on AWS, answered straight
How much does a custom domain with HTTPS cost on AWS?
The domain itself — about $16/year for a .com on Route 53 as of July 2026. The certificate (ACM) is free, and on CloudFront’s Free plan the CDN, WAF, DDoS protection, and your Route 53 hosted zone are $0/month. Without the plan, the hosted zone is $0.50/month.
Is the AWS SSL certificate really free?
Yes — public certificates from AWS Certificate Manager cost nothing and renew automatically when used with CloudFront, API Gateway, or load balancers. The catch: the private key never leaves AWS. An exportable certificate you can run elsewhere costs $7 ($79 for a wildcard).
Why does my ACM certificate not show up in CloudFront?
It was requested in a region other than us-east-1 (N. Virginia). CloudFront only reads certificates from that region, and the dropdown stays empty with no error. Switch to us-east-1, request again, validate, and it appears.
What is the difference between Route 53 and a registrar like GoDaddy or Namecheap?
Two jobs: selling the name (registration) and answering DNS queries (hosting the zone). Route 53 does both; so do most registrars. You can buy the name anywhere and host DNS in Route 53 by pointing the registrar at Route 53’s four name servers.
What is a Route 53 alias record and why not just use a CNAME?
An alias is Route 53’s pointer to an AWS resource (CloudFront, API Gateway, load balancers). Unlike a CNAME it is allowed at the bare domain (yourname.com), and queries to it are free. CNAMEs are fine for subdomains like go.yourname.com, forbidden at the apex by the DNS standard.
Does DNS really take 48 hours to propagate?
Only the one-time change of name servers at your registrar can take that long, and it usually finishes within an hour. Records you add inside Route 53 take effect in about a minute. If a padlock is red after an hour, something is misconfigured — waiting will not fix it.
Do I need CloudFront to put a custom domain on API Gateway?
No. API Gateway has its own custom domain names feature (Regional, free) that works with an ACM certificate in the API’s region and one DNS record. CloudFront is for putting the page and the API under one domain, adding caching, WAF, and DDoS protection.
Why does CloudFront return 403 Forbidden for my API Gateway origin?
CloudFront is forwarding the visitor’s Host header (your domain) to API Gateway, which only recognizes its own execute-api hostname. Set the behavior’s origin request policy to AllViewerExceptHostHeader.
Why did my click counter stop working after adding CloudFront?
CloudFront cached the redirect and is serving it from the edge, so your Lambda never sees the clicks. Use the CachingDisabled cache policy on the behavior that routes to the API.
What is the CloudFront Free plan and what does it include?
A $0/month flat-rate plan introduced in November 2025: one distribution with 100 GB and 1 million requests a month, WAF (5 rules), DDoS protection, a free TLS certificate, CloudFront Functions, a 5 GB S3 storage credit, and your Route 53 hosted zone (up to 50 records) when attached. No overage charges.
What happens if I exceed the Free plan’s allowance?
You are not billed. A one-off spike up to three times the allowance is absorbed; if you consistently exceed it without upgrading, AWS may serve your traffic from fewer or more distant edge locations. Pro ($15/month) raises the allowance to 10 million requests and 50 TB.
Is the CloudFront Free plan the same as the AWS free tier?
No. The flat-rate Free plan is a subscription you choose per distribution. Pay-as-you-go CloudFront has its own separate always-free allowance. You use one or the other for a given distribution; for a small site the Free plan is simpler because it also covers DNS and WAF.
How much does Route 53 cost?
$0.50 per hosted zone per month (first 25 zones), $0.40 per million standard queries, and queries to alias records pointing at AWS services are free. Attached to a CloudFront flat-rate plan, the zone’s fee and queries are covered.
Can I use a wildcard certificate?
Yes, and it’s free in ACM. Request *.yourname.com alongside yourname.com on one certificate and every subdomain you invent later is already covered. Validate it with DNS.
How do I make my S3 bucket private again after using CloudFront?
Use origin access control on the S3 origin, paste the bucket policy CloudFront generates, remove the old public-read statement, re-enable Block all public access, and turn static website hosting off. CloudFront keeps serving; the public S3 URL stops.
Why does my updated page not show after re-uploading to S3?
CloudFront is serving the cached copy. Create an invalidation for /* on the distribution; the first 1,000 invalidation paths per month are free.
What does CNAMEAlreadyExists mean?
The domain name is already attached as an alternate name on another CloudFront distribution — usually an old test one in your account. Remove it there first; if it belongs to another account, CloudFront’s DNS-based ownership process lets you move it.
CloudFront vs Cloudflare: which should I use?
Both have free tiers. If your project lives on AWS, CloudFront keeps one vendor, one bill, private S3 access through OAC, and a Free plan that now includes DNS and WAF. Cloudflare is a fine choice for multi-cloud setups or its own features like tunnels.
Can I keep the domain but delete everything else?
Yes. Delete the distribution, the API custom domain, and the hosted zone; the registered domain stays yours until it expires. Turn auto-renew off if you don’t want next year’s charge.
What are the CloudFront free tier limits?
On the flat-rate Free plan: 100 GB of data transfer and 1 million requests a month for one distribution, 5 WAF rules, a hosted zone with 50 records, and 5 GB of S3 credit — with no overage charges. Pay-as-you-go CloudFront keeps a separate always-free allowance of its own.
What do CloudFront 502 and 504 errors mean?
502 Bad Gateway: CloudFront reached your origin but didn’t like the answer — usually the origin’s certificate doesn’t match the origin domain name, or it returned something malformed. 504 Gateway Timeout: the origin took too long; behind API Gateway that means a Lambda that ran past the gateway’s ~30-second limit. Neither is a DNS problem, so don’t touch Route 53 for them.
Why is CloudFront blocking me, and what is cloudfront.net?
If a site you visit shows a "blocked by CloudFront" page, or a game or download comes from an address ending in cloudfront.net, that site runs on CloudFront and its firewall or geographic rules rejected your request — often a VPN exit, a country block, or rate limiting. It isn’t malware, and only that site’s owner can change the rule; a different network or turning the VPN off usually gets you through.
What are Route 53 routing policies?
Rules for how Route 53 answers when one name has several possible targets: simple (one answer), weighted (split traffic by percentage), latency (nearest region), failover (primary with a health-checked backup), geolocation and geoproximity (by where the visitor is), and multivalue (several healthy answers). This post only needs simple — one name, one CloudFront distribution.
Why is it called Route 53?
DNS runs on port 53, and the name nods at U.S. Route 66 — a highway that routes travelers. It is a DNS service that also sells domains, and it is global, not regional, which is why the console shows no region picker for it.
Why is my CloudFront invalidation not working?
Three usual reasons: the path is wrong (invalidations match the URL path exactly — /index.html and / are different entries; /* clears everything), the invalidation is still In progress (give it a minute or two), or your browser is caching locally — test with a private window or curl -I and look for the x-cache header, which says Hit or Miss from cloudfront.
CloudFront vs Global Accelerator: what’s the difference?
CloudFront caches and serves HTTP content at the edge — websites, APIs, files. Global Accelerator gives you two fixed IP addresses and routes any TCP or UDP traffic over the AWS network to your endpoints, with no caching — game servers, VoIP, non-HTTP apps. For a website or API, CloudFront; for raw sockets that need static IPs, Global Accelerator.
Does this appear on the AWS Solutions Architect exam?
Heavily. Alias versus CNAME, ACM’s us-east-1 rule for CloudFront, origin access control, cache and origin-request policies, and hosted-zone basics are all Solutions Architect – Associate material, with the vocabulary appearing in Cloud Practitioner.
Revision note. Written August 27, 2026 — the sixteenth stop in the series and the keeping of the promise the project post we made: the ugly execute-api address, replaced with a name you own. All prices checked against AWS’s pricing pages and the CloudFront flat-rate plan documentation on the day of writing (us-east-1; Route 53’s July 2026 domain price revision included). Consoles get redesigned, and CloudFront’s has been redesigned more than most — if a button in this post has moved, the answers to each setting are what matter and they have been stable for years; the contact page reaches me for fixes either way. And if your padlock is red right now and some forum has told you to wait two days: please don’t. Run the three commands above, find which of the four jobs is unhappy, and fix that one. It is almost never propagation, it is almost always a single setting, and you are almost certainly four minutes from done. Jake was.
