Using Rocketeer for Easy Deployment to VPS

In this blog, I will be referring to Laravel deployments in particular; however, Rocketeer was designed to be framework agnostic and so the general principles should be transferrable to any deployment scenario.

The primary goal of Rocketeer is to interface with your source code manager (SCM) and transfer code (from your SCM) to your deployment folder. It is important that you understand this – Rocketeer does NOT transfer code directly via ssh/scp. You MUST use an SCM (git/cvn). In the Laravel context, It also performs other tasks like running migrations, installing composer dependencies etc.

The flexibility provided by Rocketeer is particularly enticing in a VPS scenario. There are a couple of gotchas that you need to be aware of especially when using your own VPS as a github repo. Listed below are the steps I take to deploy Laravel apps to my VPS.

Step 1: Prep the laravel app under question – Include the dependency on rocketeer, add the provider and finally add and commit all code to your local git repository.

Step 2: Prep the remote VPS:

a. I will proceed with the assumption that you have hardened your VPS along the same lines as outlined in this great post by Bryan Kennedy. This means that you will ssh into your box using a predefined username and a key file (as against root+password).

b. From following step1, you must have added your local box ssh key to your hosts “.ssh/authorized_keys” file. Since Rocketeer will attempt to open an ssh channel to do a git clone, you must ADDITIONALLY generate a public key for your server and add it into the authorized_keys file. This is easily done by executing the following in your host:

ssh-keygen -t rsa -C "email@domain.com"

Accept the defaults. Then copy the contents of the generated .ssh/id_rsa.pub to your .ssh/authorized_keys file.

If the above is not properly done, the error message thrown by Rocketeer during the deploy process is:

Unable to clone the repository
Cloning into '/var/www/project1/releases/20140330095757'...
Permission denied (publickey).
fatal: The remote end hung up unexpectedly
Deployment was canceled by task "Deploy"
Execution time: 3.492s

c. Insure you have composer (globally) and git installed on your vps

d. Set up a directory structure convention for your projects (you will do this for each new project). Let’s say

  • Your project files get deployed to /var/www/project1
  • Your git repo is at /var/git/project1.git

Important: Since files will be deployed using the username you use to ssh, please also make sure that the username is in www-data group,and the www-data group has rwx permissions on /var/www. Do the same for the git folder as well.

e. Setup a git repository on your vps (/var/git/project1.git) and set the remote server option in your local repo

cd /var/git/project1.git
git init

on your local repo:

$ git remote add origin ssh://username@my.server.org/var/git/project1.git

Note how I specified my VPS hosted git repository. ‘username’ is the username that has ssh permissions to my vps. Rocketeer will login as this username and attempt to do a git clone in the deployment directory.

Run the following command to ensure that the remote server is properly set:

$ git remote -v
origin  ssh://username@my.server.org/var/git/project1.git (fetch)
origin  ssh://username@my.server.org/var/git/project1.git (push)

Note that you can use an IP address if you do not have a hostname associated with your VPS. After the remote server is set, you should be able to do:

$git push origin master

to push your code to your server repository.

