PHP Quickstart Guides
Laravel Quickstart Guide
This guide will show you how to set up a PHP app using the Laravel framework and MySQL or PostgreSQL. This guide leverages Dockerfile Deployment.
This guide is designed for Laravel 8 and later, although it may work with earlier versions as well.
Create an App
To create an App, use the Dashboard or the aptible apps:create
CLI command:
# Set or substitute $APP_HANDLE with the name of your choice
aptible apps:create "$APP_HANDLE"
Until you push code and trigger a build, Aptible uses this App as a placeholder.
The aptible apps:create
command will return the new App's Git Remote when it completes. Copy it, as you'll need it later.
Going forward, we'll refer to the App's handle as $APP_HANDLE
, and its git remote as $GIT_REMOTE
.
Provision a Database
Use the Dashboard or the aptible db:create
CLI command to provision a 10GB Database:
- PostgreSQL:
aptible db:create "$DB_HANDLE" --type postgresql
- MySQL:
aptible db:create "$DB_HANDLE" --type mysql
Make sure you set or substitute $DB_HANDLE
with the name of your choice.
The aptible db:create
command will return a connection string when complete. This is a Database Credential for the new Database. You'll need it later to configure your App.
Going forward, we'll refer to this connection string as the $DATABASE_URL
.
Note
Databases are only reachable from within your Stack's internal network.
This means your Containers will be able to connect to your database, but if you want to connect from your workstation, you'll need to use a Database Tunnel.
Add a Dockerfile
A Dockerfile is a text file that contains the commands you would otherwise execute manually to build a Docker image. Aptible uses the resulting Image to run Containers for your App.
Your Dockerfile must adhere to the following rules to work with Dockerfile Deployment:
- The file must be named
Dockerfile
, starting with a capital letter, and no extension. - It must be placed at the root of the repository.
- It must be committed to version control.
Here is a sample Dockerfile for a Laravel app. This will install your dependencies via Composer, and configure your app's public folder to be served by Apache:
FROM php:8.0-apache
WORKDIR /app
# Install dependencies
# git/zip/unzip is required by composer
# libpq-dev is required by PostgreSQL driver
RUN apt-get update && \
apt-get install -y --no-install-recommends git zip unzip libpq-dev && \
rm -rf /var/lib/apt/lists/* && \
# Install php extensions
docker-php-ext-install pdo_pgsql pdo_mysql && \
# Install composer (https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md)
composer_install='install-composer.php' && \
expected_checksum="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" && \
php -r "copy('https://getcomposer.org/installer', '${composer_install}');" && \
actual_checksum="$(php -r "echo hash_file('sha384', '${composer_install}');")" && \
([ "$expected_checksum" = "$actual_checksum" ] || (echo "ERROR: Invalid installer checksum" && exit 1)) && \
php "$composer_install" --install-dir '/usr/local/bin' --filename composer && \
rm "$composer_install"
# Install dependencies via composer
ADD composer.json composer.lock ./
RUN composer install --no-dev --no-ansi --no-interaction --no-scripts --no-autoloader
# Add application files and install scripts and autoloader
ADD . ./
RUN composer install --no-dev --no-ansi --no-interaction
# The apache www-data user must be able to access project storage and cache
RUN chown -R www-data:www-data storage/ bootstrap/cache/ && \
# Link public dir to apache public dir
rm -rf /var/www/html && ln -s /app/public /var/www/html
Connect to the Database from your App
When deploying an app on Aptible, it is recommended to pass the Database's connection info, as well as any passwords or other sensitive configuration values, to your containers as environment variables via the App's Configuration. To do so with your Laravel app, you'll need to make a few tweaks to your config/database.php
file.
First, add the following function at the very top of the file:
// NOTE: this function *must not* throw exceptions, otherwise Laravel
// will fail to boot. So, instead of throwing exceptions, we just
// return an intentionally invalid (empty) configuration if
// DATABASE_URL is not set.
function generateAptibleConnection() {
if (getenv('DB_CONNECTION') !== 'aptible') {
// If the DB_CONNECTION is not Aptible, then this won't be used,
// and we should just bail out.
return [];
}
$raw_url = getenv('DATABASE_URL');
if (!$raw_url) {
error_log('DB_CONNECTION is aptible, but DATABASE_URL is not set!');
return [];
}
$url = parse_url($raw_url);
$aptibleConnection = [
'host' => $url["host"],
'port' => $url["port"],
'username' => $url["user"],
'password' => $url["pass"],
'database' => substr($url["path"], 1),
'charset' => 'utf8',
'prefix' => '',
];
$scheme = $url["scheme"];
if ($scheme === "mysql") {
// NOTE: The options below are required to run on Aptible, because
// Aptible enforces SSL on connections to your MySQL database and
// uses a self-signed certificate for MySQL (the latter due to
// MySQL's poor security record). If you remove them, your app will
// fail to connect to MySQL with an Access Denied error.
$aptibleConnection['driver'] = 'mysql';
$aptibleConnection['collation'] = 'utf8_unicode_ci';
$aptibleConnection['options'] = [
PDO::MYSQL_ATTR_SSL_CIPHER => 'DHE-RSA-AES256-SHA',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
];
} elseif ($scheme === "postgresql") {
$aptibleConnection['driver'] = 'pgsql';
$aptibleConnection['schema'] = 'public';
} else {
error_log("DB_CONNECTION is aptible and DATABASE_URL is set, but the scheme '$scheme' is invalid!");
return [];
}
return $aptibleConnection;
}
Then, add the following key / value pair in your connections
array:
'connections' => [
'aptible' => generateAptibleConnection(),
// Some other connections you already have
]
Once again, commit the changes.
Automate Database Migrations
Your app probably expects you to run database migrations upon deploy to ensure your app code and database are in sync.
You can tell Aptible to run your migrations by adding a .aptible.yml
file in your repository.
The file must be named .aptible.yml
exactly, found at the root of your repository, and committed to version control for Aptible to detect it.
Here is a sample .aptible.yml
file to automate database migrations:
before_release:
- php artisan migrate
Bring it all together
At this point, you're almost ready to deploy.
All that is left to do is put the pieces together by configuring your App to point it to your Database, then you'll be ready to push your code to Aptible.
To add the required environment variables, use the aptible config:set
command as documented below. Make sure you set or substitute $APP_HANDLE
and $DATABASE_URL
with their proper values.
aptible config:set --app "$APP_HANDLE" \
"DB_CONNECTION=aptible" \
"DATABASE_URL=$DATABASE_URL" \
"APP_DEBUG=false"
Once you're done, push your code to Aptible by adding Aptible as a git remote for your App, and then using git push
to push your code:
git remote add aptible "$GIT_REMOTE"
git push aptible master
Deploy logs will stream to your terminal. They'll be useful in case anything goes wrong to understand the cause of the failure.
Add an Endpoint
At this point, your app is running on Aptible. Now we need to expose it on the Internet!
Follow the instructions here to proceed: How do I expose my web app on the Internet?.
Next steps
At this stage, your app should be running on Aptible. If you get an error when accessing your app, then you should check your logs via the aptible logs
CLI command.
That being said, your app is not production ready yet. Here are a few recommended next steps.
Session Storage
By default, Laravel stores sessions on the local disk. However, on Aptible, container filesystesm are ephemeral so whenever a new Release is created for your App (i.e. whenever it's restarted, deployed, scaled, etc.), sessions stored on disk will be lost, and your users will be logged out. Additionally, if your App is scaled to multiple containers, each container will have its own session store.
Storing sessions in the database will allow them to persist across Releases and allow all of the App's containers to use the same session store. To store sessions in the database, you need to do two things.
-
Create a database migration that creates the tables for your sessions by running
php artisan session:table
and commit the migration to version control. Since you automated database migrations, deploy the App now to update it and run all pending migrations. -
Instruct Laravel to use your database to store sessions by setting the
SESSION_DRIVER
environment variable:aptible config:set --app "$APP_HANDLE" \ "SESSION_DRIVER=database"
Secret Key
Your app will be using the APP_KEY
from your .env
file, which is presumably your development APP_KEY
.
You should generate a new one, and set it by running this command:
# Make sure you set or substitute $NEW_APP_KEY here!
aptible config:set --app "$APP_HANDLE" \
"APP_KEY=$NEW_APP_KEY"
Updated about 1 year ago