Note: please first test your app with our quick and simple all-in-one solution here: https://github.com/sanfrancesco/prerendercloud-server before going through this Lambda@Edge+CloudFront setup process. Once that's debugged and working the way you want it, come back here to configure Lambda@Edge+CloudFront. This will save you hours of headache because debugging/iterating with Cloudfront/Lambda/S3 is slow.
4-minute YouTube video walk-through (2024-07-10 update: AWS UI/UX has slightly changed since video but the video is still accurate): https://youtu.be/SsMNQ3EaNZ0
TL;DR:
npm install
and run: CLOUDFRONT_DISTRIBUTION_ID=yourDistributionId make deploy
(set yourDistributionId to what was created in step 2)full guidance below or in video:
<img src="https://img.youtube.com/vi/SsMNQ3EaNZ0/sddefault.jpg"
alt="4min how-to set up lambda@edge for pre-rendering" width="240" height="180" border="10" />
Server-side rendering (pre-rendering) via Lambda@Edge for single-page apps hosted on CloudFront with an s3 origin. It forwards requests to Headless-Render-API.com to be pre-rendered using a headless Chrome browser.
This is a serverless project with a make deploy
command that:
viewerRequest
, originRequest
, originResponse
)Read more:
Start with a new test bucket and CloudFront distribution before modifying your production account:
(it'll be quick because you'll be using the defaults with just 1 exception)
*
for *
)That's all you need. Now just wait a few minutes for the CloudFront DNS to propogate.
Note, you will not be creating a CloudFront "custom error response" that redirects 404s to index.html, and if you already have one, then remove it - because this project uploads a Lambda@Edge function that replaces that functionality (if you don't remove it, this project won't work).
$ git clone https://github.com/sanfrancesco/prerendercloud-lambda-edge.git
Node v20 (it works with node as low as v12 but aws lambda requires latest version of nodejs), and npm
$ npm install
Edit handler.js and set your headless-render-api.com API token (cmd+f for prerenderToken
)
note: Headless-Render-API.com was previously known as Prerender.cloud (rebranded 2022-05-01)
e.g. botsOnly
, removeTrailingSlash
in handler.js
(this step is only necessary if you are using an existing CloudFront distribution)
If you're using an existing CloudFront distribution, you need to remove this feature.
It has to be removed because it prevents the execution of the viewer-request function. This project replicates that functionality (see caveats)
viewer-request
function from executing).s3:ListBucket
permission to CloudFront user(this step is only necessary if you want 404s to work)
Since we can't use the "custom error response", and we're implementing it ourselves, this permission is neccessary for CloudFront+Lambda@Edge to return a 404 for a requested file that doesn't exist (only non HTML files will return 404, see caveats below). If you don't add this, you'll get 403 forbidden instead.
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::CHANGE_THIS_TO_YOUR_BUCKET_NAME_FROM_STEP_1/*",
"arn:aws:s3:::CHANGE_THIS_TO_YOUR_BUCKET_NAME_FROM_STEP_1"
]
If you're not editing an IAM policy specifically, the UI/UX checkbox for this in the S3 interface is, for the bucket, under the "Permissions" tab, "List Objects"
You can modify the content of the 404 page in handler.js
git pull
from this repo)$ CLOUDFRONT_DISTRIBUTION_ID=whateverYourDistributionIdIs make deploy
caveat: note that headless-render-api.com has a 5-minute server cache that you can disable, see disableServerCache
in handler.js
Visit a URL associated with your CloudFront distribution. It will take a few seconds for the first request (because it is pre-rendered on the first request). If for some reason the pre-render request fails or times out, the non-pre-rendered request will be cached.
See logs in CloudWatch in region closest to where you made the request from (although the function is deployed to us-east-1, it is replicated in all regions).
To view logs from command line:
CloudWatchLogsReadOnlyAccess
$ pip install awslogs
( https://github.com/jorgebastida/awslogs )
AWS_REGION=us-west-2 awslogs get -s '1h' /aws/lambda/us-east-1.Lambda-Edge-Prerendercloud-dev-viewerRequest
AWS_REGION=us-west-2 awslogs get -s '1h' /aws/lambda/us-east-1.Lambda-Edge-Prerendercloud-dev-originRequest
AWS_REGION
to whatever region is closest to where you physically are since that's where the logs will be)Sign in to headless-render-api.com web app and you'll see the last few requests made for your API key.
$ make destroy
will attempt to remove the Lambda@Edge functions - but as of Nov 2017, AWS still doesn't allow deleting "replicated functions" - in which case, just unnassociate them from your CloudFront distribution until delete functionality works.
This also means if you attempt to delete and recreate the functions, it will fail - so you'll need to change the name in serverless.yml and deploy.js (just append a v2)
You can also sign into AWS and go to CloudFormation and manually remove things.
prerender-cache-duration
of something longer than the default of 5 minutes (300) - like 1 week (604800)./some-special-file.html
even if /some-special-file.html
exists on your origin
blacklistPaths
option (see handler.js)<meta name="prerender-status-code" content="301">
to initiate a redirect, your CloudFront TTL must be zero, otherwise CloudFront will cache the body/response and return status code 200 with the body from the redirected pathSimply update serverless.yaml to the latest or whatever you prefer and re-deploy: make deploy
make deploy
command and look for errors