Martin Carlin

Using Deployer to Deploy a Laravel 5 Project

Reading time: Takes 2 minutes

in php, devops, laravel, deployer


After writing the first version of the post, I wanted to go back to have another look at it as I wasn't quite happy.

I was running php vendor/bin/dep for deploys since I installed Deployer as a local package.

I changed that by installing globally composer global require deployer/deployer.

Then I could use dep instead of php vendor/bin/dep.

I then removed all of the tasks that were already defined in the Deployer Laravel recipe from my script to avoid cluttering. I didn't even notice that include before so I'm glad I went back to have another look at this.

After that I setup some variables at the top to avoid any confusion over what needed updating for individual use cases.

I also followed the Laravel recipe and included the .env in the shared_files array.

The biggest change after that was to simply upload the public/build directory and its contents over having to do npm install and then gulp --production.

This makes the deploy significantly quicker and it also saves you having to install node and npm on production, as well as not having a node_modules directory for every release which would take up a significant amount of room.

I was still having issues with the bootstrap/cache folder after my re-shuffle, so I removed that line from the top level .gitignore (can't remember if it was me that added that or not, but looking at Laravel's .gitignore it must have been me) and that helped and saved needing a further task in the deploy. There is already a .gitignore in the bootstrap/cache directory so that nothing in there will be version controlled, but just having the empty directory saved endless amounts of pain.

The final piece of the puzzle was to run chmod g+s <directory> to make files inherit group to make files inherit the group from the parent directory (my parent directory had martin:nginx as the owner and group). Without that, all the newly deployed files were martin:martin which didn't work for my configuration since nginx is running as .... nginx.

New gist:

I recently tried using Deployer for the first time to setup a deployment process for a Laravel 5 project, rather than using something like Capistrano that would require installing ruby and gems rather than just adding a Composer package.

This gist represents hours of heartbreaking errors trying to figure out why things weren't working, the main one being the first task:

 * Create cache folder in bootstrap directory
task('deploy:cache_folder', function() {
  run('mkdir {{release_path}}/bootstrap/cache');
})->desc('Manually create cache folder');

I was getting an error saying that bootstrap/cache/services.php didn't exist when trying to run php artisan optimize. The solution seems to be creating the bootstrap/cache directory but of all the tutorials and blog posts I read, none mentioned it so I'm not sure if this is a recent change since the .gitignore file has /bootstrap/cache in it but a 5.1 project I have doesn't.

I think the rest is fairly self-explanatory, just replace the placeholders in the square brackets, the curly brackets are actually used by Deployer so don't change those!

This example is made a bit more complicated due to using elixir for assets, so that's why we have to have a task that runs npm install.

I also wasn't sure what to do with the .env file since it's not in source control and obviously your local one will be based on a local environment, not production, so I decided just to create a .env.production file that gets uploaded and renamed to .env. The only problem I can see there is that if you are part of a team then you'd need to communicate any changes somehow since it's not meant to be version controlled.

To deploy, run dep deploy.

If you have any suggested improvements then I'd love to hear them.