CloudFront CDN Guide
Configure Amazon CloudFront for global content delivery, including distributions, cache behaviors, Lambda@Edge, security, and performance optimization.
Prerequisites
- Understanding of HTTP caching headers (Cache-Control, ETag)
- Familiarity with S3 and/or ALB as origin servers
- Basic understanding of DNS
What is CloudFront
Amazon CloudFront is a global content delivery network (CDN) that accelerates the delivery of websites, APIs, video streams, and other web assets by caching content at edge locations around the world. CloudFront has over 600 points of presence (PoPs) across 100+ cities in 50+ countries. When a user requests content, CloudFront serves it from the nearest edge location rather than fetching it from your origin server every time, reducing latency from hundreds of milliseconds to single-digit milliseconds for cached content.
CloudFront is more than a simple cache. It provides DDoS protection (integrated with AWS Shield), web application firewall integration (AWS WAF), SSL/TLS termination, HTTP/2 and HTTP/3 support, real-time logging, edge compute (Lambda@Edge and CloudFront Functions), and origin failover. It integrates natively with S3, Application Load Balancers, API Gateway, MediaStore, and any HTTP origin including on-premises servers.
CloudFront uses a pay-per-use model with no minimum commitments. You pay for data transfer out to the internet, HTTP/HTTPS requests, and optional features like real-time logging, field-level encryption, and edge compute. For many workloads, CloudFront actuallyreduces your total cost because it offloads traffic from your origin servers and S3 data transfer from CloudFront is free.
Data Transfer Savings with CloudFront
Data transfer from S3 to CloudFront is free. Data transfer from CloudFront to the internet is cheaper than direct data transfer from S3 to the internet ($0.085/GB for CloudFront vs $0.09/GB for S3 in the US). This means using CloudFront in front of S3 is often cheaper than serving directly from S3, even ignoring the performance benefits. For origins behind an ALB, data transfer from the ALB to CloudFront within the same region is also free.
Distribution Configuration
A CloudFront distribution is the primary resource that defines how content is delivered. It specifies one or more origins (where content comes from), cache behaviors (how different URL patterns are handled), and global settings like SSL certificate, price class, and logging. Creating a distribution takes 5-10 minutes as CloudFront propagates the configuration to all edge locations.
Resources:
WebDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Comment: "Production web application"
DefaultRootObject: index.html
HttpVersion: http2and3
PriceClass: PriceClass_100 # US, Canada, Europe only (cheapest)
# Origins - where CloudFront fetches content
Origins:
- Id: S3StaticAssets
DomainName: !GetAtt AssetsBucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: ""
OriginAccessControlId: !Ref S3OAC
- Id: APIBackend
DomainName: !GetAtt ApplicationLoadBalancer.DNSName
CustomOriginConfig:
HTTPSPort: 443
OriginProtocolPolicy: https-only
OriginSSLProtocols:
- TLSv1.2
OriginCustomHeaders:
- HeaderName: X-Custom-Header
HeaderValue: !Ref SecretHeaderValue
# Default behavior (static assets from S3)
DefaultCacheBehavior:
TargetOriginId: S3StaticAssets
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: !Ref StaticAssetsCachePolicy
Compress: true
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
# Additional behaviors for specific paths
CacheBehaviors:
- PathPattern: "/api/*"
TargetOriginId: APIBackend
ViewerProtocolPolicy: https-only
CachePolicyId: !Ref APICachePolicy
OriginRequestPolicyId: !Ref APIOriginRequestPolicy
AllowedMethods:
- GET
- HEAD
- OPTIONS
- PUT
- POST
- PATCH
- DELETE
- PathPattern: "/static/*"
TargetOriginId: S3StaticAssets
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # CachingOptimized managed policy
Compress: true
# Custom error pages
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html # SPA fallback
ErrorCachingMinTTL: 10
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
ErrorCachingMinTTL: 10
# SSL certificate
ViewerCertificate:
AcmCertificateArn: !Ref Certificate
SslSupportMethod: sni-only
MinimumProtocolVersion: TLSv1.2_2021
Aliases:
- www.example.com
- example.com
# Enable WAF
WebACLId: !GetAtt WebACL.ArnPrice Classes
| Price Class | Edge Locations | Use Case |
|---|---|---|
| PriceClass_100 | US, Canada, Europe, Israel | North American/European audience only |
| PriceClass_200 | + Asia, Middle East, Africa | Global audience, excluding South America & Oceania |
| PriceClass_All | All edge locations worldwide | Truly global audience |
Origins & Origin Groups
An origin is the source of the content that CloudFront distributes. CloudFront supports several origin types: S3 buckets, Application Load Balancers, API Gateway endpoints, MediaStore containers, Lambda function URLs, and any custom HTTP/HTTPS server. Each distribution can have up to 25 origins.
S3 Origins with Origin Access Control
When using S3 as an origin, you should use Origin Access Control (OAC)to restrict direct access to the S3 bucket. With OAC, the S3 bucket policy only allows requests from CloudFront, preventing users from bypassing CloudFront by accessing the S3 URL directly. OAC replaces the older Origin Access Identity (OAI) mechanism and supports all S3 features including server-side encryption with KMS.
Resources:
# Origin Access Control
S3OAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: S3-OAC
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
# S3 bucket policy allowing CloudFront access
AssetsBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref AssetsBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: AllowCloudFrontServicePrincipal
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub "${AssetsBucket.Arn}/*"
Condition:
StringEquals:
AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${WebDistribution}"Origin Groups for Failover
Origin groups provide automatic origin failover. You define a primary origin and a secondary origin within a group. If the primary origin returns specific HTTP error codes (like 500, 502, 503, 504) or times out, CloudFront automatically routes the request to the secondary origin. This is useful for serving static fallback pages from S3 when your application origin is unhealthy, or for cross-region failover between two ALBs.
Multi-Region Origin Failover
For high-availability applications, create an origin group with your primary region's ALB as the primary origin and your secondary region's ALB as the failover origin. If the primary region goes down, CloudFront automatically routes requests to the secondary region. This provides sub-minute failover without waiting for DNS changes (which can take minutes to propagate). Combine this with Route 53 health checks for a complete multi-region DR strategy.
Cache Behaviors & Policies
Cache behaviors control how CloudFront handles requests for different URL patterns. Each behavior specifies which origin to use, what to cache, how long to cache it, and which HTTP methods to allow. The default cache behavior handles all requests that do not match any specific path pattern.
CloudFront uses three types of policies to control caching and origin requests:Cache policies define what goes into the cache key (which determines cache hits vs misses), origin request policies define what is forwarded to the origin, and response headers policies control headers added to responses.
Resources:
# Cache policy for static assets (aggressive caching)
StaticAssetsCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: StaticAssets-CachePolicy
DefaultTTL: 86400 # 1 day
MaxTTL: 31536000 # 1 year
MinTTL: 3600 # 1 hour minimum
ParametersInCacheKeyAndForwardedToOrigin:
EnableAcceptEncodingGzip: true
EnableAcceptEncodingBrotli: true
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: none
# Cache policy for API responses (short caching)
APICachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: API-CachePolicy
DefaultTTL: 0 # No caching by default
MaxTTL: 300 # Max 5 minutes
MinTTL: 0
ParametersInCacheKeyAndForwardedToOrigin:
EnableAcceptEncodingGzip: true
EnableAcceptEncodingBrotli: true
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Authorization # Different cache entries per auth token
QueryStringsConfig:
QueryStringBehavior: all # Include all query strings in cache key
# Origin request policy for API (forward everything to origin)
APIOriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
Name: API-OriginRequestPolicy
CookiesConfig:
CookieBehavior: all
HeadersConfig:
HeaderBehavior: allViewerAndWhitelistCloudFront
Headers:
- CloudFront-Viewer-Country
- CloudFront-Is-Mobile-Viewer
QueryStringsConfig:
QueryStringBehavior: all
# Response headers policy (security headers)
SecurityHeadersPolicy:
Type: AWS::CloudFront::ResponseHeadersPolicy
Properties:
ResponseHeadersPolicyConfig:
Name: SecurityHeaders
SecurityHeadersConfig:
StrictTransportSecurity:
AccessControlMaxAgeSec: 31536000
IncludeSubdomains: true
Override: true
ContentTypeOptions:
Override: true
FrameOptions:
FrameOption: DENY
Override: true
XSSProtection:
ModeBlock: true
Protection: true
Override: true
ReferrerPolicy:
ReferrerPolicy: strict-origin-when-cross-origin
Override: true
ContentSecurityPolicy:
ContentSecurityPolicy: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
Override: trueCache Key Design Is Critical
Everything included in the cache key creates a separate cache entry. Including too many elements (all headers, all cookies, all query strings) results in poor cache hit ratios because every unique combination creates a separate cached response. Include only the parameters that actually affect the response. For example, if your API response varies by Authorization header but not by User-Agent, include onlyAuthorization in the cache key. The origin request policy can forward additional headers to the origin without including them in the cache key.
Lambda@Edge & CloudFront Functions
CloudFront supports two types of edge compute that run your code at CloudFront edge locations: Lambda@Edge and CloudFront Functions. Both let you modify requests and responses as they flow through CloudFront, but they differ significantly in capabilities, performance, and cost.
| Feature | CloudFront Functions | Lambda@Edge |
|---|---|---|
| Runtime | JavaScript (ECMAScript 5.1) | Node.js, Python |
| Execution location | All 600+ edge locations | 13 regional edge caches |
| Max execution time | 1 ms | 5s (viewer) / 30s (origin) |
| Max memory | 2 MB | 128-3008 MB |
| Max package size | 10 KB | 50 MB (250 MB with layers) |
| Network access | No | Yes |
| File system access | No | Yes (/tmp) |
| Request body access | No | Yes |
| Trigger points | Viewer request, Viewer response | Viewer request, Viewer response, Origin request, Origin response |
| Cost | $0.10 per million invocations | $0.60 per million invocations + duration |
CloudFront Functions Examples
// CloudFront Function: URL rewrite for SPA routing
// Trigger: Viewer Request
function handler(event) {
var request = event.request;
var uri = request.uri;
// If the URI has a file extension, serve it as-is
if (uri.includes('.')) {
return request;
}
// For all other paths, serve index.html (SPA routing)
request.uri = '/index.html';
return request;
}
// CloudFront Function: Add security headers
// Trigger: Viewer Response
function handler(event) {
var response = event.response;
var headers = response.headers;
headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubDomains; preload' };
headers['x-content-type-options'] = { value: 'nosniff' };
headers['x-frame-options'] = { value: 'DENY' };
headers['x-xss-protection'] = { value: '1; mode=block' };
headers['referrer-policy'] = { value: 'strict-origin-when-cross-origin' };
return response;
}
// CloudFront Function: Redirect www to non-www
// Trigger: Viewer Request
function handler(event) {
var request = event.request;
var host = request.headers.host.value;
if (host.startsWith('www.')) {
return {
statusCode: 301,
statusDescription: 'Moved Permanently',
headers: {
location: { value: 'https://' + host.replace('www.', '') + request.uri }
}
};
}
return request;
}Lambda@Edge Example
// Lambda@Edge: JWT authentication at the edge
// Trigger: Viewer Request
// Region: Must be deployed in us-east-1
import jwt from "jsonwebtoken";
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----`;
export const handler = async (event: any) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
// Skip auth for public paths
if (request.uri.startsWith("/public/") || request.uri === "/health") {
return request;
}
const authHeader = headers.authorization?.[0]?.value;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return {
status: "401",
statusDescription: "Unauthorized",
headers: {
"content-type": [{ key: "Content-Type", value: "application/json" }],
"www-authenticate": [{ key: "WWW-Authenticate", value: "Bearer" }],
},
body: JSON.stringify({ error: "Missing or invalid authorization header" }),
};
}
try {
const token = authHeader.replace("Bearer ", "");
const decoded = jwt.verify(token, PUBLIC_KEY, {
algorithms: ["RS256"],
}) as { sub: string; email: string };
// Pass user info to origin via custom headers
request.headers["x-user-id"] = [{ key: "X-User-Id", value: decoded.sub }];
request.headers["x-user-email"] = [{ key: "X-User-Email", value: decoded.email }];
return request;
} catch (error) {
return {
status: "403",
statusDescription: "Forbidden",
headers: {
"content-type": [{ key: "Content-Type", value: "application/json" }],
},
body: JSON.stringify({ error: "Invalid token" }),
};
}
};Choose CloudFront Functions First
CloudFront Functions are 6x cheaper, run at all 600+ edge locations (vs 13 regional caches for Lambda@Edge), and have sub-millisecond execution time. Use CloudFront Functions for simple request/response manipulation: URL rewrites, header manipulation, redirects, and cache key normalization. Use Lambda@Edge only when you need network access (calling external APIs), longer execution time, access to the request body, or origin request/response triggers.
Security & Access Control
CloudFront provides multiple layers of security: SSL/TLS encryption, AWS WAF integration, AWS Shield (DDoS protection), signed URLs and cookies (restrict access to content), Origin Access Control (prevent direct origin access), and geo-restriction.
Signed URLs and Signed Cookies
Signed URLs and signed cookies restrict access to content served through CloudFront. A signed URL is valid for a specific resource and time period: the URL includes an expiration timestamp and a cryptographic signature. Signed cookies work similarly but apply to multiple resources (all files matching a pattern).
import { getSignedUrl } from "@aws-sdk/cloudfront-signer";
// Generate a signed URL for premium content
function generateSignedUrl(resourcePath: string, expiresInSeconds: number): string {
const url = `https://cdn.example.com${resourcePath}`;
const keyPairId = "K2XXXXXXXXXX"; // CloudFront public key ID
const privateKey = process.env.CLOUDFRONT_PRIVATE_KEY!;
const signedUrl = getSignedUrl({
url,
keyPairId,
privateKey,
dateLessThan: new Date(Date.now() + expiresInSeconds * 1000).toISOString(),
});
return signedUrl;
}
// Generate a signed URL for a video stream
const videoUrl = generateSignedUrl("/premium/video-course-101.mp4", 3600); // 1 hour
console.log("Signed URL:", videoUrl);
// https://cdn.example.com/premium/video-course-101.mp4?Expires=...&Signature=...&Key-Pair-Id=...Geo-Restriction
CloudFront supports geographic restrictions using either an allowlist (serve content only to specific countries) or a blocklist (block specific countries). Geo-restriction is based on the viewer's country, determined by their IP address using a geolocation database. This is useful for content licensing restrictions or regulatory compliance.
SSL/TLS & Custom Domains
CloudFront supports custom domain names (CNAMEs) with SSL/TLS certificates from AWS Certificate Manager (ACM). Certificates for CloudFront must be provisioned in theus-east-1 region. CloudFront supports SNI (Server Name Indication), which means multiple distributions can share edge IP addresses, and dedicated IP addresses for legacy clients that do not support SNI.
# Request an ACM certificate (must be in us-east-1 for CloudFront)
aws acm request-certificate \
--domain-name "example.com" \
--subject-alternative-names "*.example.com" \
--validation-method DNS \
--region us-east-1
# After DNS validation, the certificate is issued automatically
# Create a Route 53 alias record pointing to CloudFront
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "www.example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d1234567890.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}]
}'HTTP/3 with QUIC
CloudFront supports HTTP/3 (based on QUIC protocol), which provides faster connection establishment, improved performance on lossy networks (mobile), and built-in encryption. Enable HTTP/3 by setting HttpVersion: http2and3 in your distribution config. CloudFront automatically negotiates the best protocol with the client. Clients that support HTTP/3 use it, while others fall back to HTTP/2 or HTTP/1.1.
Cache Invalidation Strategies
Cache invalidation removes cached content from CloudFront edge locations before its TTL expires. Invalidation is necessary when you update content and need users to see the new version immediately. However, invalidation should be a last resort, not a routine operation: it is slow (takes 1-2 minutes to propagate globally), expensive (free for the first 1,000 paths/month, then $0.005/path), and indicates a caching strategy that could be improved.
Invalidation vs Versioned URLs
| Approach | How It Works | Speed | Cost |
|---|---|---|---|
| Invalidation | POST /api/distributions/DIST_ID/invalidations | 1-2 minutes | $0.005/path after 1,000 free |
| Versioned URLs | Include hash in filename: app.a1b2c3.js | Instant (new URL = cache miss) | Free |
| Short TTL | Set Cache-Control: max-age=60 | Automatic (after TTL expires) | Free (but more origin requests) |
# Invalidate specific paths
aws cloudfront create-invalidation \
--distribution-id E1234567890 \
--paths "/index.html" "/api/config.json"
# Invalidate all content (expensive for large sites)
aws cloudfront create-invalidation \
--distribution-id E1234567890 \
--paths "/*"
# Check invalidation status
aws cloudfront list-invalidations \
--distribution-id E1234567890 \
--query 'InvalidationList.Items[0].{Id:Id, Status:Status}'Prefer Versioned URLs Over Invalidation
The best caching strategy uses versioned URLs (content-hashed filenames) for all static assets and short TTLs for dynamic content. With versioned URLs likeapp.a1b2c3d4.js, every deployment creates new filenames that are automatically cache misses. The old files remain cached until they expire naturally, and the new files are fetched from the origin on first request. This approach is instant, free, and eliminates the need for cache invalidation entirely. Most build tools (webpack, Vite, Next.js) generate content-hashed filenames by default.
Real-Time Logs & Monitoring
CloudFront provides two logging mechanisms: standard logs (delivered to S3 in batch every few minutes) and real-time logs (delivered to Kinesis Data Streams within seconds). Standard logs are free (you pay only for S3 storage), while real-time logs cost $0.01 per million log lines.
Key CloudWatch Metrics
| Metric | Description | Alarm Threshold |
|---|---|---|
Requests | Total number of requests | Anomaly detection for traffic spikes |
BytesDownloaded | Data transferred to viewers | Anomaly detection for unexpected volume |
4xxErrorRate | Percentage of 4xx responses | > 5% |
5xxErrorRate | Percentage of 5xx responses | > 1% |
TotalErrorRate | Overall error rate | > 5% |
CacheHitRate | Percentage of cache hits | < 80% (investigate cache policy) |
OriginLatency | Time for origin to respond | p99 > 5 seconds |
# Enable standard logging to S3
aws cloudfront update-distribution \
--id E1234567890 \
--distribution-config '{
"Logging": {
"Enabled": true,
"Bucket": "my-cf-logs.s3.amazonaws.com",
"Prefix": "cdn-logs/",
"IncludeCookies": false
}
}'
# Create a real-time log configuration
aws cloudfront create-realtime-log-config \
--name production-realtime-logs \
--sampling-rate 100 \
--fields "timestamp" "c-ip" "cs-uri-stem" "sc-status" "cs-method" \
"time-taken" "x-edge-result-type" "x-edge-response-result-type" \
--end-points '{
"StreamType": "Kinesis",
"KinesisStreamConfig": {
"RoleARN": "arn:aws:iam::123456789012:role/CloudFrontRealtimeLogRole",
"StreamARN": "arn:aws:kinesis:us-east-1:123456789012:stream/cf-realtime-logs"
}
}'Cost Optimization & Best Practices
CloudFront costs consist of data transfer out, HTTP/HTTPS requests, and optional features. Several strategies can significantly reduce your CloudFront bill while maintaining or improving performance.
Cost Optimization Strategies
Choose the right price class. If your audience is primarily in North America and Europe, PriceClass_100 is significantly cheaper thanPriceClass_All. Users outside the covered regions can still access your content; they are just served from the nearest available edge location, which may be farther away.
Enable compression. CloudFront can automatically compress text-based content (HTML, CSS, JavaScript, JSON) using gzip or Brotli before delivering it to viewers. This reduces data transfer by 60-80% for compressible content. Enable compression in your cache behavior settings and ensure your origin supports theAccept-Encoding header.
Maximize cache hit ratio. A higher cache hit ratio means fewer origin requests, which reduces both origin load and data transfer costs. Optimize your cache key to include only parameters that affect the response. Normalize URLs (lowercase, remove trailing slashes) using CloudFront Functions to prevent duplicate cache entries.
Use CloudFront Security Savings Bundle. If you use AWS WAF with CloudFront, the Security Savings Bundle offers up to 30% savings by committing to a fixed monthly spend for 1 year.
Monitor and optimize with CloudFront reports. The CloudFront console provides cache statistics, popular objects, top referrers, and viewer reports. Use these to identify low-hit-ratio paths, large uncached objects, or unexpected traffic patterns.
Avoid Wildcard Invalidations in CI/CD
A common anti-pattern is running aws cloudfront create-invalidation --paths "/*" after every deployment. This invalidates your entire cache, forcing CloudFront to re-fetch everything from the origin. This increases origin load, increases latency for users (cache misses), and costs $0.005 per path if you exceed 1,000 invalidation paths per month. Instead, use content-hashed filenames for static assets and invalidate only the specific dynamic files that changed (like /index.html).
Complete CloudFront Checklist
Security: Enable HTTPS (redirect HTTP to HTTPS), use TLS 1.2+, enable AWS Shield Standard (free, automatic), configure AWS WAF for application protection, use Origin Access Control for S3 origins, and add security headers via response headers policy.
Performance: Enable HTTP/2 and HTTP/3, enable Brotli and gzip compression, optimize cache key design, use versioned URLs for static assets, configure origin timeouts and keep-alive, and consider Lambda@Edge for dynamic personalization.
Reliability: Configure origin groups for failover, set up CloudWatch alarms for error rates, enable standard logging for troubleshooting, and test your distribution with geographic and device-based testing.
S3 Storage Classes: Optimizing Your CloudFront OriginRoute 53 DNS Patterns: Custom Domains for CloudFrontKey Takeaways
- 1CloudFront delivers content from 450+ edge locations worldwide for low-latency access.
- 2Origin Access Control (OAC) securely restricts S3 bucket access to CloudFront only.
- 3Cache behaviors allow different caching rules per URL path pattern.
- 4CloudFront Functions run at edge for lightweight request/response manipulation.
- 5Lambda@Edge provides full Node.js/Python runtime for complex edge logic.
- 6Signed URLs and signed cookies control access to premium or private content.
Frequently Asked Questions
What is the difference between CloudFront Functions and Lambda@Edge?
How do I invalidate the CloudFront cache?
What is Origin Access Control (OAC)?
How much does CloudFront cost?
Can CloudFront serve dynamic content?
Written by CloudToolStack Team
Cloud engineers and architects with hands-on experience across AWS, Azure, and GCP. We write guides based on real-world production patterns, not just documentation rewrites.
Disclaimer: This guide is for educational purposes. Cloud services change frequently; always refer to official documentation for the latest information. AWS, Azure, and GCP are trademarks of their respective owners.