Deploying Laravel with Capistrano 3
Deploying PHP with Ruby?
Step back to the days where you would deploy your application by FTP’ing into your server and copying files over or directly editing on the server. Those days aren’t long gone but, the tools to help you integrate better practices and source control have come a long way.
Github
If Github isn’t part of your team’s or personal workflow seriously consider it our a product like it. At Koofers we have recently made the move to Github for our product development and project management. It makes it easy to coordinate tasks and issues with remote teams. Capistrano allows you to pull in the latest version of your code and deploy it directly to your production servers.
What Does Capistrano Do?
Capistrano deploys your source code and keeps versions locally on the server for easy rollback. It aids in installing all the dependencies and setting up file permissions all via an easy configuration file.
Install
Deploy.rb
We will go step by step through the deploy.rb file and at the end I will post a fully functioning version.
lock ‘3.1.0' # Capistrano 3set :application, “” # The name of your appset :scm, :git # Tell Capistrano we are using GIT
set :repo_url, “” # Your Github Repositoryset :keep_releases, 3 # Keep the last 3 releasesset :use_sudo, false # Don't use sudo
set :ssh_options, {
keys: %w(~/.ssh/id_rsa) # Use our local SSH keys
}
I break the rest of my tasks out into separate files located in the lib/capistrano/tasks.
Compser.cap
This file sets up and runs composer install on the directory for php dependencies.
desc “Running Composer Self-Update”
task :update do
on roles(:app), in: :sequence, wait: 5 do if test “[“, “-e”, “/usr/local/bin/composer”, “]”
execute :composer, “self-update”
else
execute :curl, “-sS”, “https://getcomposer.org/installer”, “|”, :php
execute :mv, “composer.phar”, “/usr/local/bin/composer”
end end
end
First we check to see if composer is installed. If it is we run self-update or we download and install it and at to the bin.
desc “Running Composer Install”
task :install do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :composer, “install —no-dev —no-scripts —quiet —optimize-autoloader”
end
end
end
Then we run composer install and hide all the output and updates.
desc “Running Composer Dump Autoload”
task :install do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :composer, “dump-autoload”
end
end
end
This command is just a utility and isn’t used in our deploy script specifically. All of these tasks are wrapped inside of:
namespace :composer # tasks go hereend
Then we register these tasks with Capistrano under the namespace deploy.
namespace :deploy do after :updated, “composer:update” # composer namespace
after :updated, “composer:install” # install taskend
Laravel.rb
All of the following tasks are under the “laravel” namespace.
desc “Setup Laravel folder permissions”
task :permissions do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :chmod, “u+x artisan”
execute :chmod, “-R 777 app/storage/cache”
execute :chmod, “-R 777 app/storage/logs”
execute :chmod, “-R 777 app/storage/meta”
execute :chmod, “-R 777 app/storage/sessions”
execute :chmod, “-R 777 app/storage/views”
end
end
end
This task sets all the file permissions on the storage files so that we can write to them.
desc “Optimize Laravel Class Loader”
task :optimize do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, “artisan clear-compiled”
execute :php, “artisan optimize”
end
end
end
Optimize the class loader so that our application is optimized for production.
desc “Run Laravel Artisan migrate task.”
task :migrate do
on roles(:app), in: :sequence, wait: 5 do
within release_path do
execute :php, “artisan migrate”
end
end
end
Run the Laravel Artisan migrate task so that our database is up to date.
namespace :deploy do after :updated, “laravel:permissions”
after :updated, “laravel:optimize”
after :updated, “laravel:migrate”end
Apache.rb
Finally, this is on that I have struggled with for a long time. I do not want to hard code passwords and other configuration values into my code. So I use the handy .local.env.php that Laravel provides but, this is hard to translate into environment variables on the server. Capistrano provides an API to set session environment variables. What this script does is take those and copy them into an Ubuntu environment. Specifically it places the variables in the /etc/environment.
namespace :apache do desc “Copy Environment Variables”
task :sync do
on roles(:app), in: :sequence, wait: 5 do
execute :echo, “-n /etc/environment”, raise_on_non_zero_exit: false
fetch(:default_environment).each do |key, value|
execute :echo, “’#{key}=\”#{value}\”’ >> /etc/environment”
end
execute :service, “apache2 restart”
end
endendnamespace :deploy do after :finishing, “apache:sync”end
This copies all the variables from the Capistrano :default_environment variables to the /etc/environment.
Finally the Production.rb file
This file is an environment that you want to deploy to. You can have staging.rb or development.rb.
server ‘example.com’, user: ‘root’, roles: %w{web app db}set :default_environment, {
“TEST_ENV” => “production”,
}
To run your deployment:
cap production deploy
If you have any questions or comments feel free to reach out to me on Twitter @arhea10. I hope this helps you as much as you helped me.