Setting up AWS CloudFront CDN
CloudFront is AWS's CDN with 450+ PoPs, tightly integrated (S3, EC2, ALB, API Gateway). Use when already on AWS or need fine control over caching and routing.
Create Distribution via Terraform
resource "aws_cloudfront_distribution" "main" {
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
price_class = "PriceClass_200"
origin {
domain_name = aws_lb.main.dns_name
origin_id = "alb-origin"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
ordered_cache_behavior {
path_pattern = "/assets/*"
target_origin_id = "s3-assets"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = true
cache_policy_id = aws_cloudfront_cache_policy.assets.id
}
default_cache_behavior {
target_origin_id = "alb-origin"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
compress = true
cache_policy_id = aws_cloudfront_cache_policy.pages.id
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.main.arn
ssl_support_method = "sni-only"
}
}
resource "aws_cloudfront_cache_policy" "assets" {
name = "assets-immutable"
min_ttl = 31536000
max_ttl = 31536000
default_ttl = 31536000
parameters_in_cache_key_and_forwarded_to_origin {
cookies_config { cookie_behavior = "none" }
headers_config { header_behavior = "none" }
query_strings_config { query_string_behavior = "none" }
enable_accept_encoding_brotli = true
enable_accept_encoding_gzip = true
}
}
CloudFront Functions for edge logic
// Add security headers on every request
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: 'SAMEORIGIN' };
return response;
}
Cache invalidation on deploy
aws cloudfront create-invalidation \
--distribution-id $DISTRIBUTION_ID \
--paths "/*"
// Laravel: invalidate on article publish
use Aws\CloudFront\CloudFrontClient;
class ArticlePublished {
public function handle(Article $article): void {
$client = new CloudFrontClient(['version' => 'latest']);
$client->createInvalidation([
'DistributionId' => config('services.cloudfront.distribution_id'),
'InvalidationBatch' => [
'Paths' => ['Quantity' => 1, 'Items' => ["/blog/{$article->slug}"]],
'CallerReference' => (string) now()->timestamp,
],
]);
}
}
Origin Shield
Additional cache layer between edge and origin. Reduces origin load 10-50x:
origin {
origin_shield {
enabled = true
origin_shield_region = "eu-central-1"
}
}
Setup time: 1-2 days with Terraform, including ACM certificate.







