Getting headless Chrome to run on AWS Lambda Node

Today I needed to update a couple Lambda functions from the Node 8 runtime to use the Node 10.x runtime. These functions required headless Chrome because they are used to take screenshots. Unfortunately, moving from the Node 8 runtime to 10x runtime is not a simple as it sounds, because AWS have decided to change the Linux environment which now excludes some files that Chromium requires to run.

As a reminder to myself, and for anyone else who might find it useful, I thought I’d document my setup here in a blog post. This post will assume you have the Serverless CLI set up and successfully deploying to AWS.

To start, I am using the following utilities:

Set up a Lambda Layer

Since the Chromium binary is quite large we don’t want to have to deploy it as part of the function. We need to put it in a Layer and use the Layer in our function.

Download this pre-built layer from GitHub ( chrome_aws_lambda.zip ) which contains the Chromium binary, and the chrome-aws-lambda and puppeteer-core npm packages.

In the AWS Console create a new layer and upload the above zip file.

Copy the ARN for the Layer.

Configure Serverless

You will need to add a layers setting in serverless.yml config for your function with the ARN you previously copied:


1
2
3
4
5
6
7
functions:
  myFunctionName:
    handler: myFunctionHandler
    timeout: 30
    memorySize: 2048
    layers:
      - ADD_LAYER_ARN_HERE

Set up your handler

Now you can use Puppeteer in your handler via the chrome-aws-lambda module. You don’t need to npm install this module because it will automatically be included from the Layer:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const chromium = require("chrome-aws-lambda");

module.exports = async (event, context) => {
     try {
        const browser = await chromium.puppeteer.launch({
            headless: true,
            executablePath: await chromium.executablePath,
            args: chromium.args
        });

        const page = await browser.newPage();
        await page.goto("https://somewebsite.com");

        // ...do something, screenshot etc

        await browser.close();
    } catch (err) {
        console.log(err);
        // ...handle error
    }

    return {
        statusCode: 200,
        body: JSON.stringify({
            success: true
        })
    };
}

Hopefully that should be everything you need to have Chromium loaded via a Layer and running on Lambda Node 10.x.

Hero photo by Max LaRochelle on Unsplash.

Posted toAWS Javascript Lambda NodeJS