When I learned Ruby on Rails, I found out about Capistrano. This whole automated deployment thing seemed pretty neat. But then my Rails project finished, and I was back to working on a PHP site. There I was, coding along in naive bliss.
Then I started working on voteforchange.com for the Obama Campaign. Nick and I didn’t have the biggest iron or the most … process. But we did have Capistrano for PHP.
A little light bulb went off in my head.
Heather’s sites were a great candidate for Capistrano deployments. I could stick everything in subversion … develop on my PowerBookMacBook Pro and deploy to the DreamHost web server. Professional deployment techniques for a site with an engineering team of one.
One thing was bothering me, though. The VFC Capistrano script was so much longer than the ones I was using for my Rails site. Longer. More complicated. Less elegant.
We were making our own folder structure:
t = Time.now folder = "#{t.year}"+"#{t.month}"+"#{t.day}"+"#{t.hour}"+"#{t.min}"+"#{t.sec}"
Wasn’t Capistrano supposed to do that for me? Yes, it was. So I started looking around. Everyone was pointing at Jon Maddox’s instructions. Those were a good starting point, but I had to make a few changes. Here’s what I learned.
How to deploy PHP sites with Capistrano 2
- Cache your authentication credentials
- Configure Capistrano
- Run Capistrano’s initial setup
- deploy
Cache your authentication credentials
You’re going to want to set up passwordless authentication for both SSH and Subversion. Otherwise, you’ll get prompted every time you check in or deploy. (This also makes using TextMate‘s subversion bundle harder.)
- Cache your SSH credentials. Generate your keypair. On your local machine, do this:
ssh-keygen -t rsa chmod -R 700 ~/.ssh
Repeat this on the web and svn servers.
-
Upload your public key from your local machine to the web (svn) server:
ssh www.mysite.com "echo '`cat $HOME/.ssh/id_rsa.pub`' >> .ssh/authorized_keys"
Do the same thing from the web server to the svn server.
-
Often, your username on your local machine is not the same as your username on the subversion server. To tell subversion what name to use, edit
~/.ssh/config
, adding lines like these:Host svn.mysite.com User joeblow Host www.mysite.com User joeblow
Test this out by typing
ssh www.mysite.com
. If you still get prompted for a password, make sure the permissions are correct on the webserver (chmod -R 700 ~/.ssh
). - On the web server, cache the subversion credentials. Just check out the repository:
svn co svn+ssh://svn.mysite.com/svn/mysite/trunk
Enter your password when prompted. Subversion will cache this information in
~/.subversion/auth/
. You can now delete the trunk directory.
Configure Capistrano
Normally, you prepare a project for Capistrano by typing capify
. You don’t really need to do that for PHP sites, because you don’t need a two-part Capistrano script. Instead, just create a text file called Capfile
that looks like this:
load 'deploy' if respond_to?(:namespace) # cap2 differentiator Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } set :use_sudo, false set :home_path, "/var/www/mysitename" set :checkout, "export" set :repository, "svn+ssh://svn.mysite.com/svn/mysite/trunk" role :web, "www.mysite.com" namespace :deploy do task :restart do end end
Run Capistrano’s initial setup
Run the Capistrano setup command: cap setup
. This creates the releases/
and shared/
directories on the server.
Deploy
To get the site up, just run cap deploy
.
Tips, tricks and notes
- Following DreamHost’s Capistrano instructions, I set
use_sudo
to false. On a shared hosting site, I didn’t have root. Duh. Why is this the default option on Capistrano? Dunno. - You need to disable Capistrano’s restart task. Since we aren’t using Rails, there was no mongrel, and nothing to restart.
So I tried this:
task :restart do end
I still got an error. It turns out you have to specify the Capistrano namespace:
namespace :deploy do task :restart do #nothing end end
-
What about database passwords for your web site? You don’t want to store those in the subversion repository. As the Cap FAQ explains, stick a configuration file elsewhere on the server, and copy in a post-deploy task.
task :copy_database_configuration do run "cp #{home_path}/config/#{config_file} #{release_path}/helpers/config.php" end after "deploy:update_code", :copy_database_configuration
-
If you’re developing with other people, having your SSH script prompt for your SSH username can be helpful:
set(:user) { Capistrano::CLI.ui.ask("SSH username: ") }
-
You can configure your script to do different work on staging versus production deployments. There are probably better ways to do this, but here’s what I have working for me. Suppose you have staging and production on the same server:
if ENV['PRODUCTION'] set :home_path, "/var/www/production" else set :home_path, "/var/www/stage" end
By default,
cap deploy
deploys to stage. To deploy to production, runPRODUCTION=1 cap deploy
(assuming bash). -
If you’re deploying WordPress, you will want to make sure the uploads directory is writeable. You might also want a special .htaccess file put in place (I use different ones for localhost and production). Here’s how to do this:
task :after_symlink do run "cp #{current_path}/config/show_htaccess #{current_path}/.htaccess" run "chmod -R a+w #{current_path}/wp-content/uploads/" end
Of course, your subversion deployment will overwrite your existing uploads directory, so this particular example is of limited value.
More details
Clayton Lengel-Zigich’s tips for using Capistrano with PHP and the Capistrano FAQ are very helpful.
Thanks for taking the time to note this in detail. It will definitely be useful for my current project. Thanks again.
Similar manual in russian language there is on http://wmparser.ru/content/viewArticle/73
You can upload public keys with ssh-copy-id.
e.g.
ssh-copy-id user@host