PHP
Article

Deploy Your Website Using Laravel and Git

By James Dow

Use Git and Laravel to deploy your websites with one click using a bookmark.

You can’t be a successful web developer without using some sort of deployment workflow for your websites. It doesn’t matter how good or bad your workflow might be. If you can’t get your website up to production then your client will never pay you for your hard work.

There are many different ways to deploy your website to your production server. Each one of them has their own list of pros and cons, and each one starts and finishes the same way. What makes a good website deployment workflow is what happens in the between.

The other day I was working on a project where I was using FileZilla to FTP my files up to my live production server. I’ve never considered FileZilla to be the easiest interface to use, but for the longest time I thought it to be standard practice.

For the same project, I was also using Git to track my file changes. I started to type out git push origin when I stopped to think to myself. Wouldn’t it be convenient if deploying websites was as easy as pushing Git repositories?

If you think about it, Git is the perfect tool to handle website files in deployment. It keeps track of all your file changes, and it pushes or pulls only what it needs with one command. I decided to set out on a Google journey to search for a way to use Git when deploying my own websites.

One popular method I found using Git to deploy your websites is by making good use of Git Hooks (Tom Oram likes to use a similar approach). Imagine as soon as you type git push origin into your terminal console, Git Hooks launch a predefined script. That predefined script accesses your production server and pulls your most recent file changes. With the same command you used to push your changes, you were also able to update your website. I thought this method was awesome until I realized that just because I push my local repository doesn’t mean I am ready to go live with it.

I wanted something that was as easy as pushing a repository with Git. More important, I wanted to be in full control when pushing content live. I was able to find a similar workflow that used Git to handle the file transferring. On top of that I found out I could also use the PHP framework Laravel to automate the more repetitive tasks.

Here is the website deployment workflow I came up with:

Getting Started with Structure

In this section, we will set up a --bare repository as our central repository and create two repositories by cloning. One is for our local website where we will be executing our deployment process, and the other for our live website. We will also be installing Laravel.

A visual file structure example we'll be using in this tutorial.

Before getting started, you will need a local server and production server with Git installed on both.

Helpful Resources:

1. Initialize your --bare repository

SSH into your production server and locate the directory you would like your central repository to be.

ssh username@domain.com
cd repos

Now initialize your repository.

git init --bare --shared mywebsite.git

It’s usually considered a good practice to keep this folder outside of your public folder structure. This way, someone can’t stumble upon your private repository on accident.

2. Clone to create live website

Determine where in your public_html you would like to host your live website files.

cd ~/public_html/

Now you clone the central --bare repository you just created and logout of this SSH session.

git clone username@domain.com:~/repos/mywebsite.git mywebsite
exit

3. Clone to create local website

If you’re using something like Homestead, you may need to use the Vagrant command to SSH into your local server to access your files.

vagrant ssh

Follow the steps you just went through to create your live website.

cd websites
git clone username@domain.com:~/repos/mywebsite.git mywebsite

4. Setting up Laravel

Before setting Laravel up, you need to have it installed on your local website.

Helpful Resources:

Add your remote server settings to the configuration file by opening /app/config/remote.php.

'connections' => array(
        'production' => array( 
            'host'      => 'domain.com',
            'username'  => 'username',
            'password'  => '********************',
            'key'       => '',
            'keyphrase' => '',
            'root'      => '/var/www',
        ),
    ),

Remember the “production” key because we will need to reference it later.

Add your files to your local website repository so we can track any changes to them.

git add .

Execute your initial commit.

git commit -m 'initial commit with laravel'

Finally, push to your central repository on your production server.

git push origin master

Install Laravel to be used to deploy websites.

When you visit your localhost you should see Laravel’s, “You have arrived.” screen.

Great job! you’re all set up and configured, so you should now be ready to dive into the fun stuff.

The Core Workflow Using Git

Once everything is set up, deploying your websites with Git is a piece of cake. Let’s look at the code to try and understand what’s going on at its core.

It’s important to understand the workflow because we will rewrite it later in PHP with Laravel. It’ll also help us debug any problems that may come up.

1. Go ahead and SSH into your live server, and then find your production repository.

ssh username@domain.com
cd public_html/mywebsite

2. Now pull your central repository down to merge the new file changes.

git pull origin master

If you have done everything correct up to this point, you should see Laravel’s, “You have arrived.” screen when you visit your live site.

If you wanted to stop here, I wouldn’t think any less of you. That in itself is a pretty solid deployment workflow. But we can make it even more efficient by automating it using Laravel.

