This post is a continuation and basically an application based on my previous post, Flexible Development Environment Using Docker, in which we are going to run a Laravel application with Inertia and Vue.js frontend using our previous setup, which is Docker.
Requirements
PHP CLI (at least version 8.2)
In modern debian-based distros, you can just install it using apt:
Note that we are just installing the CLI version of PHP, not the standalone
php package from APT, since it also ships apache by default, and we
don’t want apache to take over our port 80 once it gets installed on our
system. So we should just install the CLI version.
PHP Extensions
Even if we’re gonna run Laravel through Docker, we still need the PHP extensions needed by Laravel for us to generate a project.
To install required PHP extensions by Laravel, just use this command:
Composer
We also need Composer CLI on our system to easily generate Laravel projects with a single command.
To install Composer, just enter these commands on your terminal:
Alright! Let’s generate our Laravel project!
Generate Laravel project
To easily create a Laravel project, let’s first install the Laravel installer globally:
Then, let’s check if we have the laravel command on our terminal:
Oops! ZSH doesn’t consider our global Laravel installation. Let’s fix it by including the Composer bin to our PATH variable on our .zshrc:
Open our .zshrc file on our editor:
Add the following lines to the end of the file:
Then, let’s source the file to apply the changes:
That’s it! The laravel command should now work.
Nice! Now let’s generate our project. First, let’s create a project directory if you don’t have one:
(Optional) Then create a laravel directory just to be organized.
Use the Laravel Installer to generate a project
It will ask you some questions regarding on how you will start your project. Here’s mine:
What is the name of your project? my-project (Name it whatever you want)
Would you like to install a starter kit? Laravel Breeze
Which Breeze stack would you like to install? Vue with Inertia
Would you like any optional features? Dark mode, TypeScript
Which testing framework do you prefer? Pest
Would you like to initialize a Git repository? Yes
Which database will your application use? MySQL
Default database updated. Would you like to run the default database migrations? No
We don’t need to run the default migrations immediately since we’ll setup our MySQL container after the installation.
Alright! Now our project is generated, let’s create our compose.yaml file!
First, let’s open our project in VSCode.
Then create a file in the root directory named compose.yaml
Let’s start by defining our top-level name:
Web Server
There are two main options for the web server of our Laravel app, which are Apache and NGINX. It of course, depends on your preference and the server you’ll deploy your app.
Apache
Our PHP-Apache app service looks like this:
It’s a pretty basic single service that contains PHP and Apache together. You can also read the comments to know what it does, and you remove the comments after if you want.
The Dockerfile for this service is this:
Looks complicated, but it basically does these things:
Get the PHP 8.3 with Apache image from Docker Hub
Install system dependencies
Configure Apache to serve our app
Install PHP Extensions needed by Laravel
Get the latest Composer binary
Install Node.js
Set some permissions
NGINX
Now for NGINX, it’s quite more complicated. This time we need to have 2 separate services: app and server. The app service will be our PHP service and server will be NGINX. The services looks like these:
This is the Dockerfile for our app service:
The Dockerfile for our app service is actually quite similar to the Dockerfile for our Apache service, except that we don’t configure our web server inside this Dockerfile, since our NGINX service is separated. This Dockerfile does the following:
Get the PHP 8.3-fpm image from Docker Hub
Install system dependencies
Install PHP Extensions needed by Laravel
Get the latest Composer binary
Install Node.js
Set some permissions
Now, create a .docker directory to store our service configurations.
For our NGINX configuration, create a app.conf file on your .docker/nginx/conf.d directory:
This is a pretty basic NGINX configuration. You can modify it as you want.
Database
The database service for both web servers are the same. We’ll just use MySQL:
Alright! That’s our services. Last thing, we need to define the volumes and networks we used:
That’s it! Here are the complete compose.yaml for both web servers:
Apache
NGINX
Now, before spinning up our services, we must update our vite.config.ts to enable HMR:
We also need to modify our .env for our app URL and database credentials:
Nice! It’s finally time to spin up our services!
After the containers are built, you should be able to visit your Laravel app using the custom domain you assigned (http://my-project.localhost) in my case.
You can check if the HMR works when you run the Vite dev server:
You can also run artisan and composer commands using the following:
Bonus
Well, it’s not fun to manually type all those commands every time I want to execute some artisan, composer, or npm commands. So I have a simple solution: justfile!
It’s a command runner that we can use to alias our common commands throughout the project. To know more, you can read visit the repository here.
Installation and Setup
Set up the APT repository
Install using APT
Create a justfile on the root of your project.
That’s it! You can now just run your commands normally, just prefix it by just.
All those commands are just my personal preference to use. It’s up to you what commands you want to alias. Feel free to modify the justfile!
Conclusion
This is how you dockerize a modern Laravel Application effectively. While these configuration seems like a lot of work, it can save us a lot of time especially in production environments.