Deploying WordPress with Capistrano

Capistrano is a command line utility for deploying web applications to one or more servers. It was primarily developed for Ruby on Rails applications, but applicable to all sorts of web applications these days, including of course WordPress. Honestly, I discovered Capistrano a couple of weeks ago during Mark Jaquith’s talk at WordCamp San Francisco 2011 so I decided to give it a go.

I’m not a Capistrano expert (yet) and in this post I’ll try to give you an overview how to set it up and how to deploy WordPress applications (websites) in seconds. We’ll work with only one server today but the principles in deploying to two or more are pretty much the same. I’ll probably write a few follow up posts on this topic as I get better, so stay tuned ;)

First of all I’d like to thank Mark Jaquith for his wonderful presentation at WordCamp San Francisco 2011, for his follow-up interview and for doing a quick review of this post before it went public. Thanks Mark! And now back to Capistrano…

What is Capistrano?

As mentioned in the introduction of this post, Capistrano is a command line tool for deploying websites. A typical web application resides in a version control repository (Git, Mercurial or perhaps Subversion). It’s being worked on locally (on one or many computers) and when the time comes, you access your production server, typically via SSH, and then pull or checkout the new stuff from the repository — i.e. you deploy your application.

If you’re doing things this way, you’re on the right track, since you can always checkout to a previous tag or commit (rollback) if something goes wrong. If you’re not, then you should be.

Capistrano wraps the whole deployment process in a few commands which are easy to understand and memorize, so in a few minutes you won’t be SSH’ing and Git pull’ing anymore, you’ll simply do cap deploy and you’re ready to go, the rest is done for you. Capistrano makes rolling back as easy as deploying with cap deploy:rollback. With Capistrano you can also manage multiple servers and multiple stages and the most exciting part is that you can (and should) write your own deployment scripts!

That should give you a basic overview of what Capistrano is and how it works, so let’s move over to the next part.

Installing Capistrano

First things first, since Capistrano is written in Ruby you’ll have to get Ruby working in your local environment. Note that Capistrano sits and works from your local (or development) computer and not at the production web server, so most of the stuff you’ll do today is going to be local. You should get a little familiar with Ruby at some point, but copy pasting your way through will work.

Ruby is pre-installed on some linux distributions, on others you can get it from the software manager. For Windows and Mac OS X I’ll recommend the following:

Ruby comes bundled with a package manager called gem so to install Capistrano, type the following gem commands in your terminal:

sudo gem install capistrano
sudo gem install railsless-deploy
sudo gem install capistrano-ext

The first package is Capistrano itself, the second package allows deploying non-rails applications with Capistrano and the third package bundles some great Capistrano extensions, like staging, etc. You won’t really need the extensions for this tutorial but you’ll probably need them later on.

Getting Ready to Capify WordPress

I’ll make a few assumptions before we go ahead. We talked about version control earlier, so I’ll make the assumption that you’re using Git. We talked about SSH access and although Capistrano can ask your for your SSH username and password, you’ll be better off with public and private SSH keys.

I’ll also assume that you’re using RSA keys to access your Git repository, so at no point you should be asked to enter a password. Last assumption that I’m going to make is that your whole WordPress directory is in your Git repository, not only your theme or plugin files or directories. This includes your WordPress configuration which we’ll talk about later, but doesn’t include your wp-content/uploads directory since that would be a little crazy. To wrap up on the assumptions:

  • You’re using Git and have access to a remote Git repository
  • You have SSH access to your production server via RSA keypair
  • You have RSA keypair access to your Git repository
  • Your whole WordPress directory is under version control

The RSA keys part is perhaps the most difficult here, so here are some links to tutorials about that:

Also note that for your Git repository, both your local and production environment have to have public key access, meaning that you should be able to carry out a git pull on your production server without being asked for a password.

WordPress Configuration

Your WordPress configuration should be under source control as well and this doesn’t mean that your database credentials should be identical on your local computer and on your production server, in fact that would be quite insecure. So how do you have one wp-config.php file for both? Well Mark Jaquith suggested to structure your configuration file like this:

if ( file_exists( dirname( __FILE__ ) . '/local-config.php' ) ) {
    include( dirname( __FILE__ ) . '/local-config.php' );
} else {
    define( 'DB_NAME', 'production_db' );
    define( 'DB_USER', 'production_user' );
    define( 'DB_PASSWORD', 'production_password' );
    define( 'DB_HOST', 'production_db_host' );
}

This means that whenever there is a file called local-config.php sitting next to wp-config.php it’ll include that file which will provide the database settings for your local environment and if there isn’t one, define the values for production. You then ignore the local-config.php file from your Git repo using .gitignore to make sure it doesn’t end up on your production server.

While this approach works, I like to take a different one which might be a little bit more complicated but allows staging, like this:

