Tuesday, March 1, 2016

Setting up Capistrano for Laravel 5 in Ubuntu

Capistrano for Laravel 5 in Ubuntu

Install Capistrano in Ubuntu


gem install capistrano

SSH access

Capistrano deploys using SSH. Thus, you must be able to SSH from the deployment system to the destination system for Capistrano to work. You can test the SSH connection using a ssh client, e.g.

ssh your_username@destinationserver

If you cannot connect, in order to be able to do this you need two things:
1) An account on the target machine
2) Your public key added to ~/.ssh/authorized_keys file.

So, SSH into the staging machine and add your key to username’s ~/.ssh/authorized_keys. You should now be able to pull from git on the server without it asking you for identification.

Server privileges

In order to deploy, the user needs some special privileges.

First add a group named deploy to the server:

sudo groupadd deploy

We now need to add ourselves and any other users that need access (other developers) to the deploy group, and the user that executes our web server. Opening the /etc/group file, and look for the line that beings with deploy. We append users, comma delimited. In this example I am using a nginx server.

deploy:x:1003:your_username,nginx

Now we have a deploy group, whose members include us, any other developers who will be deploying and the web server user.

Add the deploy group to the /etc/sudoers. For that create file /etc/sudoers.d/01deply to enable members of deploy group to access root via sudo without passwords

%deploy ALL = (ALL) NOPASSWD: ALL

and set up 440 permissions to the file

chmod 440 /etc/sudoers.d/01wheel

Project structure

Now define the new structure for your project

projectname
 |-- components
 |-- deploy

all of then will have 755 permissions and g+i flag that indicates that old the subdirectories will have the same privileges as the project directory.

sudo mkdir -p new-project/components 
sudo mkdir -p new-project/deploy 
sudo chmod -R 775 new-project 
sudo chmod -R g+i new-project 
sudo chown -R your_username new-project 
sudo chgrp -R deploy new-project

On the local machine

Go to the Laravel root project's folder and run

cap install

The command creates the following structure:

mkdir -p config/deploy 
create config/deploy.rb 
create config/deploy/staging.rb 
create config/deploy/production.rb 
mkdir -p lib/capistrano/tasks 
create Capfile Capified

where staging.rb and deploy.rb are the files that we are going to work.
We have to create an additional file to store our credentials:

vi config/myconfig.rb

set :ssh_options, { user: 'your_username' }
set :tmp_dir, '/home/your_username/tmp'



Adding Task to Capistrano

Vendor files and config files

Edit the config file deploy.rb

vi config/deploy.rb

and add the next lines after the lock line.

set :application, 'new-project'
set :repo_url, 'git@github.com:githubusername/project.git'

set :deploy_to, '/var/www/new-project/deploy'

components_dir = '/var/www/new-project/components'
set :components_dir, components_dir

# Devops commands
namespace :ops do

  desc 'Copy non-git files to servers.'
  task :put_components do
    on roles(:app), in: :sequence, wait: 1 do
      system("tar czf .build/vendor.tar.gz ./vendor")
      upload! '.build/vendor.tar.gz', "#{components_dir}", :recursive => true
      execute "cd #{components_dir}
      tar -zxf /var/www/new-project/components/vendor.tar.gz"
    end
  end

end


Now configure the staging.rb condig file

vi config/deploy/staging.rb

adding the next lines:

role :app, %w{your_username@destinationserver}

require './config/myconfig.rb'

namespace :deploy do

  desc 'Get stuff ready prior to symlinking'
  task :compile_assets do
    on roles(:app), in: :sequence, wait: 1 do
      execute "cp #{deploy_to}/../components/.env.staging.php #{release_path}"
      execute "cp -r #{deploy_to}/../components/vendor #{release_path}"
    end
  end

  after :updated, :compile_assets

end


# Devops commands
namespace :ops do

  desc 'Copy non-git ENV specific files to servers.'
  task :put_env_components do
    on roles(:app), in: :sequence, wait: 1 do
      upload! './.env.staging.php', "#{deploy_to}/../components/.env.staging.php"
    end
  end

end


Deploy

Let's try if everything works. Check if the tasks are available for cap writing cat -T.

Now let's transfer the config and vendor files to the server:

cap staging ops:put_components 
cap staging ops:put_env_components

Once the files are in the server we can deploy

cap staging deploy


Possible errors

Is you receive an error like this:

the deploy has failed with an error: Exception while executing as your_username@destinationserver: git exit status: 128 git 
stdout: Nothing written git stderr: Error reading response length from authentication socket. 
Permission denied (publickey). 
fatal: Could not read from remote repository.

that means you have to follow an additional step in your local terminal. Run

eval $(ssh-agent) 
ssh-add ~/.ssh/id_rsa

And try again, e.g.

cap staging deploy

That's all

Hope helps