Deploying Laravel

There is surprisingly little information about deploying a Laravel app. I’ve got an EC2 and wanted to deploy a couple of experiments and had no idea what needs to happen. So, this is a quick overview that I wish I had read on the first day.

The Overview

All of the source files need to be put on the server as well as the compiled javascript and css.

When composer.json changes, then composer needs to run on the server. It does not need to run for every deploy, but that doesn’t hurt anything.

The javascript does NOT need to be processed on the server. It is processed on the development machine and just the compiled assets are copied to the server.

In addition, there are some folders that need to be expressly marked writable by the server.

One Time Server Task

Composer must be installed, and it can be installed on the server like this:

cd ~
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

The Initial Preparation

Laravel is built with PHP, so the basic setup is the same as WordPress. So start with the same steps as deploying WordPress:

1. Point the DNS records to your server.
2. Add a my-project.conf file to the nginx/apache config that is similar to the WordPress configuration.
3. The one difference to the conf file is to add “public” to the path. Here is the example for nginx:

root $ROOT/my-project/public;

4. Don’t forget to restart apache or nginx.

The next few steps require that you have your project stored in git and that you have ssh access to your server.

1. Make a script file in the root folder of your project called deploy_constants.sh. DO NOT CHECK THIS FILE INTO GIT. It will contain your secrets. It should look like this:

#!/usr/bin/env bash

#The location that all of the deployments are on this server.
BASE_DIR=/var/www/html
# The folder that will contain this deployment (often the domain name)
DIR_NAME=my-project.com
# The SSH line (That is, "ssh $SSH" should work.)
SSH=me@myserver
# On the server, "git clone $REPO" needs to work.
REPO=git@github.com:account/repo.git

ROOT=$BASE_DIR/$DIR_NAME

2. Then make another script called deploy-to-production-setup.sh that contains:

#!/usr/bin/env bash
. $(dirname "$0")/deploy_constants.sh
ssh $SSH "cd $BASE_DIR && git clone $REPO $DIR_NAME"
ssh $SSH "cd $ROOT/public && mkdir js"
ssh $SSH "cd $ROOT/public && mkdir css"
ssh $SSH "cd $ROOT/public && mkdir fonts"
scp .env $SSH:$ROOT/.env
ssh $SSH "cd $ROOT && chmod -R 777 ./storage"
ssh $SSH "cd $ROOT && chmod -R 777 ./bootstrap/cache"

3. Run this script. That should leave a new folder on the server with all of the source files.

4. On the server, edit the file .env to be correct for the server. At least change APP_ENV to “production”, and APP_URL to the actual URL. There are likely other app-specific things to change.

5. Create the following deployment script, and call it deploy-to-production.sh:

#!/usr/bin/env bash
. $(dirname "$0")/deploy_constants.sh
npm run production
ssh $SSH "cd $ROOT && git pull"
scp -r public/js/* $SSH:$ROOT/public/js
scp -r public/css/* $SSH:$ROOT/public/css
scp -r public/fonts/* $SSH:$ROOT/public/fonts
ssh $SSH "cd $ROOT && composer install --no-dev"

Each Deployment Iteration

Each time you want to push the latest code to production, check your code in, compile it, and run the deploy-to-production.sh script. This compiles the assets, gets the latest code from github, and runs composer just in case something changed.

I put the following two scripts in package.json for convenience and documentation:

"deploy-production": "./deploy-to-production.sh",
"deploy-production-setup": "./deploy-to-production-setup.sh"

Then I can deploy with:

npm run deploy-production

Note that deploy-to-production.sh and deploy-to-production-setup.sh are completely generic, so the same files can be used for all projects. It is just the values in deploy_constants.sh that change.