Since one year or two (I pushed a quick tutorial some months ago on Github),
I intensively use Capistrano as well as its “Symfony” variant,
capifony. And I’m really happy. I deploy in production
ten times a day, and it really helps getting things done, securely.
For a new project I work on, I decided to go with it, again. But it’s time to evolve, so I decided to go with Capistrano 3.x. As of this day (2013-11-27) the version 3.0 seems stable, yet not complete though.
The documentation is still at its early days, and I’m obviously not a Rubyist. However, things have clearly evolved, in the good way, and now Capistrano is not shipped with all the Ruby/Rails tasks that we, PHP guys, don’t need. The tool is not bloated with all those things and that’s good for us.
Anyway, I decided to dive in the process of deploying a project with the new Capistrano 3.
As the migration note states, it is recommended to start over, do no try to make Capistrano 2.x
Capfile works with Capistrano 3.x, it won’t, work, at, all.
One of the first thing I mentioned when installed Capistrano 3.0 is that I was not able to override paths! By default, Capistrano 3.x
(command which generates a skeleton deployment scripts) generates files in
config/ folder. Maybe that’s the way to go in Ruby projects, but that’s
not my taste, and I sometimes like to make things work how I want they work (yeah I’m that kind of guys).
Luckily, an issue had been posted a while ago, and luckily again, it got merged.
Being merged on an unstable branch, I had to build the gem myself from source, here we go:
1 2 3
Easy isn’t it?
Now that we’ve a more customizable version of Capistrano, we can get back to work.
So the first thing to do is to generate the default deployment scripts shipped by Capistrano:
I like my deployment scripts to live in, guess, the
deployement/ folder, I move them there.
It makes more sense to me to move stages configuration there.
So far we have a
Capfile which looks like this:
1 2 3 4 5 6 7 8 9 10 11 12
And our folder structure looks like this:
1 2 3 4 5 6
deploy.rb global configuration, two stages (production & staging), no custom tasks, yet.
To get a minimal working deployment script, we have to configure some variables:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Note that the
deploy_path variable is set to
/var/www/domain.tld but the actually deployed project
will live in
releases/[some-release-date] and symlinked to
current/, so any virtualhost should have
its document root sets to
Now, we need to configure the production stage (or the staging stage, no matter):
Time to test, run
cap production deploy. Capistrano should now be able to connect to the remote server,
create the folders (your deployment user should have the permissions, use POSIX ACL for this), and clone
the remote repository.
We are done for now, the next step is to create custom tasks. For now, I’m only interested in two things:
Composer has already a gem for this, so we’ll use it.
For the sake of simplicity I’ll start to add it to a
Gemfile, it is very similar to our
it is used to define dependencies requirements for a project.
1 2 3
Then make sure the gem is actually loaded by Capistrano, in
It will automagically execute itself after the
Now, let’s take a look at grunt. Grunt relies on npm/bower packages to execute tasks. In order to properly run grunt on your remote server, we need to make sure nodejs & npm are available.
Grunt itself being a library, not an actually cli command, we also need to install
grunt-cli npm package, it should be done once, and globally on the remote server.
(In my case it is part of my provisioning process using puppet)
And guess what, the same apply to bower:
Our server is ready to get fed with some bytes of deployment process.
Now, let’s add the according gems to our
1 2 3
I decided to use a Capistrano task to resolve bower dependencies but it could have been done within grunt itself with the proper plug-in.
Configure the task we want grunt to run:
If not set, it will execute the
default task, as if we ran
grunt command alone.
To make sure our tasks will execute in the correct order (hence,
we add the following statement at the end of
We are done.