From f32c5a86b6fc2db591c943255f7f733c0b8f3806 Mon Sep 17 00:00:00 2001 From: Lasalot <61053418+Lasalot@users.noreply.github.com> Date: Mon, 12 Aug 2024 10:32:16 +0200 Subject: [PATCH 1/6] Error handling 404 --- prerender-cloudfront.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/prerender-cloudfront.yaml b/prerender-cloudfront.yaml index afd4616..ff6ab38 100644 --- a/prerender-cloudfront.yaml +++ b/prerender-cloudfront.yaml @@ -138,8 +138,7 @@ Resources: Enabled: true CustomErrorResponses: - ErrorCode: 404 - ResponseCode: 200 - ResponsePagePath: /index.html + ResponseCode: 404 HttpVersion: http2 Origins: - CustomOriginConfig: From ead764836896d706bd652ea628a55403c446fde9 Mon Sep 17 00:00:00 2001 From: Lasalot <61053418+Lasalot@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:15:13 +0200 Subject: [PATCH 2/6] Added option for 404 handling --- prerender-cloudfront.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/prerender-cloudfront.yaml b/prerender-cloudfront.yaml index ff6ab38..2d22c07 100644 --- a/prerender-cloudfront.yaml +++ b/prerender-cloudfront.yaml @@ -139,6 +139,11 @@ Resources: CustomErrorResponses: - ErrorCode: 404 ResponseCode: 404 + # If you wish to respond with 200 even if the page is not existing + # CustomErrorResponses: + # - ErrorCode: 404 + # ResponseCode: 200 + # ResponsePagePath: /index.html HttpVersion: http2 Origins: - CustomOriginConfig: From ee1ac811761c5c41f2c861e5ef790e25a7f4bc45 Mon Sep 17 00:00:00 2001 From: lazokjacint Date: Mon, 10 Feb 2025 14:17:13 +0100 Subject: [PATCH 3/6] added AI bots --- prerender-cloudfront.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prerender-cloudfront.yaml b/prerender-cloudfront.yaml index 2d22c07..bcf8277 100644 --- a/prerender-cloudfront.yaml +++ b/prerender-cloudfront.yaml @@ -52,7 +52,7 @@ Resources: const user_agent = headers['user-agent']; const host = headers['host']; if (user_agent && host) { - var prerender = /googlebot|adsbot\-google|Feedfetcher\-Google|bingbot|yandex|baiduspider|Facebot|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|redditbot|applebot|whatsapp|flipboard|tumblr|bitlybot|skypeuripreview|nuzzel|discordbot|google page speed|qwantify|pinterestbot|bitrix link preview|xing\-contenttabreceiver|chrome\-lighthouse|telegrambot/i.test(user_agent[0].value); + var prerender = /googlebot|adsbot\-google|Feedfetcher\-Google|bingbot|yandex|baiduspider|Facebot|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|redditbot|applebot|whatsapp|flipboard|tumblr|bitlybot|skypeuripreview|nuzzel|discordbot|google page speed|qwantify|pinterestbot|bitrix link preview|xing\-contenttabreceiver|chrome\-lighthouse|telegrambot|Perplexity|OAI-SearchBot|ChatGPT|GPTBot|ClaudeBot|Amazonbot/i.test(user_agent[0].value); prerender = prerender || /_escaped_fragment_/.test(request.querystring); prerender = prerender && ! /\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)$/i.test(request.uri); if (prerender) { From 1c9c59b3ed6e85be438de2c1f5d2eaa924d80ec6 Mon Sep 17 00:00:00 2001 From: lazokjacint Date: Thu, 13 Feb 2025 10:17:13 +0100 Subject: [PATCH 4/6] added User agent to forwarded headers This is to make sure that Prerender serves the correct version of the pages to the bots. mobile version to mobile crawlers and desktop version to desktop crawlers --- prerender-cloudfront.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/prerender-cloudfront.yaml b/prerender-cloudfront.yaml index bcf8277..257d863 100644 --- a/prerender-cloudfront.yaml +++ b/prerender-cloudfront.yaml @@ -128,6 +128,7 @@ Resources: - "X-Prerender-Host" - "X-Prerender-Cachebuster" - "X-Query-String" + - "User-Agent" TargetOriginId: origin ViewerProtocolPolicy : allow-all LambdaFunctionAssociations: From 34f155430477b9586583dcdfdbeab62d90c03e2c Mon Sep 17 00:00:00 2001 From: Tranz9shko Date: Mon, 12 May 2025 17:09:54 +0200 Subject: [PATCH 5/6] Upgraded runtime to Node22; fixed AWS compatibility issues --- prerender-cloudfront.yaml | 162 ++++++++++++++++++++++++-------------- 1 file changed, 104 insertions(+), 58 deletions(-) diff --git a/prerender-cloudfront.yaml b/prerender-cloudfront.yaml index 257d863..23a998b 100644 --- a/prerender-cloudfront.yaml +++ b/prerender-cloudfront.yaml @@ -1,27 +1,27 @@ Parameters: + DeploymentName: + Description: Unique name used to create OAC and cache policy. + Type: String + PrerenderToken: Type: String + Description: Prerender.io token + Resources: - WebBucket: - Type: "AWS::S3::Bucket" - Properties: - AccessControl: PublicRead - WebsiteConfiguration: - ErrorDocument: index.html - IndexDocument: index.html + LambdaEdgeExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - - edgelambda.amazonaws.com - Action: - - sts:AssumeRole + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + - edgelambda.amazonaws.com + Action: + - sts:AssumeRole Policies: - PolicyName: logging PolicyDocument: @@ -44,28 +44,28 @@ Resources: Code: ZipFile: !Sub | - 'use strict'; - /* change the version number below whenever this code is modified */ - exports.handler = (event, context, callback) => { - const request = event.Records[0].cf.request; - const headers = request.headers; - const user_agent = headers['user-agent']; - const host = headers['host']; - if (user_agent && host) { - var prerender = /googlebot|adsbot\-google|Feedfetcher\-Google|bingbot|yandex|baiduspider|Facebot|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|redditbot|applebot|whatsapp|flipboard|tumblr|bitlybot|skypeuripreview|nuzzel|discordbot|google page speed|qwantify|pinterestbot|bitrix link preview|xing\-contenttabreceiver|chrome\-lighthouse|telegrambot|Perplexity|OAI-SearchBot|ChatGPT|GPTBot|ClaudeBot|Amazonbot/i.test(user_agent[0].value); - prerender = prerender || /_escaped_fragment_/.test(request.querystring); - prerender = prerender && ! /\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)$/i.test(request.uri); - if (prerender) { - headers['x-prerender-token'] = [{ key: 'X-Prerender-Token', value: '${PrerenderToken}'}]; - headers['x-prerender-host'] = [{ key: 'X-Prerender-Host', value: host[0].value}]; - headers['x-prerender-cachebuster'] = [{ key: 'X-Prerender-Cachebuster', value: Date.now().toString()}]; - headers['x-query-string'] = [{ key: 'X-Query-String', value: request.querystring}]; - } + 'use strict'; + /* change the version number below whenever this code is modified */ + exports.handler = (event, context, callback) => { + const request = event.Records[0].cf.request; + const headers = request.headers; + const user_agent = headers['user-agent']; + const host = headers['host']; + if (user_agent && host) { + var prerender = /googlebot|adsbot\-google|Feedfetcher\-Google|bingbot|yandex|baiduspider|Facebot|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|redditbot|applebot|whatsapp|flipboard|tumblr|bitlybot|skypeuripreview|nuzzel|discordbot|google page speed|qwantify|pinterestbot|bitrix link preview|xing\-contenttabreceiver|chrome\-lighthouse|telegrambot|Perplexity|OAI-SearchBot|ChatGPT|GPTBot|ClaudeBot|Amazonbot|integration-test/i.test(user_agent[0].value); + prerender = prerender || /_escaped_fragment_/.test(request.querystring); + prerender = prerender && ! /\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)$/i.test(request.uri); + if (prerender) { + headers['x-prerender-token'] = [{ key: 'X-Prerender-Token', value: '${PrerenderToken}'}]; + headers['x-prerender-host'] = [{ key: 'X-Prerender-Host', value: host[0].value}]; + headers['x-prerender-cachebuster'] = [{ key: 'X-Prerender-Cachebuster', value: Date.now().toString()}]; + headers['x-query-string'] = [{ key: 'X-Query-String', value: request.querystring}]; } - callback(null, request); - }; - Runtime: "nodejs14.x" - SetPrerenderHeaderVersion3: + } + callback(null, request); + }; + Runtime: "nodejs22.x" + SetPrerenderHeaderVersion1: Type: "AWS::Lambda::Version" Properties: FunctionName: @@ -102,17 +102,31 @@ Resources: } callback(null, request); }; - Runtime: "nodejs14.x" + Runtime: "nodejs22.x" RedirectToPrerenderVersion1: Type: "AWS::Lambda::Version" Properties: FunctionName: Ref: "RedirectToPrerender" Description: "RedirectToPrerender" - CloudFront: - Type: "AWS::CloudFront::Distribution" + + # Creates a new origin access control. The signing behavior "always" is the most common use case. + # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originaccesscontrol-originaccesscontrolconfig.html + CloudFrontOriginAccessControl: + Type: AWS::CloudFront::OriginAccessControl + Properties: + OriginAccessControlConfig: + Name: !Ref DeploymentName + OriginAccessControlOriginType: s3 + SigningBehavior: always + SigningProtocol: sigv4 + + CloudFrontDistribution: + Type: AWS::CloudFront::Distribution Properties: DistributionConfig: + Enabled: true + DefaultRootObject: index.html DefaultCacheBehavior: Compress: true # NOTE: we let cloudfront cache heavily the resurces of the SPA. Your deploy @@ -122,33 +136,65 @@ Resources: MinTTL: 31536000 DefaultTTL: 31536000 ForwardedValues: - QueryString: false + QueryString: true Headers: - "X-Prerender-Token" - "X-Prerender-Host" - "X-Prerender-Cachebuster" - "X-Query-String" - "User-Agent" - TargetOriginId: origin - ViewerProtocolPolicy : allow-all + TargetOriginId: thisS3Origin + ViewerProtocolPolicy: allow-all LambdaFunctionAssociations: - EventType: viewer-request - LambdaFunctionARN: !Join [ ":", [ !GetAtt [SetPrerenderHeader, Arn], !GetAtt [SetPrerenderHeaderVersion3, Version] ] ] + LambdaFunctionARN: !Join [ ":", [ !GetAtt [ SetPrerenderHeader, Arn ], !GetAtt [ SetPrerenderHeaderVersion1, Version ] ] ] - EventType: origin-request - LambdaFunctionARN: !Join [ ":", [ !GetAtt [RedirectToPrerender, Arn], !GetAtt [RedirectToPrerenderVersion1, Version] ] ] - Enabled: true - CustomErrorResponses: - - ErrorCode: 404 - ResponseCode: 404 - # If you wish to respond with 200 even if the page is not existing - # CustomErrorResponses: - # - ErrorCode: 404 - # ResponseCode: 200 - # ResponsePagePath: /index.html - HttpVersion: http2 + LambdaFunctionARN: !Join [ ":", [ !GetAtt [ RedirectToPrerender, Arn ], !GetAtt [ RedirectToPrerenderVersion1, Version ] ] ] Origins: - - CustomOriginConfig: - OriginProtocolPolicy: http-only - DomainName: !Select [2, !Split [ '/', !GetAtt [WebBucket, WebsiteURL]]] - Id: origin - PriceClass: PriceClass_100 + - DomainName: !GetAtt Bucket.DomainName + Id: thisS3Origin + OriginAccessControlId: !Ref CloudFrontOriginAccessControl + S3OriginConfig: + OriginAccessIdentity: "" + + # Creates a new S3 bucket with SSE and public access blocked. + # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html + Bucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - BucketKeyEnabled: true + ServerSideEncryptionByDefault: + SSEAlgorithm: AES256 + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + + # Creates a bucket policy giving OAC read-only access to the S3 bucket. + # https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html + BucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref Bucket + PolicyDocument: + Version: 2008-10-17 + Statement: + - Sid: AllowCloudFrontServicePrincipalReadOnly + Action: + - 's3:GetObject' + Effect: Allow + Principal: + Service: cloudfront.amazonaws.com + Resource: !Sub "${Bucket.Arn}/*" + Condition: + StringEquals: + AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution.Id}" + +Outputs: + CloudFrontDomain: + Description: URL of CloudFront distribution. + Value: !GetAtt CloudFrontDistribution.DomainName + From c28fdf65d022129cca3663e1cc97b4398e551458 Mon Sep 17 00:00:00 2001 From: Tranz9shko Date: Mon, 12 May 2025 17:11:36 +0200 Subject: [PATCH 6/6] Custom error codes example --- prerender-cloudfront.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prerender-cloudfront.yaml b/prerender-cloudfront.yaml index 23a998b..88c388c 100644 --- a/prerender-cloudfront.yaml +++ b/prerender-cloudfront.yaml @@ -126,6 +126,10 @@ Resources: Properties: DistributionConfig: Enabled: true + CustomErrorResponses: + - ErrorCode: 404 + ResponseCode: 404 + ResponsePagePath: /404.html DefaultRootObject: index.html DefaultCacheBehavior: Compress: true