Zero-Downtime Deployments for Laravel Apps with deployer
This article has been published a while ago.
If this is a technical article some information might be out of date. If something is terribly broken, let me know and I will update the article accordingly.
Matt Stauffer recently tweeted about deployment in the Laravel world and how people ask him questions about it. In this post I wanna share how I usually deploy my Laravel apps.
My deployment workflow is dictated by a small set of questions I have to ask myself first:
- Is this a little side project that only I use or is it an app which is exposed to hundreds/thousands of users and will generate money?
- How complex is the deployment process itself? - Is a git pull sufficient? - Do I have to run database migrations? - Do I have to install
If the answers are "just a side project" and "just install composer dependencies" is usually stick to the "Deploy script" feature of Laravel Forge. If the answers are more like "it's a bigger project" and "there are more steps to deploy this app" I use deployer.org (You can deploy any kind of app with it, not just Laravel or PHP projects).
One of the key benefits of using
deployer is, that it comes with support for "zero downtime" deployments out of the box. This means, that each deployment is created in its separate folder and only when all your deployment steps go through without errors, the new release gets activated by placing a symlink in your webroot to the new release.
When you first setup
deployer you have the option to select one of many pre-made recipes for popular Frameworks like Laravel, Symfony or Drupal. The Laravel recipe looks like this. It will automatically clear your caches and config values for you. Nice 👌.
At work, we use a customized "Common" recipe. Our
deploy task looks like this:
desc('Deploy your project'); task('deploy', [ 'deploy:prepare', 'deploy:lock', # Lock the server for further deploys 'deploy:release', # Create new release 'deploy:update_code', # Fresh Git clone 'deploy:shared', # Setup shared dirs and files 'deploy:writable', # Fix permissions 'deploy:vendors', # Run composer install 'deploy:clear_paths', 'artisan:cache:clear', 'artisan:view:clear', 'artisan:config:cach' 'deploy:symlink', # Create the symlink 'deploy:restart-php-fpm', 'deploy:bugsnag-deploy-tracking', # Send API request to Bugsnag 'deploy:unlock', 'cleanup', # Cleanup old releases 'success', ]);
So it's not just a
The switch to deployer from our previous solution is now over 12 months ago and I can say, that it saved our ass multiple times.
So my summary of
- Comes with Zero Downtime support out of the box.
- Can work on shared hosting (depends on the hosting provider, but it's possible).
- Flexible and extendable with your own tasks.
- Deployment are usually triggered from your machine and not through a Web UI or through ChatOps. (Can be done, but needs a bit of setup)
I can highly recommend the following articles, if you want to read more about deployment: