Running Laravel on AWS Lambda
Learn how to create serverless Laravel applications by deploying them to AWS Lambda.
Prerequisites
Before deploying to AWS Lambda, you will need:
- An AWS account
Install Node JS and serverless CLI
Download and import the Nodesource GPG key
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
Create deb repository
NODE_MAJOR=18
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
Run Update and Install
sudo apt-get update
sudo apt-get install nodejs -y
Install the serverless
CLI using NPM
npm install -g serverless
Update Package Lists
sudo apt-get update
Install PHP and Required Extensions
sudo apt install php libapache2-mod-php php-mbstring php-xmlrpc php-soap php-gd php-xml php-cli php-zip php-bcmath php-curl php-tokenizer php-json
Install Composer
Downloads and installs Composer globally. Create Laravel Project:
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer
Create A sample Laraval Project
Uses Composer to create a new Laravel project named "serverless-laravel"
composer create-project laravel/laravel serverless-laravel
cd to serverless-laravel
install Bref and its Laravel integration
composer require bref/bref bref/laravel-bridge --update-with-dependencies
create a serverless.yml
configuration file
php artisan vendor:publish --tag=serverless-config
connect the serverless to your AWS account
connect the serverless CLI to your AWS account via AWS access and secret key keys
Create AWS access and secret keys by following bref.sh
documentation https://bref.sh/docs/setup/aws-keys,
Adding keys
serverless config credentials --provider aws --key <key> --secret <secret>
Deploy
serverless deploy
Using RDS as the database
Edit the .env
configuration file to set up the database connection.Also, Make sure Lambda has access to this Database;
DB_CONNECTION=mysql
DB_HOST=<host url>
DB_PORT=3306
DB_DATABASE=<database_name>
DB_USERNAME=<user>
DB_PASSWORD=<password>
Deploying for production
composer install --prefer-dist --optimize-autoloader --no-dev
Stages
Serverless Framework has a concept of stages (environments). We can deploy the same application multiple times in completely separated environments
serverless deploy --stage=prod
Automating deployments
If you are using CodePipeline you can use this in AWS CodeBuild as buildspec.yml
version: 0.2
phases:
install:
runtime-versions:
nodejs: 18
php: 8.2
commands:
- npm install -g serverless
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- composer install --prefer-dist --optimize-autoloader --no-dev
build:
commands:
- serverless deploy --stage=prod
Note: Make sure the AWS code build has permission (Role) attached to it so the code build is allowed to deploy.
Modify the IAM Role of CodeBuild and add this Policy, this is a Minimal AWS policy that allows to deployment of a serverless application using the Serverless Framework.
{
"Statement": [
{
"Action": [
"apigateway:*",
"cloudformation:CancelUpdateStack",
"cloudformation:ContinueUpdateRollback",
"cloudformation:CreateChangeSet",
"cloudformation:CreateStack",
"cloudformation:CreateUploadBucket",
"cloudformation:DeleteStack",
"cloudformation:DeleteChangeSet",
"cloudformation:Describe*",
"cloudformation:EstimateTemplateCost",
"cloudformation:ExecuteChangeSet",
"cloudformation:Get*",
"cloudformation:List*",
"cloudformation:UpdateStack",
"cloudformation:UpdateTerminationProtection",
"cloudformation:ValidateTemplate",
"dynamodb:CreateTable",
"dynamodb:DeleteTable",
"dynamodb:DescribeTable",
"dynamodb:DescribeTimeToLive",
"dynamodb:UpdateTimeToLive",
"ec2:AttachInternetGateway",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:CreateInternetGateway",
"ec2:CreateNetworkAcl",
"ec2:CreateNetworkAclEntry",
"ec2:CreateRouteTable",
"ec2:CreateSecurityGroup",
"ec2:CreateSubnet",
"ec2:CreateTags",
"ec2:CreateVpc",
"ec2:DeleteInternetGateway",
"ec2:DeleteNetworkAcl",
"ec2:DeleteNetworkAclEntry",
"ec2:DeleteRouteTable",
"ec2:DeleteSecurityGroup",
"ec2:DeleteSubnet",
"ec2:DeleteVpc",
"ec2:Describe*",
"ec2:DetachInternetGateway",
"ec2:ModifyVpcAttribute",
"events:DeleteRule",
"events:DescribeRule",
"events:ListRuleNamesByTarget",
"events:ListRules",
"events:ListTargetsByRule",
"events:PutRule",
"events:PutTargets",
"events:RemoveTargets",
"iam:AttachRolePolicy",
"iam:CreateRole",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:DetachRolePolicy",
"iam:GetRole",
"iam:PassRole",
"iam:PutRolePolicy",
"iot:CreateTopicRule",
"iot:DeleteTopicRule",
"iot:DisableTopicRule",
"iot:EnableTopicRule",
"iot:ReplaceTopicRule",
"kinesis:CreateStream",
"kinesis:DeleteStream",
"kinesis:DescribeStream",
"lambda:*",
"logs:CreateLogGroup",
"logs:DeleteLogGroup",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:FilterLogEvents",
"logs:GetLogEvents",
"logs:PutSubscriptionFilter",
"logs:TagResource",
"logs:DeleteSubscriptionFilter",
"s3:CreateBucket",
"s3:DeleteBucket",
"s3:DeleteBucketPolicy",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListAllMyBuckets",
"s3:ListBucket",
"s3:PutBucketNotification",
"s3:PutBucketPolicy",
"s3:PutBucketTagging",
"s3:PutBucketWebsite",
"s3:PutEncryptionConfiguration",
"s3:PutObject",
"sns:CreateTopic",
"sns:DeleteTopic",
"sns:GetSubscriptionAttributes",
"sns:GetTopicAttributes",
"sns:ListSubscriptions",
"sns:ListSubscriptionsByTopic",
"sns:ListTopics",
"sns:SetSubscriptionAttributes",
"sns:SetTopicAttributes",
"sns:Subscribe",
"sns:Unsubscribe",
"states:CreateStateMachine",
"states:DeleteStateMachine",
"states:TagResource"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
}