if ( file_exists( dirname( __FILE__ ) . '/../env_local' ) ) {

    // Local Environment
    define('WP_ENV', 'local');
    define('WP_DEBUG', true);

    define('DB_NAME', 'local_db_name');
    define('DB_USER', 'local_db_user');
    define('DB_PASSWORD', 'local_db_password');
    define('DB_HOST', 'local_db_host');

} elseif ( file_exists( dirname( __FILE__ ) . '/../env_playground' ) ) {

    // Playground Environment
    define('WP_ENV', 'playground');
    define('WP_DEBUG', true);

    // ... playground db constants
} else {

    // Production Environment
    define('WP_ENV', 'production');
    define('WP_DEBUG', false);

    // ... production db constants
}

Now this may seem a little crazy at first (I also stripped a bunch of defines for brevity) but it really is simple. Note that my whole website installation is in a directory called application so the config file resides in application/wp-config.php.

So I first look for a file called env_local in a directory one level up from wp-config.php (which is application) and if it’s there, define the database settings for the local environment. If it doesn’t exist I look for one called env_playground (this is how I called the testing/staging server) and define the database settings for my testing server. If none of the two exist I assume that it’s the production server, so I define the production database parameters.

Hope this isn’t too weird ;) Anyhow, you should put env_local, env_playground and env_production into .gitignore and make sure none of them get inside your repository. You’ll create one locally to work and we’ll get Capistrano to create the production file when deploying. Staging might be a follow-up tutorial ;)

You’re almost done, final step is to check how things work by manually doing a git clone, checkout or pull on your production environment and make sure the configuration file is okay and that everything works as expected. Ready for action? Capify!

Capify WordPress

Let’s revisit our repository and website structure, assuming your website is called project:

  • project is under source control
  • project/application is where WordPress lives
  • project/application/wp-config.php is your WordPress configuration file
  • project/env_local exists only in your local environment
  • project/application/wp-content/uploads is not under source control

Great! Now fire up your command line or terminal, create a new directory somewhere in your local environment, not necessarily your project directory, in fact your Capistrano files shouldn’t be in your project’s source at all, otherwise it can create a chicken-egg situation, so my suggestion is to keep all Capistrano files in a totally different directory tree and you can put them under source control as a different project, perhaps /home/user/deployments/project_name/. And now, type this:

capify .

That’s capify followed by a space and a dot. Congratulations, you have capified WordPress! But don’t rush to deploy yet, we’ve still got some Capistrano configuration to do. If you browse the directory you just capified (let’s call it your deployments directory) you’ll now see a file called Capfile and a directory called config. Since Capistrano was built for Ruby on Rails, we’re going to do some (almost) heavy modifications to fit our needs.

Open the Capfile first and remove all it’s contents. Yes, remove everything there’s written and pump in the following:

require 'railsless-deploy'
load 'config/deploy'

The first line loads the railsless-deploy module that will be used when not dealing with rails applications and the second line will load the deploy.rb file inside our config directory, so let’s take a look at that right now. You’ll see some pre-written template, which again is for rails applications, so remove everything and type in the following:

set :application, "your-application-name"
set :repository, "git@github.com:you/your-project.git"
set :scm, :git
set :deploy_to, "/home/path/to/project/"

set :deploy_via, :remote_cache
set :copy_exclude, [".git", ".DS_Store", ".gitignore", ".gitmodules"]

server "example.org", :app

It’s quite easy to follow along, even if you don’t know Ruby/DSL. First few lines set some variables required by Capistrano, deploy_to sets the directory where your application will be deployed. We let Capistrano know about our application and repository. The :deploy_via option is set to :remote_cache which means that a remote git checkout will be cached on each server for faster deploys. The :copy_exclude makes sure you don’t deploy your git and annoying OS X files.

The last line sets the host for your server for the :app role. You don’t have to worry about roles yet, just keep in mind that this line represents the host to which Capistrano will connect via SSH to deploy your application.

Don’t rush to set your deploy_to path to a real target, but rather create a directory which doesn’t necessarily has to be live, you’ll just see what’s going on inside it via SSH. You’ll be able to change these configs any time, so make sure you’re comfortable with them before going live. So here’s where we’re at:

  • project is under source control
  • project/application this is WordPress
  • deployments/my_project/Capfile this is the Capistrano capfile
  • deployments/my_project/config/deploy.rb this is the deployment script

And now you’re ready to carry out your first deployment task.

Your First Capistrano Deployment

Capistrano tasks all start with cap and you have to be somewhere in your deployments directory tree since Capistrano will need to find your Capfile to carry out your tasks. So in theory, with the structure and the configuration that you have created, issuing a cap deploy command would result in a deployment task on your production server, inside the deploy_to path that you have set.

This means that Capistrano will log on to your example.org server, browse to the /home/path/to/project/ directory and clone the HEAD commit from your Git repository.

