Serverless has been very popular for several years now. When we need very high performance it can be a very good alternative to traditional server solutions. Therefore, this time we will try to run CodeIgniter 4 in a serverless environment.
Installation
The first thing to do is to install the Serverless framework (if you don’t already have it). You can read how to do that here: https://bref.sh/docs/installation.html
Follow all the steps from the “Serverless” section and come back here.
If we already have the Serverless Framework installed and an AWS account configured, we can move on. Let’s create a sample project in CodeIgniter 4:
composer create-project codeigniter4/appstarter serverless-ci4
Inside our project, let’s install bref
, which will allow us to easily run our PHP project on Lambda function.
composer require bref/bref
Let’s initiate the project.
vendor/bin/bref init
And select the 0
option when asked about the type of apllication.
Configuration
First things first. We should adjust the serverless.yaml
file to our needs:
service: serverless-codeigniter4
provider:
name: aws
region: eu-central-1
runtime: provided.al2
memorySize: 512
plugins:
- ./vendor/bref/bref
functions:
api:
handler: public/index.php # point us to the CodeIgniter's index.php file
description: ''
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-81-fpm}
events:
- httpApi: '*'
# Exclude files from deployment
package:
patterns:
- '!node_modules/**'
- '!tests/**'
Now we can move on. CodeIgniter 4 requires the Intl
extension. By default, this extension is disabled, so we need to enable it.
To do this, we need to create a php.ini
file that will be loaded when the instance is launched.
In the root directory of our project, let’s create the following path/file: php/conf.d/php.ini
with the contents:
extension=intl
Let’s move on to CodeIgniter’s configuration settings, because there are a few things we need to change.
Let’s create a copy of the env
file under the name .env
. Now let’s edit the value for CI_ENVIRONMENT
and few others.
CI_ENVIRONMENT = development
app.indexPage = ''
app.uriProtocol = 'PATH_INFO';
We change the CI_ENVIRONMENT
just in case something goes wrong, so we can see the errors. Later we will go back to the production
value.
The change for the uriProtocol
is necessary so the Lambda could recognize our routing.
Next, we need to overwrite the paths for the session
(if we will use it) and cache
files. In the following example
we assume that we use a file handler for both the session and cache files.
// app/Config/Registrar.php
namespace App\Config;
use RuntimeException;
class Registrar
{
public static function App()
{
$isLambda = isset($_SERVER['LAMBDA_TASK_ROOT']);
if ($isLambda) {
$sessionPathDir = '/tmp/session';
if (! is_dir($sessionPathDir)) {
if (! mkdir($sessionPathDir, 0755, true) && ! is_dir($sessionPathDir)) {
throw new RuntimeException(sprintf('Directory "%s" cannot be created', $sessionPathDir));
}
}
return [
'sessionSavePath' => $sessionPathDir,
];
}
return [];
}
public static function Cache()
{
$isLambda = isset($_SERVER['LAMBDA_TASK_ROOT']);
if ($isLambda) {
$cachePathDir = '/tmp/cache';
if (! is_dir($cachePathDir)) {
if (! mkdir($cachePathDir, 0755, true) && ! is_dir($cachePathDir)) {
throw new RuntimeException(sprintf('Directory "%s" cannot be created', $cachePathDir));
}
}
return [
'file' => [
'storePath' => $cachePathDir
],
];
}
return [];
}
}
The last point will be to change the logging method so that the logs are available in CloudWatch
.
To do this, we will install a simple extension that will replace our default logger.
composer require bref/logger
Let’s edit the Services.php
file to start using the new logger.
// app/Config/Services.php
namespace Config;
use CodeIgniter\Config\BaseService;
use Bref\Logger\StderrLogger;
class Services extends BaseService
{
/**
* The Logger class is a PSR-3 compatible Logging class that supports
* multiple handlers that process the actual logging.
*
* @return StderrLogger
*/
public static function logger(bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('logger');
}
return new StderrLogger();
}
}
We can now upload our project. The first time deploy may take about 2 minutes.
serverless deploy
After navigating to the address that will be displayed to us in the console, we should see the standard landing page of CodeIgniter 4.
The last thing we should do is to update the CI_ENVIRONMENT
and baseURL
variables in the .env
file:
CI_ENVIRONMENT = production
app.baseURL = 'https://out-instance-number.execute-api.eu-central-1.amazonaws.com'
The value for baseURL
should be the value displayed to us after deployment in the console.
Now we should call serverless deploy
one more time and we are all set.
Of course, usually we won’t be serving entire websites, but rather providing an API. But if we come to run a full-fledged website, we should remember not to serve the static files through the Lambda function.
Fortunately, there are built-in solutions for this. I encourage you to study the documentation: https://bref.sh/docs/.
That would be it. We have a CodeIgniter 4 application served through the Lambda function - in other words: Serverless CodeIgniter 4.