Automating Deployment with Laravel

Ok, so now that we know how to deploy a website using Git let’s use Laravel to automate the process. This part may not be necessary, but if you’re already using Laravel I ask, “Why not?” Using Laravel here makes this website deployment workflow easy, efficient, controllable, and customizable.

1. Let’s begin by creating a simple route that references a controller.

Open up your routes.php page in your /app folder, and append the following line of PHP to the file.

Route::get('/deploy', 'Server@deploy');

Whenever we visit http://localhost/deploy the public function deploy in the Server controller will execute.

2. Now let’s create the controller we’re referencing, and save it.

Start off with an empty Server class that extends the BaseController.

class Server extends BaseController {

    }

Now insert a public function deploy into the controller.

class Server extends BaseController {
    
        public function deploy() {
        
        }
    }

Save it in your /app/controllers folder, and name it Server.php.

Here’s where it gets fun!

3. Insert Laravel’s SSH facade into the deploy function and repeat the Git deployment workflow.

Insert the SSH facade. We want to access the production remote configurations we set up earlier.

SSH::into('production')->run();

Now the run() function will accept two arguments that we need to provide. The first, and most important one is an array of terminal commands we want to run when we execute our deploy function.

SSH::into('production')->run(array(
	    'cd ~/public_html/mywebsite',
	    'git pull origin master'
	));

The second is a function we want called to handle the feedback we’re receiving from the server.

SSH::into('production')->run(array(
	    'cd ~/public_html/mywebsite',
	    'git pull origin master'
	), function($line){
	
	    echo $line.PHP_EOL; // outputs server feedback
	});

Now whenever we want to deploy our website, all we have to do is visit http://localhost/deploy and we’re done. Easy enough right? Yes, and no.

There are a couple of security breaches we need to handle before we can call this a night. Anyone and their mother could stumble upon http://domain.com/deploy and deploy our website as is. What we need to do is set something in place to prevent this.

There are many ways of going about doing this, and we could debate which method is the most secure until we’re blue in the face. You can password protect the route, you could prevent access by IP address, etc.

For this example we’re going to use .gitignore, and check to make sure the file exists before we run the route we just created.

4. Create a .gitignore file in controllers to ignore Server.php.

Create a new file and save it in /app/controllers as .gitignore.

Add the following line of text to the file and save it.

Server.php

5. Make sure Server.php file exists before running the route that deploys our website.

Remember the route we created earlier to deploy our website? We need to wrap it with this conditional statement, and then we’ll be ready to go live with it.

if (file_exists(__DIR__.'/controllers/Server.php')) {
        // route goes here
    }

It should look like this when we’re all done.

if (file_exists(__DIR__.'/controllers/Server.php')) {
	    Route::get('/deploy', 'Server@deploy');
    }

Finish up by Getting Creative

So there you have it! Just stage all your updated files, commit, push, and you’re ready to start deploying with a Git friendly workflow.

Add your new deployment page to your bookmarks for one-click deployment.

If you want to you can take this tutorial a step further. Just add http://localhost/deploy to your bookmarks for quick one-click deployment. You can even create a simple HTML form that posts to the page that allows you to pull specific branches. The possibilities are endless.

Deploying with Git and Laravel has taken a boring and daunting task of deploying my websites, and made it fun again. It’s easy to set up if you understand Git, but it’s even easier to use.

Please share with me the creative ways you’re using to make website deployment easier!

Free Guide:

7 Habits of Successful CTOs

