Running a Symfony application on AWS Lambda (Part 1)

Navid Hosseini
7 min readNov 25, 2023

In the traditional realm of web development, deploying a PHP application often entailed setting up and managing a web server infrastructure, such as Apache or Nginx, to serve as the backbone for your application. However, in the age of serverless computing, a paradigm shift has occurred, ushering in the possibility of running your PHP application without the need for conventional servers.

This revolutionary transformation is made possible, in part, by the ingenious Bref.sh project, which opens the door to serverless PHP application deployment on AWS Lambda. In this article, we will embark on a journey that challenges the status quo of server-based hosting by demonstrating how to deploy a Symfony application on AWS Lambda using Bref.sh. The exciting part? You won’t need to provision, configure, or manage traditional servers. With this cutting-edge approach, your Symfony application will seamlessly operate in the cloud, dynamically scaling to meet your application’s demands, without the burden of maintaining infrastructure.

By the end of this article, you will have a comprehensive understanding of how to leverage AWS Lambda and Bref.sh to run your Symfony application serverlessly, opening up new horizons for efficient, cost-effective, and hassle-free web application deployment.

Advantages:

Running a PHP application on AWS Lambda offers several advantages and benefits:

  1. Scalability: AWS Lambda is designed to automatically scale with the incoming traffic. When your PHP application experiences a surge in traffic, Lambda can quickly and effortlessly accommodate the load by running multiple instances of your application in parallel. This auto-scaling capability ensures that your application remains responsive even during traffic spikes, without you having to worry about provisioning or managing additional servers.
  2. Cost-Efficiency: Traditional server-based hosting often requires you to pay for server resources continuously, whether or not your application is actively handling requests. In contrast, AWS Lambda charges you only for the compute time your application consumes, measured in milliseconds. This “pay-as-you-go” model can result in significant cost savings, especially for applications with varying or intermittent workloads. You won’t incur unnecessary infrastructure costs during idle periods.
  3. Serverless Simplicity: With AWS Lambda, you delegate the operational responsibilities to AWS. You no longer need to manage servers, apply security patches, or handle server maintenance tasks. AWS Lambda takes care of the underlying infrastructure, allowing you to focus on writing code and building features. This simplifies the development and deployment process, reducing operational overhead.
  4. Event-Driven Architecture: AWS Lambda is inherently designed for event-driven architecture. It can be easily integrated with other AWS services and external event sources. This is particularly advantageous for building serverless microservices and orchestrating complex workflows. Your PHP application can respond to a wide range of events, such as changes in data stored in Amazon S3, updates in a database, or HTTP requests, making it a versatile solution for various use cases.

Disadvantages:

While AWS Lambda offers several advantages for hosting PHP applications, it’s important to be aware of the potential challenges and disadvantages:

  1. Read-only filesystem: One notable limitation of using AWS Lambda for hosting Symfony applications is its read-only file system (Except /tmp folder). Lambda's file system is designed to be immutable, making it unsuitable for storing dynamic files, cache data, or any content that requires write access. Symfony applications typically rely on read-write file storage for caching and managing dynamic content, necessitating a separate strategy for handling these essential components outside of Lambda's read-only space.
  2. Cold Starts: One of the primary issues with AWS Lambda is the concept of “cold starts.” When a Lambda function is triggered after a period of inactivity, it may experience a delay as it initializes. For PHP applications, this delay can impact response times, especially for low-traffic applications. You can mitigate this by using provisioned concurrency or warming strategies.
  3. Execution Time Limit: AWS Lambda imposes a maximum execution time limit (usually 15 minutes). If your PHP application has long-running processes or tasks, you may need to refactor your code or use other AWS services like Step Functions to handle such tasks.
  4. Stateless Nature: AWS Lambda functions are designed to be stateless. This can be a challenge for PHP applications that rely on maintaining a state across multiple requests, as each function execution is independent. You’ll need to manage state externally, possibly using databases or cache solutions.
  5. Dependency Management: Managing dependencies for your PHP application in a Lambda environment can be challenging. You may need to package all dependencies and libraries with your deployment package, which can lead to larger deployment artifacts and longer deployment times.

Setting up and Running the project:

In this tutorial, we’ll guide you through the process of deploying a Symfony application on AWS Lambda using PHP 8.2 and Symfony 6.3. You can start by cloning the project from the following repository: sf-lambda.

Setup Serveless:

To begin, ensure you have the Serverless framework installed. If you don’t have it yet, you can install it globally using npm:

npm install -g serverless

For detailed information about Serverless and its configuration, refer to the official documentation.