Step 3: You are now ready to deploy apps to your vps using Rocketeer. Rocketeer uses the new Laravel 4.1 RemoteManager component (https://github.com/illuminate/remote). This requires a more recent version version of PHP.

Fill in the appropriate details in app/config/remote.php (Rocketeer pulls information from this config file into its own config.php file)

'connections' => array(
    'production' => array(
    'host'      => 'my.server.org',
    'username'  => ‘username’,
    'password'  => '',
    'key'       => '/home/vagrant/.ssh/id_rsa',
    'keyphrase' => '',
    'root'      => '/var/www',
    ),
),

On running php artisan, you should see the following Rocketeer specific options like so:

deploy
 deploy:check Check if the server is ready to receive the application
 deploy:cleanup Clean up old releases from the server.
 deploy:current Display what the current release is
 deploy:deploy Deploy the website.
 deploy:flush Flushes Rocketeer's cache of credentials
 deploy:ignite Creates Rocketeer's configuration
 deploy:rollback Rollback to the previous release, or to a specific one
 deploy:setup Set up the remote server for deployment
 deploy:teardown Remove the remote applications and existing caches
 deploy:test Run the tests on the server and displays the output
 deploy:update Update the remote server without doing a new release.

Start off the process (this is a once per project setup of config options) by typing

$ php artisan deploy:ignite
No repository is set for the repository, please provide one :ssh://username@my.server.org/var/git/project1.git
Configuration published for package: anahkiasen/rocketeer
What is your application's name ? (project1)
The Rocketeer configuration was created at anahkiasen/rocketeer
Execution time: 7.4155s

Go through the \config\packages\anahkiasen\rocketeer\remote.php file and ensure that the settings are correct.

I had to make a couple of changes:

'root_directory'   => '/home/www/', to
'root_directory'   => '/var/www/',

Also I commented out the ‘composer self-update’ task (this is because I have composer installed globally in the /usr/local/bin directory and the username that rocketeer uses to ssh does not have appropriate permissions to the folder for the composer self-update process)

// The process that will be executed by Composer
 'composer' => function ($task) {
 return array(
 //$task->composer('self-update'),
 $task->composer('install --no-interaction --no-dev --prefer-dist'),
 );
 },

Run the deploy:check command to verify that you are good to go.

$ php artisan deploy:check
Checking presence of git
Checking presence of Composer
Checking presence of mcrypt extension
Checking presence of mysql extension
Checking presence of pdo_mysql extension
Your server is ready to deploy
Execution time: 3.1507s

If any deficiencies are noted, please fix them prior to proceeding.

 Once you are ready to deploy. Type in

$ php artisan deploy

or

$ php artisan deploy:deploy

If all goes well, you should get a success message from Rocketeer and a copy of your code on the host VPS.

To troubleshoot the deploy process, type in

$ php artisan deploy --verbose

The –verbose switch will display a wealth of information to help you debug the source of the error.

We have barely scratched the surface of Rocketeer (although it covers the most common use-case). Be sure to read up the wiki to understand what exactly happens during a “deploy” and to implement more intricate deployment scenarios.

On a related note, I would also like to mention that git deployments can be accomplished using git post-receive hooks. There is a great tutorial explaining the process at digital ocean. Personally I prefer the Rocketeer way as it is easier to implement and also offers a simple version switching mechanism.

 

Advertisements

Laravel Hash::make() explained

First, let us run through a couple of observations in Laravel 4:

return Hash::make('test');
$2y$10$ooPG9s1lcwUGYv1nqeyNcO0ccYJf8hlhm5dJXy7xoamvgiczXHB7S
return Hash::make('test');
$2y$10$QRgaiS6bpATKKQeT22zGKuHq.edDfXQc2.4B3v.zaN.GtGwoyQuMy
return Hash::make('test', array('rounds'=>12));
$2y$12$Az4ZMmEhUxYQ3CcgfnaTt.C1MYxmFfjNxpjgPtye0uKoMBnirw8TC

These are the results returned for me.. of course, you will get different results. But the takeaway points are:

1. Hash make returns a different hash each time. This is quite curious.
2. The output is always a 60 char string
3, The initial characters of the hash are metadata (first 7 chars)

This blog post will attempt to demystify some of the inner workings that cause Hash::make() to behave this way. So, how does Laravel do this? how then is the password check performed? and finally what is the advantage that this offers?

How?

Internally, Hash::make() encrypts using the bcrypt function and Blowfish algorithm. For php>5.5, password_hash() and password_verify() functions are used. For previous php versions, a compatibility library irc_maxell/password_compat is pulled in by composer. In fact, reviewing the source code of the password_compat library provides a lot of insight into the inner workings of password_hash() and password_verify().

According to the php documentation (http://www.php.net/manual/en/function.crypt.php), “Blowfish hashing with a salt as follows: “$2a$”, “$2x$” or “$2y$”, a two digit cost parameter, “$”, and 22 characters from the alphabet “./0-9A-Za-z”.”

So, in our trial run 1 above,
$2y$ represents use of blowfish algorithm with salt
10 is the default “cost” factor
A 22 character “salt” is (randomly) generated and appended to the previous two components
this is followed by the encrypted password.

The php crypt function (that is internally used to implement bcrypt) is then called :

crypt($password, $hash);

where $password is the string to be hashed, and $hash is the concatenated value of “$2y$”.”10″.”22 random characters from 0-9, a-z, A-Z”.”$”. This function returns the 60 character hash string associated with the password.

The cleverness of this is that the algorithm, salt and cost are embedded into the hash and so can be easily parsed out into  individual components for reconstruction/verification (Please see relevant sections of the php crypt source code at https://github.com/php/php-src/blob/master/ext/standard/crypt.c#L258). Because of this, you don’t need to store the salt/cost separately in a database table.

Password check

For checking the password (wrapped by password_verify() for php>5.5), an internal function semantically equivalent to :

return crypt($password, $hash)==$hash;

is used. The original hash that was generated by the encryption is passed to the function (this is key). The supplied password is salted and run through the crypt function to generate the original hash (provided the same password is used). Note that internally, the crypt function only cares about the first 29 characters of the passed in hash (7 metadata+22 salt). Remember that the crypt function implements a one-way hash – there is no way to retrieve the password from the encrypted hash. The only way to verify password equivalence is to hash it using the same salt and compare the results. Both the Hash::check() and Auth::attempt() methods in Laravel run the same check.

Why?

The conventional method of using a md5 or sha1 to generate password hashes is insufficient for modern security requirements. Due to the advancement in computation power, it has become trivial to use a Rainbow Table (http://en.wikipedia.org/wiki/Rainbow_table) to crack passwords stored using md5/sha1 hash. The use of bcrypt function avoids this vulnerability. So, you now have a one-way hash function that is both secure and easy to implement.

Nginx config for hosting multiple projects in sibling folders

I have recently begun the process of migrating (laravel) apps into using Nginx+PHP-FPM.

Needless to say, it is definitely more challenging than configuring good ol Apache! For starters, you absolutely must know regular expressions fairly well. Nginx makes extensive use of regexes to figure out matching rules for urls. The second paradigm shift is learning that Nginx does configs on a “per-application” basis. What I mean is, you cannot just setup the server one time, and expect to drop in apps into the web folder, and hope things work (this is especially true for apps that use clean urls via htaccess rewrites). So, prior to setting up any web application, expect to work a bit on tweaking the Nginix config. The reward is a nimbler web server that performs much better under load.

I put together a config file that serves multiple Laravel applications stored in sibling folders (on a single server). So, http://192.168.33.10.xip.io/project1 will serve up application 1, and http://192.168.33.10.xip.io/project2 will serve up application 2.

/Vagrant is the root web folder, and /project1 and /project2 are sibling folders within the vagrant folder containing full laravel applications.

Hope you find this useful!

Moving From Zend Framework to Laravel 4

Let me preface this blog with the following: I have been a programmer for the past 12 yrs and have used php for nearly 8 yrs, ZF1 for nearly 3 yrs (10+projects) and ZF2 since its inception. So, I understand the framework(s) quite well and have given it a fair amount of trial time.

About 2 months ago, I stumbled upon the Laravel framework. A couple of hours into studying Laravel, I had an epiphany : This is what all other frameworks should strive to be! Easy, Functional, modern and completely out of the way. While its CodeIgniter underpinnings are easily discernible based on the folder structure and config files, it is quite a radical departure in terms of the underlying code. Laravel 4 in particular embraces all prevailing best practices in the PHP world.

In comparison, both ZF1 and ZF2 are complicated, and require a steep learning curve. I kid you not, I was up and running with Laravel 4 in about 3 hours! (properly understanding my first “hello world” with ZF2 took me a week).
In my humble opinion, ZF2 is over-engineered, demanding more attention than the actual web application at hand. The reliance on (deeply nested) arrays for everything from route configs to parameters makes coding a chore. See, while arrays are speedy and flexible, they are a debugging nightmare. You get pretty much Zero IDE support (autocomplete, code completion etc). You have to remember verbatim all the required keys (I kind of got around this using netbeans code templates.But the templates became so many in number that remembering those presented a problem!).

Two projects later, I can confidently say that there is nothing that I can do in ZF2 that I can’t do using Laravel 4 (and in lesser time). The fact that L4 ties into composer/packagist means that pretty much any open source php project(on packagist) can be utilized in a Laravel project. In fact, L4 uses ‘monolog’ for logging, ‘swiftmailer’ for emailing and ‘symfony’ for the HTTP core and command line interface. All while providing a very ‘laravelesque’ approach to coding. There really are no limits. Very cool indeed!

Although I feel a certain closeness with ZF due to the sheer amount of time I spent with it, I feel the time is right to switch to L4 for future projects. I think L4 has done a LOT of things right, and deserves credit for it. The Eloquent ORM is very easy to work with. Routing in Laravel is an absolute joy! It does much of the heavy lifting when it comes to RESTful interfaces.
Form management is beautifully implemented. It is trivial to implement custom form/html controls.The DI mechanism is very expressive.So are Filters and Events. The Blade templating engine has an uncanny resemblance to the Razr engine used by ASP.NET MVC (which I really like!).
Although it looks like L4 uses an abundance of static methods, in reality it harnesses the __callstatic() php magic method to actually load objects from the DI container. The L4 command line tool “artisan” is also very well executed. Unit testing is very simple and works right out of the box (no lengthy setups required prior to running phpunit).

L4 has indeed improved my productivity quite dramatically 🙂