Web applications on AWS Lambda

To run HTTP APIs and websites on AWS Lambda, Bref runs your code using PHP-FPM. That means PHP applications can run on Lambda just like on any other PHP hosting platform.

That's great: we can use our favorite framework as usual, like Laravel or Symfony.

If you are interested in the details, know that AWS Lambda can react to HTTP requests via API Gateway. On Lambda, Bref forwards API Gateway requests to PHP-FPM via the FastCGI protocol (just like Apache or Nginx).

Every code we deploy on AWS Lambda is called a "Function". Do not let this name confuse you: in this chapter, we do deploy HTTP applications in a Lambda Function.

In the Lambda world, an HTTP application is a function that is called by a request and returns a response. Good news: this is exactly what our PHP applications do.

Setup

Below is a minimal serverless.yml configuration to deploy an HTTP application:

service: app
provider:
    name: aws
    runtime: provided.al2
plugins:
    - ./vendor/bref/bref
functions:
    app:
        handler: index.php
        layers:
            - ${bref:layer.php-74-fpm}
        events:
            - httpApi: '*'

To create it automatically, run vendor/bin/bref init and select "Web application".

Handler

The handler is the file that will be invoked when an HTTP request comes in.

It is the same file that is traditionally configured in Apache or Nginx. In Symfony and Laravel this is usually public/index.php but it can be anything.

functions:
    app:
        handler: public/index.php

Runtime

For web apps, the runtime (aka layer) to use is the FPM runtime (php-74-fpm):

functions:
    app:
        layers:
            - ${bref:layer.php-74-fpm}

To learn more check out the runtimes documentation.

Routing

On AWS Lambda there is no Apache or Nginx. API Gateway acts as the webserver.

The simplest API Gateway configuration is to send all incoming requests to our application:

        events:
            - httpApi: '*'

Assets

Lambda and API Gateway are only used for executing code. Serving assets via PHP does not make sense as this would be a waste of resources and money.

Deploying a website and serving assets (e.g. CSS, JavaScript, images) is covered in the "Website assets" documentation.

In some cases however, you will need to serve images (or other assets) via PHP. One example would be if you served generated images via PHP. In those cases, you need to read the Binary requests and responses section below.

Binary requests and responses

By default API Gateway does not support binary HTTP requests or responses like images, PDF, binary files… To achieve this, you need to enable the option for binary media types in serverless.yml as well as define the BREF_BINARY_RESPONSES environment variable:

provider:
    # ...
    apiGateway:
        binaryMediaTypes:
            - '*/*'
    environment:
        BREF_BINARY_RESPONSES: '1'

This will make API Gateway support binary file uploads and downloads, and Bref will automatically encode responses to base64 (which is what API Gateway now expects).

Be aware that the max upload and download size is 6MB. For larger files, use AWS S3. An example is available in Serverless Visually Explained.

Context access

Lambda context

Lambda provides information about the invocation, function, and execution environment via the lambda context.

Bref exposes the Lambda context in the $_SERVER['LAMBDA_INVOCATION_CONTEXT'] variable as a JSON-encoded string. Here is an example to retrieve it:

$lambdaContext = json_decode($_SERVER['LAMBDA_INVOCATION_CONTEXT'], true);

Request context

API Gateway integrations can add information to the HTTP request via the request context. This is the case, for example, when using AWS Cognito authentication on API Gateway.

Bref exposes the request context in the $_SERVER['LAMBDA_REQUEST_CONTEXT'] variable as a JSON-encoded string. Here is an example to retrieve it:

$requestContext = json_decode($_SERVER['LAMBDA_REQUEST_CONTEXT'], true);

Cold starts

AWS Lambda automatically destroys Lambda containers that have been unused for 10 minutes. Warming up a new container can take some time, especially if your application is large. This delay is called cold start.

To mitigate cold starts for HTTP applications, you can periodically send an event to your Lambda including a {warmer: true} key. Bref recognizes this event and immediately responds with a Status: 100 without executing your code.

You can set up such events using AWS CloudWatch (read this article for more details):

        events:
            - httpApi: '*'
            - schedule:
                rate: rate(5 minutes)
                input:
                    warmer: true

You can learn more how AWS Lambda scales and runs in the Serverless Visually Explained course.