AWS account and credential:

Before deploying your Symfony application on AWS Lambda, you need an AWS account and configured credentials on your machine. If you don’t have an AWS account, you can create one at AWS. Follow these instructions to create and set up your AWS credentials.

Once you have your access keys, configure Serverless by running:

serverless config credentials --provider aws --key "key" --secret "secret”

Alternatively, you can set them as environment variables:

export AWS_ACCESS_KEY_ID=key
export AWS_SECRET_ACCESS_KEY=secret

Install Bref packages into your Symfony project:

Assuming you have a well-configured Symfony project on your machine, install the Bref packages using Composer:

composer require bref/bref bref/symfony-bridge --update-with-dependencies

This command will install bref and bref/symfony-bridge packages with all needed 3rd party packages. If you are using Symfony flex, this command will also apply all needed configurations to your project. One of that files is the serverless.yml that will be created after this. This default serverless file have all necessary configurations with two default functions, one function for web part and another for console commands.

...
functions:
# This function runs the Symfony website/API
web:
handler: public/index.php
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-82-fpm}
events:
- httpApi: '*'
# This function let us run console commands in Lambda
console:
handler: bin/console
timeout: 120 # in seconds
layers:
- ${bref:layer.php-82} # PHP
- ${bref:layer.console} # The "console" layer
...

The important part that you may consider, is the bref layers versions that is used in the serverless.yml file and revise it to the correct version of PHP that you are using in you local. So for example if you are using PHP version 8.2.* then you should use the bref:layer.php-82-fpm and bref:layer.php-82 for you functions.

The Symfony framework by default use filesystem in the project directory for some purposes like cache, logs and etc but in the Lamda the filesystem is readonly except the /tmp folder. Ofcourse it is possible to change default cache and logs directory in a Symfony app to another folder but to prevent unwanted result the Bref will do it for you easily. You just need to revise the src/Kernel.php file from its default to this:

<?php

namespace App;

use Bref\\SymfonyBridge\\BrefKernel;
use Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait;
class Kernel extends BrefKernel
{
use MicroKernelTrait;
}

Actually instead of extending Kernel from the Symfony\Component\HttpKernel\Kernel it should extend from Bref\SymfonyBridge\BrefKernel and BrefKernel will take care of readonly filesystem in Lambda and will change cache and log directory to /tmp folder.

Deploy project to AWS Lamda:

Before deploying the the project into the AWS Lambda you should know the deploy command will upload a zip file of the project directory to the AWS. So be cautious about sensitive data. Exclude unnecessary files and folders in the serverless.yml file:

package:
patterns:
# Excluded files and folders for deployment
- '!assets/**'
- '!node_modules/**'
- '!public/build/**'
- '!tests/**'
- '!var/**'
# If you want to include files and folders that are part of excluded folders,
# add them at the end
- 'var/cache/prod/**'
- 'public/build/entrypoints.json'
- 'public/build/manifest.json'

You should be also aware of the region that your app will be deployed on it. The region is us-east-1 by default but you can change it to the region and zone that is appropriate for you:

...

provider:
# The AWS region in which to deploy (us-east-1 is the default)*
region: us-east-1
...

Also be sure all dependencies has been installed. you can ignore dev libraries:

composer install --no-dev

Warmup the cache for prod environment:

bin/console cache:clear --env=prod

And finally deploy your project:

serverless deploy

The deploy command will create a new CloudFormation stack for your project based on functions that you have defined in the serverless.yml :

As you can see it will create a random web API link for your web function which by accessing it you can see the first page of the website which is now hosted on AWS Lambda. Each change that you make in the app, you can easily run the deploy and apply your changes into the server again.

You can find the files of this tutorial in my Github page.

As we conclude the initial phase of deploying a Symfony application on AWS Lambda, we’ve laid the foundation for a serverless architecture that brings unparalleled scalability and cost-efficiency. The journey, however, doesn’t end here. In the upcoming second part of this series, we delve into more advanced concepts crucial for a comprehensive deployment.

In the next installment, we’ll explore advanced topics such as deploying assets in a serverless environment and harnessing the power of Redis as the cache for our Symfony application. These intricacies are pivotal for optimizing performance and ensuring a seamless user experience.

By combining the serverless capabilities of AWS Lambda with the robust Symfony framework, we’re not only redefining how applications are hosted but also unlocking a realm of possibilities for efficient, scalable, and dynamic web development. Join us in the next part as we navigate through the intricacies of advanced deployment strategies, enhancing our Symfony application’s capabilities in the serverless landscape.

--

--