Static Website with CDN#
A cost-effective, highly available static website using S3, CloudFront, Route53, and ACM — ideal for blogs, landing pages, documentation sites, and SPAs.
Architecture Overview#
┌─────────────────────────────────────┐
│ Route53 (DNS) │
│ www.example.com → CloudFront │
└────────────────┬────────────────────┘
│
┌────────────────▼────────────────────┐
│ CloudFront (CDN) │
│ • SSL termination (ACM cert) │
│ • HTTP → HTTPS redirect │
│ • Geo-restriction (if needed) │
│ • WAF integration │
└──┬────────────────────────────┬──────┘
│ │
┌────────▼────────┐ ┌─────────▼─────────┐
│ S3 Bucket │ │ S3 Bucket │
│ (Website) │ │ (Logs/Access) │
│ example.com │ │ logs.example.com │
│ • index.html │ │ │
│ • error.html │ │ • CloudFront logs │
│ • assets/* │ │ • S3 access logs │
└─────────────────┘ └───────────────────┘Services Used#
| Service | Purpose | Configuration |
|---|---|---|
| S3 | Static file hosting | Static website hosting disabled (use OAC), versioning enabled |
| CloudFront | CDN + edge caching | Price Class 100 (US/Europe), HTTP/2, compression enabled |
| Route53 | DNS management | Alias record to CloudFront distribution |
| ACM | SSL/TLS certificate | us-east-1 (required for CloudFront), auto-renewal |
| WAF | Security | Rate limiting, geo-blocking (if needed) |
| CodePipeline | CI/CD | Deploy on git push, invalidate CloudFront cache |
Key Design Decisions#
| Decision | Rationale |
|---|---|
| OAC over OAI | Origin Access Control is the newer, more secure method for S3-CloudFront |
| Static hosting disabled | Forces all access through CloudFront (no direct S3 access) |
| S3 versioning enabled | Allows rollback to previous versions on deployment issues |
| CloudFront Price Class 100 | Cheapest option — serves US/Europe only |
| Custom error page | SPA support — route 404 errors to index.html |
| Compression enabled | CloudFront compresses files automatically (gzip/brotli) |
Step-by-Step Deployment#
# 1. Create S3 bucket
aws s3 mb s3://www.example.com
aws s3 website s3://www.example.com --index-document index.html --error-document error.html
# 2. Block public access (OAC only)
aws s3api put-public-access-block \
--bucket www.example.com \
--public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
# 3. Request SSL certificate (via AWS Console or CLI)
aws acm request-certificate \
--domain-name www.example.com \
--validation-method DNS \
--region us-east-1
# 4. Create CloudFront distribution with OAC
# (via Console — OAC requires Console or CloudFormation)
# 5. Update Route53 record
aws route53 change-resource-record-sets \
--hosted-zone-id ZONE_ID \
--change-batch '{"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "www.example.com",
"Type": "A", "AliasTarget": { "HostedZoneId": "Z2FDTNDATAQYW2", "DNSName": "d123.cloudfront.net", "EvaluateTargetHealth": false }
}
}]
}'
# 6. Upload website files
aws s3 sync ./build/ s3://www.example.com/
# 7. Invalidate CloudFront cache
aws cloudfront create-invalidation \
--distribution-id E123ABC \
--paths "/*"Real-World Use Case#
Scenario: A SaaS company needs a marketing website with blog, docs, and pricing page — global audience, low budget.
Costs:
| Component | Estimated Cost |
|---|---|
| S3 storage (10GB) | ~$0.23/month |
| CloudFront (100GB transfer) | ~$8.50/month |
| Route53 hosted zone | ~$0.50/month |
| ACM certificate | Free |
| Total | ~$9.23/month |
Performance: CloudFront caches at 400+ edge locations globally — pages load in <100ms for most users.
✅ Key Exam Takeaways#
- CloudFront + S3 = the standard pattern for static websites
- OAC (Origin Access Control) is the modern, secure way to restrict S3 access
- Never make S3 buckets public — always use CloudFront OAC
- ACM certificates for CloudFront must be in us-east-1
- Custom error page = SPA support (redirect 404s to index.html)
- CloudFront supports HTTP/2 and compression — enable both