The recent announcements at LaraconUS have sparked a renewed interest in cloud-based deployments within the Laravel community. As the debate continues on how to deploy your apps, one thing is clear: the cloud is becoming a more viable option for Laravel users.
In this article, we'll explore how to prepare your Laravel app for deployment in a cloud environment using FrankenPHP, Caddy, Dockerfiles, and finally deploying it to Sevalla.
So where do we start? In the local environment of course! 🤓
Local development environment
For the sake of simplicity, we'll assume you have a fresh Laravel app installed on your local machine, which connects to a PostgreSQL database to read/write some data.
Before we move on, make sure you have a .env
file
in your project root with the following content:
.env
:
...
DB_CONNECTION=pgsql
...
Once that's verified, we can start building. 🤓 ☕️
It's always a good idea to have a local development environment that closely resembles your production environment. This way, you can catch any issues early on and avoid surprises when you deploy your app in production.
To mimic the production setup we're going to use, we'll rely on Docker and Docker Compose. If you don't have Docker installed on your machine, you can download it from the official website.
Running Laravel without the database
First off, create a new file called compose.yml
in
the root of your Laravel project and add the following content:
compose.yml
:
services:
php:
image: dunglas/frankenphp:php8.3-alpine
command: php artisan serve --host 0.0.0.0 --port 8080
ports:
- 8080:8080
volumes:
- .:/app
This configuration file defines a service called
php
that uses the
dunglas/frankenphp:php8.3-alpine
image, which is a
lightweight FrankenPHP image that includes necessary extensions to
run a Laravel app. We also expose port 8080
to access
the app from the host machine.
To test your configuration, try running the following command in your terminal:
docker compose up [-d]
You should see a Laravel error page explaining the connection
was not established to the database because of a missing driver
when you navigate to https://0.0.0.0:8080
in your
browser. This is expected as we haven't connected our Laravel app
to a database yet.
Awesome, so far we've configured our Laravel app to be served by
a FrankenPHP runtime running php artisan serve
.
Next, let's connect our local app with a PostgreSQL database!
Running Laravel with the database
To connect your Laravel app to a PostgreSQL database, we'll need to do a couple of things.
First, we need to set the following environment variables in
your .env
file:
.env
:
...
DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432 # default PostgreSQL port
DB_DATABASE=main
DB_USERNAME=admin
DB_PASSWORD=password
Following that, you'll need to add new services to your
compose.yml
file, and create a custom
Dockerfile
for your dev environment. Create and update
the files with the following content:
Dockerfile.dev
:
FROM dunglas/frankenphp:php8.3-alpine
RUN install-php-extensions pdo_pgsql
Dockerfile.dev
is only meant to be used by your
local/development environment, and it extends the
dunglas/frankenphp:php8.3-alpine
image to include the
pdo_pgsql
extension, which is required to connect to a
PostgreSQL database.
compose.yml
:
services:
init:
build:
dockerfile: Dockerfile.dev
command: php artisan migrate
depends_on:
db:
condition: service_healthy
volumes:
- .:/app
php:
build:
context: .
dockerfile: Dockerfile.dev
command: php artisan serve --host 0.0.0.0 --port 8080
ports:
- 8080:8080
depends_on:
init:
condition: service_completed_successfully
volumes:
- .:/app
db:
image: postgres:16.4-alpine
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: password
POSTGRES_DB: main
volumes:
- /var/lib/postgresql/data
healthcheck:
test: pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB
interval: 1s
There is a lot going on here, let's take a look at what has changed and why:
- We've updated the
php
service to use a custom Dockerfile calledDockerfile.dev
to build a new image that includes the necessary extensions to connect to a PostgreSQL database. - We've added a new service called
db
that uses thepostgres:16.4-alpine
image to run a PostgreSQL database. We've also defined some environment variables to set up the database user, password, and database name. - We've created a new volume called
db_data
to persist the data in the database on your machine, and Docker could reuse it when you restart the services. - A new service called
init
was also added that reusesDockerfile.dev
. This image is used to run thephp artisan migrate
command to run your database migrations. Thedepends_on
key ensures that thedb
service is up and running before the migrations are run. - The
php
service now depends on theinit
service to ensure that the database migrations are run before the Laravel app starts. - We've added a health check to the
db
service to ensure that the PostgreSQL database is up and running before theinit
service runs the migrations.
To test your configuration, run the following command in your terminal:
docker compose up --build
Your application should now be connecting to your PostgreSQL database, and your database migrations are always run. 🎉
Your local envnironment is now ready to mimic your production environment. You can now develop your app locally and test a really similar setup you'll use in production.
Preparing for production
It's time to make the necessary changes for your production environment.
The first step is to tell Docker which directories it can safely
ignore when building the production image. Create a new file called
.dockerignore
in the root of your Laravel project and
add the following content:
.dockerignore
:
vendor
bootstrap/chache/*
tests
This file tells Docker to ignore the vendor
,
bootstrap/cache
, and tests
directories.
Then, create a Dockerfile
that will be used to
build your production image:
Dockerfile
:
FROM dunglas/frankenphp:php8.3-alpine
ENV SERVER_NAME=":8080"
RUN install-php-extensions @composer pdo_pgsql
WORKDIR /app
COPY . .
RUN composer install \
--ignore-platform-reqs \
--optimize-autoloader \
--prefer-dist \
--no-interaction \
--no-progress \
--no-scripts
This Dockerfile
is similar to the
Dockerfile.dev
we created earlier, but it includes a
few additional steps:
- As the FrankenPHP image uses Caddy as the default web server,
we've set the
SERVER_NAME
environment variable to:8080
to instruct Caddy to listen on port8080
. - We install the
@composer
PHP extension to install Composer in the image. composer install
command is run to install the dependencies of your Laravel app.- We've set the working directory to
/app
and copied the contents of your Laravel app to the image.
To test your changes in your local environment, you'll need to produce a production build of your app. Run the following command in your terminal:
docker build -t my-laravel-app .
This command builds a new Docker image called
my-laravel-app
based on the Dockerfile
in
the current directory.
To test your newly built production image, use the following command:
docker run -p 8080:8080 -e APP_KEY=<your-app-key> my-laravel-app
Replace <your-app-key>
with the value of the
APP_KEY
environment variable in your .env
file or grab a key from here.
Visit 0.0.0.0:8080 in your browser, and your app should start in production mode. It may error due to the lack of a database connection, but that's expected.
Deploying to the cloud
Now that you have a production-ready Docker image, you can deploy it to a cloud provider. 🚀
In this tutorial, we'll use Sevalla, a new cloud provider that offers a
simple way to deploy Dockerfile
-based deployments.
As your app depends on a PostgreSQL database, you're better off provisioning a new PostgreSQL database on Sevalla first. Once you're logged in the Sevalla dashboard,
- Navigate to the Create database modal
- Select PostgreSQL database
- Confirm the settings and create the database
Once your database is ready, you can create your Laravel app on Sevalla.
- Navigate to the Create app modal
- Select your app's repository from your preferred Git provider
- Make sure to select the same data-center your database is in
- Set the
APP_KEY
environment variable required by Laravel - Select
Dockerfile
as build type - Confirm the rest of the settings and hit "Deploy later" button
If your app is ready, you can now connect it with your PostgreSQL database.
- Navigate to the app's page
- Go to the "Network" tab
- Click on the "Add connection" button and select your PostgreSQL database
- Confirm the settings and hit "Connect"
Then, set the following environment variables in the "Environment variables" tab with your database's connection details:
DB_CONNECTION
DB_HOST
DB_PORT
DB_DATABASE
DB_USERNAME
DB_PASSWORD
We recommned using the internal network address of your database
as the DB_HOST
value. This way, your app can connect
to the database over a private network.
The last step is to set up a Job process for your application to run the database mirgations before starting the app.
- Navigate to the "Processes" tab
- Click on the "Create process" button and select "Job"
- Set the command to
php artisan migrate --force
- Set the start policy to "Before deployment"
- Confirm the settings and hit "Create"
If this is also done, you can now initiate a manual deployment of your app in the Deployments tab. 🎉
If all went well, congrats! You've successfully prepared your Laravel app for the cloud. 🚀
Conclusion
In this article, we've explored:
- How to setup your local environment to mimic your production
environment using Docker and
docker compose
. - How to prepare your Laravel app for deployment in a cloud environment using Docker, FrankenPHP, and Caddy.
- We've also covered how to deploy your app to a cloud provider like Sevalla.
By following these steps, you can take your Laravel app to new heights and enjoy the benefits of cloud-based deployments. 🌤
The post Prepare your Laravel app for the cloud appeared first on Laravel News.
Join the Laravel Newsletter to get all the latest Laravel articles like this directly in your inbox.
Read more https://laravel-news.com/prepare-your-laravel-app-for-the-cloud