Warning: You are reading an outdated version of this guide. Unless you're here for a specific reason, you probably want the updated version instead.
This article walks you through a simple script for automatically redeploying your app after every Git push to the server.
This setup is simple and not robust (largely because it reinstalls dependencies and rebuilds your app directly in your app’s production directory). It’s meant more as a learning exercise for people using Git hooks for the first time than for use on a real production system.
My suggestion: if this is your first time deploying a web app, read through this article, try it out, and then, once you feel ready, move on to zero-downtime redeployment once you understand what’s going on here. Experienced users probably want to jump directly to zero-down redeployment.
The main downsides of the simple workflow in this article are:
A more sophisticated setup would use zero-downtime redeployment, which solves all of these issues and is covered in a separate article.
post-receive
hook in your server-side Git repo and understand what the hook does, i.e. copy your app to the production directory in /srv/www/
after every Git push.This redeployment workflow relies on the post-receive
hook in your server-side Git repo and looks something like this:
post-receive
hook.post-receive
hook first copies your updated app to the production directory in /srv/ww/
(as in the server-side Git setup article), then runs the standard Laravel (re)deployment recipe, i.e. Composer and NPM installs, rebuilding your app, caching routes and config, etc.We’ll basically collect all of the deployment commands we’ve run manually over the past few articles, and add them to the post-receive
hook in your app’s Git repo.
Go ahead and open the post-receive
in your server-side Git repo with a text editor and add in all of deployment steps used so far.
To save your from going back through all of the past articles, your final post-receive
hook should look something like this:
#!/bin/sh
# Server and Git repo directories.
# Update paths as needed.
SRV="/srv/www/laravel-project"
REPO="/home/laravel/repo/laravel-project.git"
# Temporarily disable your app during the redeployment.
# See https://laravel.com/docs/10.x/configuration#maintenance-mode
cd ${SRV}
php artisan down
# Copy app from Git repo to server directory
git --work-tree=${SRV} --git-dir=${REPO} checkout --force
# A standard Composer install for a Laravel production environment.
# See https://laravel.com/docs/10.x/deployment#autoloader-optimization
composer install --no-dev --optimize-autoloader
# Install node packages and build assets.
# You can skip this if your app has no Node.js dependencies.
npm ci && npm run build
# Cache Laravel configuration settings, routes, and views for efficiency.
# See https://laravel.com/docs/10.x/deployment#optimizing-configuration-loading,
# https://laravel.com/docs/10.x/deployment#optimizing-route-loading,
# and https://laravel.com/docs/10.x/deployment#optimizing-view-loading
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Run database migrations.
# The force flag is needed for automated deploys to suppress warning prompt.
php artisan migrate --force
# Leave maintenance mode and re-enable your application
php artisan up
Comments:
php artisan down
to temporarily disable your app during the redeployment, then php artisan up
to re-enable your app after the redeployment completes (here’s a link to the Laravel docs on maintenance mode).npm ci
instead of npm install
.
This is standard best practice in production environments—see e.g. this Stack Overflow answer for details.The above recipe should work well for most users, but it is certainly not the only possible way to (re)deploy a Laravel app. You might find other guides online with a slightly different sequence of commands and/or slightly different commands—don’t worry, they probably work, too!
Here are a few commands to consider using if your app needs them:
php artisan queue:restart
if using queuesphp artisan cache:clear
if using an application cache (which you will probably have to run with sudo
, since cache files are created by the web server and the laravel
user doesn’t have permission to delete them)(But if you’re using these more advanced Laravel features you probably already know what your doing!)
At this the post-receive
hook should successfully take care of updating and redeploying your app every time you push a new version to your server-side Git repo.
Time to test if this simple redeployment setup is working properly.
Make a test change to your app on your dev machine (add a new feature, change some text, tweak a color, etc.—anything you’ll easily notice), commit the change, then push the new version of your app to the server.
# On your dev machine, push your app's main branch to the production server.
you@dev:laravel-project$ git push production main
Here’s what should happen (the first few steps are the same as in the dev-side Git setup article):
Git on your dev machine recognizes which SSH key to use to connect to the server, and prompts you for the key’s password, if needed.
Your app is pushed to the server-side Git repo (SSH into the server and check the contents of /home/laravel/repo/laravel-project.git
).
Pushing code to the server triggers the server-side post-receive
hook.
The post-receive
hook begins executing—it first places your app in maintenance mode (which you can test by visiting your app in a browser during the redeployment process) and then begins running through each of the deployment steps added in this article.
You should be able to follow along as the script’s standard output appears in your SSH session; obviously, you want each deployment step to complete successfully.
The redeployment should complete within a minute or so, the script should exit maintenance mode, and the latest version of your app should be live.
Disclaimer: there are, of course, a million things that could go wrong, and it’s best to manually inspect and try to understand any error messages (which are often helpful) and adjust accordingly.
With that said:
post-receive
hook is executable, right?npm run build
command failing? Make sure your Node.js is reasonably up to date and then your server has sufficient RAM (covered in the NPM article).Next: The next article shows how to set up a custom domain name for your web app.
Finding this tutorial series useful? Consider saying thank you!
The original writing and media in this series is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.