...

Deploying Laravel App on LEMP Stack using Git Hooks

In this tutorial, we will learn to set up Laravel onto a virtual private server (VPS) using what is called a LEMP stack. I assume the VPS has been already set up on Digital Ocean and installed LEMP Stack has been installed.

If you wish you can check How to install LEMP Stack on Ubuntu here.

1- Logging Into Your Server

After setting up the server you will need to log on to the server using the terminal command:

ssh root@234.120.320.345

Don't forget to replace your server IP with 234.120.320.345

2- Configure Nginx

I recommend creating an Nginx config file per domain because sometimes we need to have multiple websites hosted on the same droplet. Open a new file using nano and add the below content on this file:

sudo nano /etc/nginx/sites-available/yourdomain

Don't forget to replace yourdomain to your domain name or something as you like in the above line.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name your_domain.com;
    root /var/www/PROJECT_DIR/public;
    index index.php index.html index.htm index.nginx-debian.html;

     location / {
        try_files $uri $uri/ =404;
    }
     location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

You will need to update a couple of things  from the above content,

Replace your_domain.com  with your domain name.

PROJECT_DIR is where your project files will be uploaded and Nginx will look up to serve your application requests. 

To save it remember to press Ctrl + X and then type Y and then press enter.

Now that we have saved the file, make sure it is error-free by typing:

sudo nginx -t

If everything was correct then you should get this notice when submitting the command:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

This means you have no errors. Good work, now create a soft or symbolic link typing:

ln -s /etc/nginx/sites-available/yourdomain /etc/nginx/sites-enabled/

on the terminal.

symbolic link, also termed a soft link, is a special kind of file that points to another file, much like a shortcut in Windows or a Macintosh alias. Unlike a hard link, a symbolic link does not contain the data in the target file. It simply points to another entry somewhere in the file system.

Now to let it take effect you can restart Nginx with the terminal command:

sudo systemctl reload nginx

With this setup, you are now ready to deploy any PHP/Laravel application. The server is all set up to accept and deliver it.

3- Create A Laravel Project Directory

Now the server is ready to serve files, So create your project directory from the terminal using:

sudo mkdir -p /var/www/PROJECT_DIR

In Laravel, there is a file called index.php in our public directory. This file is a PHP file that is actually most of the magic behind Laravel. Regardless of our routes, we always want to load this file. This file then grabs information about the request and sends it to our routes file (in routes/web.php in Laravel 5.3) which then parses the URL that was passed into it to determine which controller to send it over to. When the routes file determines which controller and action to implement it does so, executes your controller action, which most likely returns a view that is what ultimately is returned to the user.

The reason that this workflow is important to understand is that regardless of which route you go to, the page that is always loaded is the index.php page. All the routes and views that you see are actually the result of loading this same page on every request.

4- Install Composer

You need to install the composer to update/install PHP/Laravel dependencies. Follow the instructions to install the composer on the GetComposer.org website.

5- Install Git

We will install Git onto our server now in a folder called /var/repo/. Let’s make the folder now.

cd /var mkdir repo && cd repo

This will move us into our /var/ directory and then make a new directory called repo/ and then move us into that folder. You should now be inside /var/repo/ when you execute the next commands.

mkdir site.git && cd site.git
git init --bare

The --bare flag might be a new one for you, and that is because it is generally only used on servers. A bare repo is a special kind of repo whose sole purpose is to receive pushes from developers. You can learn more about these types of repositories from the official git site.

We now have a git repository in /var/repo/site.git congratulations!

6- Setting Up Git Hooks

Git repositories have a cool feature called hooks that we are going to use to move our files after a git push. Think of git hooks like webhooks or maybe WordPress hooks. Basically, you can create scripts that execute when certain hooks are triggered. There are three hooks available through Git: pre-receive, post-receive, and update.

We will focus on the post-receive hook which triggers after the repo has fully downloaded your files and completed receiving a push.

To set up hooks we need to move into the hooks directory inside of our site.git folder. In /var/repo/site.git# we can type ls to see all the files and folders inside. You will see the hooks/ directory which we need to cd into.

Once you are inside the hooks/ directory we are going to create the post-receive script. We will be using a new command called touch which makes an empty file.

sudo nano post-receive

Now you will open up a blank file in Nano (terminal text editor). Type the next two lines into the file and save and exit the file.

#!/bin/sh
git --work-tree=/var/www/PROJECT_DIR --git-dir=/var/repo/site.git checkout -f