So, let’s see if this works, from the command line type:

cap deploy

You should see a lot of verbose things from Capistrano, it’s basically telling you what it’s doing at each and every stage. If at the end of it all you see a transaction: commit message, this means that your deployment has been successful. If not, something has gone wrong…

Let’s now connect to our server via SSH and see what the deploy has really done. Inspect the /home/path/to/project/ directory and you’ll see two things — a releases directory and a current symlink. This is the nature of Capistrano so you should get familiar with it (although the names can be changed if needed). Every release is deployed inside the releases directory under a unique name and if the transaction was successful, the current symlink will point to that release.

By now you should have figured out that you need to point your web server (Apache or nginx) to the /home/path/to/project/current/application directory to reach WordPress. Right? Try and make some changes, commit and push them to your repository and deploy again, you’ll see that the current symlink now points to a different release — your newest one.

Rolling Back & Cleaning Up

So what if things have gone wrong? Try it out:

cap deploy:rollback

This is a very fast task which will simply make your current symlink point to the previous release. Then cap deploy to move forward again. Pretty simple, eh? Right, Capistrano will store every deployment in it’s own folder under releases and it might get huge if you forget to:

cap deploy:cleanup

That will leave the latest 5 releases (or whatever the default setting is) for you to roll back to and get rid of the older ones. If for some reason the clean up didn’t work and you’ve seen a sudo-related message, this means that Capistrano has tried to use the sudo command to get rid of the old releases. You can either set up password-less sudo, which is not very secure, or just add the following to your deploy configuration file.

set :use_sudo, false

There are many more cap commands (or tasks) that you can try out and you can even write your own, but this is out of scope of this tutorial. To get a list of all available tasks you can use the following command:

cap -T

Capistrano & Shared Files

Now that Capistrano is set up to deploy and rollback your application you’ll need to somehow manage shared files across releases. I’m talking about the wp-content/uploads directory primarily. The uploads directory is ignored in your Git repository (which is correct) so Capistrano won’t deploy it. Let’s create a shared directory on your production environment and an uploads directory inside it. Here’s what you should have on your production server:

  • /home/path/to/project/releases/ is where your releases are
  • /home/path/to/project/current/ is a symlink to your current release
  • /home/path/to/project/current/application/ is your directory root (that is set up on Apache or nginx)
  • /home/path/to/project/shared/ is the shared data across all the releases
  • /home/path/to/project/shared/uploads/ is your new uploads folder

For Apache or nginx to access your uploads, you’ll need a symlink in current/application/wp-content/uploads that will point to shared/uploads and the uploads directory in shared should be writable by the Apache/nginx user (typically www-data) so that new files can be written inside.

You can easily do this while you’re in SSH with the ln command in the current/application/wp-content directory, but beware that your next cap deploy will erase all your changes and you’ll be left without your uploads again, so this has to be done with Capistrano and it’s quite easy to do so.

Assuming that you have created the shared/uploads directory, go back to your local environment and edit the deployment configuration file and right after the server command add the following snippet:

namespace :myproject do
    task :symlink, :roles => :app do
        run "ln -nfs #{shared_path}/uploads #{release_path}/application/wp-content/uploads"
    end
end

after "deploy:symlink", "myproject:symlink"

Save and close, and then run cap deploy again. If everything goes well you can peek inside the current/application/wp-content directory and see that there’s now a symlink pointing to the shared uploads folder that you have created, great!

The above snippet shows how you can easily create your very own tasks and execute them during certain events (after deploy:symlink in our case). The task itself simply runs an ln command to create the symlink and once you understand how that works, it’s really easy to do other stuff, like create that env_production file I talked about earlier, you can do it in the same task for brevity, right after the first run:

run "touch #{release_path}/env_production"

And voila. An empty env_production file will be created when deploying to your production server, so your configuration file should now work as expected, hopefully it does. It’s now time to point your Apache or nginx configuration to your new directory — the current/application folder. And that brings us to an end for this tutorial.

Conclusion

Today you (should) have learned about Capistrano, installing and configuring it for production. Of course Capistrano itself is much more powerful than simple single-server deploys. You can get it to deploy to multiple servers, you can get it to stage your deploys and you can even get it to migrate your databases. The most difficult is the first step though, so hopefully this tutorial has shown you how easy it to deploy WordPress like a pro.

I’ll maybe write a series of follow-up tutorials on working with WordPress and Capistrano, but it really depends on your feedback. Do let us know if this was clear enough, whether there are some things I should clarify and were you at all able to follow along. Tell us how you feel now that you’re deploying with Capistrano.

Use the comments section below to leave your thoughts and don’t forget to follow our RSS feed! Thank you for reading!

Wait, there’s more! Please proceed to the next part of this tutorial: Deploying WordPress with Capistrano Part 2: Staging Servers, Tagging & Database Security.