"What makes a great CTO?" Engineering skills? Business savvy? An innate tendency to channel a mythical creature (ahem, unicorn)? All of the above? Discover the top traits of the most successful CTOs in this free guide.

  • Tiago Sá Velho

    Very creative solution. Thank you!

  • Oscar Blank

    This is pretty standard, except it would be better to use a standalone script with no dependency on Laravel.

    • https://twitter.com/photodow James Dow

      I agree, not being dependent on Laravel is probably ideal, but for the purpose of this article Laravel has a cleaner and more approachable style to how it’s done. In my opinion it’s a little easier to swallow.

  • mamun bl

    It’s a very important post. Thank you for sharing…

  • Magnus Eriksson

    I agree. Using Laravel for this seems a bit redundant.
    We do something similar but without depending on Laravel. It’s all Git!

    * First we have our main repos on a private GitLab setup (could be anywhere though).
    * Then we add a –bare git repo outside the web root on the server. (let’s call it “hub”)
    * Now add a “git init” in the web root and run:
    git remote add hub /path/to/hub.git

    *In the /path/to/hub.git/hooks/post-update:
    #!/bin/sh
    echo “* Pulling changes to /path/to/webroot/”
    cd /path/to/webroot/ || exit
    unset GIT_DIR
    git pull hub master

    *On your local environment, do a:
    git remote add production username@production-domain.com:/path/to/hub.git

    That’s it.

    Now you can push to master (GitLab) how much you want without affecting the live site and when you want to deploy, run:
    git push production master

    You can of course change the post-update hook to fit your needs.

    That’s my to cents. :)

    • angra89

      This comment is still useful. Thanks

    • https://arjunphp.com arjun

      Useful comment!. Thanks!

  • kuindji
  • http://uliciphotography.com/ Adi Ulici

    A really easy way to deploy using git, which I’m using on some projects, is with git-ftp : http://git-ftp.github.io/git-ftp/

    This tool allows you to deploy with FTP, no ssh access is required. This way you can use it even on shared hosting.

  • hot_rush

    that’s all good until you need to migrate/seed/install smth/reload supervisor/etc and sometime rollback changes
    i’m using capistrano for this needs

    • https://twitter.com/photodow James Dow

      I’ve heard of capistrano, but I’ve never actually used it. I personally haven’t come into any problems like the ones you listed here because the projects I usually use this process on are pretty small, but I’m glad Capistrano solves this for you! Thanks for sharing it!

  • https://twitter.com/photodow James Dow

    That’s awesome, thanks for sharing! I have a small project right now that doesn’t allow me to SSH into the server, so I’m going to have to see about giving this a try.

  • https://twitter.com/photodow James Dow

    Nice deployment workflow, I love how you’re using a private repo to circumvent the problem. I need to “git” better at using Git Hooks myself, so thanks for sharing your process I’ll have to try it out.

    I agree with you. Using Laravel in this way doesn’t make much sense unless you’re already using it on your project. I never said this workflow was the best deployment workflow, but I still stand by its ease and flexibility. I personally feel like Git Hooks has more of a learning curve, and maybe even some restrictions. Although, it’s probably worth making a couple sacrifices to achieve a pure Git workflow. ;)

  • Denn Massalitin

    Was using something like this on one project in form of small php script.

    Wanted to add small detail to your step-by-step guide. It’s about general workflow.
    After you created git user on remote server, run
    ssh-copy-id git@host

    this will copy your ssh credentials to server and you will be never requested password again.
    Without this every git push will ask password, which is very uncomfortable

  • Guest

    Best practice shows that you should be using a tool like Fabric, Ansible, Saltstack (or something along those lines) for your deployments. Nice article, but could be more focused on best practice :)

  • Bjorn Theart

    I created an Artisan command and simply run php artisan deploy. It wraps around Laravel’s SSH functionality. I don’t just do git specific stuff, but also things like running migrations, seeding, and updating Laravel through Composer

  • http://about.me/halilim Halil Özgür

    If you are on Linux or Mac, you can use Envoy to deploy, run composer install, migrate etc. Example setup: https://gist.github.com/halilim/47ec5be515bd4552324c (The config syntax is Blade but you don’t need Laravel in order to run it).

    You might want to use something like Capistrano (tried) or Rocketeer (haven’t tried) for a full fledged solution.

  • dud3

    Ideally, deploying from the laravel’s route is not practical and much reusable for other projects.
    You better write a customizable shell script that handles all the deployment.

    Beside if you’re using “composer package manager”(which laravel uses by default) and include a dependency/bundle/library… and after that run the route of “local…/deploy”, that might not be a good way to deploy you’re application.

  • Guest

    How can I Automating Deployment with Laravel if my GitHub repository is a private one?

  • Sazzad Tushar Khan

    How can I Automating Deployment with Laravel if my repository in GitHub is a private one?

  • Ian Simmons

    I’m trying this out on a shared host with git and ssh enabled. For me step 3 Clone to create live website was just ‘git clone ~/repo/testsite.git ~/public_html’ No need to specify user@domain because you are already logged into the production server so you’re just cloning from a local directory to another local directory. Unless I’m misunderstanding something.

  • Steven Warwick

    this is a really, really well done writeup.

    In our case, however, the Laravel public server needs to be different than the development server.. for the public server, we minimize all script/css files using elixer and ‘gulp –production’ and point to different database servers and api servers both in laravel and client javascript code. I’m thinking there may be a clever way to use a git merge and git hooks on the production server to handle these customizations as the pull is done onto the public server but have not seen any writeups that use this approach. Thoughts?

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in PHP, once a week, for free.