Now save and exit (the same way we keep doing it Ctrl + X then Y to confirm the save and enter to save it as /var/repo/site.git/hooks/post-receive. This file is where all of the magic happens.

The  --work-tree= tells git where to copy received files to after it has completed. We set it to point to the folder for our Laravel application that we made earlier. The --git-dir= tells git where the bare git directory is that has received the files. It is that simple. Make sure that the whole command is on one line (including the checkout -f).

After you save the /var/repo/site.git/hooks/post-receive file, you need to make one last command before we leave this folder and push our files up. The post-receive file needs execution permissions in order to copy these files over. So we can do that really quickly with one line of code. Make sure you are still in /var/repo/site.git/hooks/ folder when you type this command:

sudo chmod +x post-receive

That is it! Now when we push to this repository on our server, the files will be placed in our /var/www/PROJECT_DIR/ directory and Nginx can begin to serve them to our users.

We are now done on our server, for now, we need to exit the ssh session to access our local machine for the next step. Type the following command to end your ssh session.

exit

Your command prompt should now change to the name of your computer instead of root@localhost#. This indicates you are no longer on your server and you are making changes now to your local computer.

7- Set up our Local Computer to Push to Production

Now that our server is set up to receive the files, let’s set up our local computer so that it can push the files to our server. We will be using git, so make sure that your local computer’s Laravel directory is under git version control before you continue.

Just like when we push our files up to GitHub, we set up a git remote called origin that represents GitHub. So when we want to push to GitHub we make a command like this git push origin branchname. This tells git to push the branch (branchname in this example) to our origin remote.

Now in the same fashion that we set up GitHub as a push location, we will also set up our new server as a push location. I like to call this remote by name production which represents our live production website. The goal is that after we set it up, we can tell it to push to our server from our local computer by just typing the command git push production master and this will push the master branch to our production server. You can continue to push to GitHub using git push origin master but then when you are ready to make changes go live you will run the push to production

To set up a new remote you use the git remote add command. Before you do this make sure you are in the correct location. First of all, you should no longer be on your server. If you still see root@localhost# in your prompt then you are on your server still. Type exit and hit enter to leave the server. You should see the name of your computer in the command prompt now. Use cd commands to get into your Laravel project folder that you want to push to the server. In my case my project is under /var/www/blog so I type this to get into my folder via the terminal:

cd /var/www/blog

Also, make sure you have git setup for this project. I am assuming you have already made at least one commit and you are currently on your master branch which contains your latest production-ready code.

Now add the production repo to git by typing:

git remote add production ssh://root@234.120.320.345/var/repo/site.git

Make sure to substitute the red text with your domain or IP address. The command should mimic the ssh command you use to log into your server. So if you type ssh root@234.120.320.345 to get into your server then 234.120.320.345 is what it should show on the command above.

With this command, we now created a remote called production that sends our files to the new bare git repo we made on our server.

Now once again, assuming your project code is production-ready and is on your master branch then you can type this command to push it up to your server:

git push production master

The output will look just like when you push to GitHub, but this time you are pushing to your own server! Let’s log back into our server now to make sure it worked.

8- Verify our Git Hook Works

Now let’s make sure our code is in the right place. It should be in our /var/www/PROJECT_DIR/ folder on our server. It is easy to check, just log back into your server and look at the directory.

ssh root@234.120.320.345

Remember that example.com needs to be changed to your domain or IP address. Now cd into your PROJECT_DIR folder.

cd /var/www/PROJECT_DIR
ls

You should now see what appears to be a Laravel project. You can poke around but it should mimic your files from your local computer. If you have your Laravel project in here then you have done everything right.

9- Run Composer

Remember when we installed the composer a while ago? Well, let’s use it. Now that we have Laravel on our server and all the files we need, let's run the composer to get it working. Make sure you are in /var/www/PROJECT_DIR/ when you run composer commands because you want to be inside your Laravel project.

composer install --no-dev

The --no-dev command flag is very important. Without it, a composer will try to install a bunch of stuff that you do not need on production. It is also very likely that the install will fail as well since some of the dev dependencies won’t work on our server. By adding --no-dev we are only installing the main require elements and not other random things.

10- Laravel Permissions

In order to run, Nginx needs certain permissions over the Laravel directory we made. We need to first change ownership of the Laravel directory to our web group.

sudo chown -R :www-data /var/www/PROJECT_DIR

Now the web group owns the files instead of the root user. Next, we need to give the web group writes privileges over our storage directory so it can write to this folder. This is where you store log files, cache, and even file uploads.

sudo chmod -R 775 /var/www/laravel/storage

Now go to your web browser and type in your domain or IP address to attempt to view the site. What do you see?