How to Dockerize a Laravel App to run in Laravel Forge

Search for a command to run...

No comments yet. Be the first to comment.
Fun fact, while deep diving how Claude Code works, I realised some files were stored with a .jsonl format! Whatβs this, a typo?? π Of course notβ¦. It's a text format where each LINE is a valid JSON object. So why this and not just a JSON array?! Reg...

This apply the dependencies transformations needed, and add the PostCSS config file needed. npm remove @tailwindcss/vite npm remove tailwindcss npm install tailwindcss@3 @tailwindcss/forms npm install postcss autoprefixer cat > postcss.config.js ...

Warning: I just deprecated it. Claude Code is fantastic, it does the same job I wanted to achieve with this. Itβs a CLI instead of an UI, but it does 10x or 100x more than the current application situation. Get it here: https://docs.anthropic.com/en/...

I know, Livewire and Tailwind are the base for Filament, and this tutorial is not any hidden gem, but my gut feeling tells me I should write it. It shows few steps of the docs, but many don't get there, and don't even know this is possible. Filament ...

You're reading this, so you want the Login page ready to go in local environments, without having to type in a default user (configured in your seeder). Let's go. Let's create a Filament Page. Press <enter> for an empty answer, when asked if the page...

So I'm almost sure you were already in the previous blog post. If not, you might want to visit How to deploy Docker Applications with Laravel Forge.
This will be a "show by example", so let's build an App from scratch and deploy it!
Let's make a fresh Laravel Application with Sail Builder
curl -s "https://laravel.build/example-docker-forge?with=mysql,redis" | bash
cd example-docker-forge
sail up -d
When it finishes, you should be up and running! π

So now, let's make this really easy, by using a package I built. Run the following commands:
composer require ijpatricio/docker-for-forge --dev
php artisan dockerEnv:install
It will ask you a few questions:
App Domain: The host that will be registered with Traefik, routing requests from such host to that container (service).App Name and Vendor Name are used to populate the docker-compose.yml
For the time being, it makes a single container, with Supervisor (as in Laravel Sail) guaranteeing the webserver running (Nginx), the PHP interpreter (PHP-fpm), and cron (scheduling). Take into consideration using this "as-is" just with a single container.
More complex scenarios are possible; this is keeping everything simple for the sake of understanding the basics!
I could go into details, but everything is taken care of regarding permissions so that Laravel Forge can read the logs in the UI, we can mount a storage folder, can run commands, and more. Maybe in another post, I could explain things further!
The build will use multiple steps, keeping the image lean. Builds frontend, installs composer dependencies, and more. The sensible basics have been covered. Customize at taste!
Also, .env variables can be used to change some values, but I kept things in the repo for simplicity.
Before committing the code, let's do one more thing:
mv docker-compose.yml docker-compose.dev.yml
echo "docker-compose.yml" >> .gitignore
This is so that each environment will use a specific docker-compose. For example, we locally have a database, but in production, we most likely have that service separated in another VPS.
Commit your code, let's deploy!
Back on the UI, let's add a website.

And we should get something like this. Use your repository. Un-check "Install Composer Dependencies".

We arrive on the App tab. We now change the deploy script accordingly.

And here is the code:
cd /home/forge/example-docker-forge
git pull origin $FORGE_SITE_BRANCH
cp docker-compose.prod.yml docker-compose.yml
docker-compose build
docker-compose up -d --remove-orphans
# Run commands as `forge` user, not `root`
function forgeCmd {
docker-compose exec example-docker-forge bash -c "gosu forge bash -c \"$@\""
}
# Run this just the first time, so it doesn't keep changing
forgeCmd "php artisan key:generate"
# add route cache, db migrate, and your other commands as you see fit!
# forgeCmd "php artisan migrate --force"
Check that environment variables are properly set!

The build can now run!

Ta-daaaa π
Logs are available from the UI:

Storage folder is mounted into the container. This app has its own instance of Redis, so no need for prefixes and so on!
And of course, our website is live, and SSL secured:

Happy coding, happy deploys π