In the first part of this tutorial we met Capistrano — a command line utility to deploy your web application. We went through the process of installing Capistrano and “capifying” WordPress, a new look at the WordPress configuration file and the shared uploads directory.
Today we’ll dig deeper into Capistrano and cover three topics that may come in useful for larger projects. We’ll talk about staging, where deploys are made to a testing server by default and on a production server on demand. We’ll also talk about deploying with Git tags instead of the master branch. Finally I’ll show you a trick on how to hide your production database credentials, useful for large-scale projects where many developers are involved.
Recap
Recap from the previous tutorial, our deploy.rb file in the config folder does the WordPress deployments for us and here’s what it looked like at the end of that tutorial:
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 :use_sudo, false
set :deploy_via, :remote_cache
set :copy_exclude, [".git", ".DS_Store", ".gitignore", ".gitmodules"]
server "example.org", :app
namespace :myproject do
task :symlink, :roles => :app do
run "ln -nfs #{shared_path}/uploads #{release_path}/application/wp-content/uploads"
run "touch #{release_path}/env_production"
end
end
after "deploy:symlink", "myproject:symlink"
The first block sets a few settings for Capistrano, quite self-explanatory, the second chunk configures how deployments are made and what files to exclude. The server command specifies which server we’ll be deploying to and the myproject part creates the symlink for the shared WordPress uploads folder as well as creates an env_production file which will alter the execution of our wp-config.php file.
If there’s some part of the current deployment configuration file that you didn’t understand, you should revisit the previous tutorial where each section is explained in detail. From now on I’ll assume that you’ve got things set up and working, meaning you can use cap deploy to deploy your WordPress application to your production server.
Staging Deploys
As defined by Wikipedia:
Staging site, in website design, is a website used to assemble, test and review its newer versions before it is moved into production.
Often referred to as the testing server or a playground server. The server itself has to be configured as close as possible to the production server so that the web application is tested in the same environment. It’s not a very good idea to test the application on the same server, since if things go wrong (and they will, trust me), you might affect your production website.
Staging in Capistrano is done using the capistrano-ext gem libraries which you should have installed in the first part of this tutorial. The rest is done by simply setting the available stages and the default stage and including the multistage module using require.
What we’ll need to do is adapt the code snippet shown above to different environments — playground (testing) and production. Meaning the env_production file will have to be created on the production stage only, while the playground would need an env_playground file to work correctly. The server will change as well and so will the deploy_to path. So let’s get started.
At the beginning of your deploy.rb file, enable staging, like this:
set :stages, %w(production playground)
set :default_stage, "playground"
require 'capistrano/ext/multistage'
This defines the two stages and sets playground as the default, meaning all cap task commands will be issued to the playground server by default, and to the production server only when we explicitly ask it to with cap production task.
With this setup, multistage will look for and try to include deploy/playground.rb and deploy/production.rb when deploying to playground and production respectively. The deploy directory should be located right next to your deploy.rb file, so create the following structure:
project/Capfileis your Capistrano “make” fileproject/config/deploy.rbis your deployment fileproject/config/deploy/production.rbis your production configuration file, andproject/config/deploy/playground.rbis your playground config file
As I said earlier we’ll have to remove (or comment out) the deploy_to, server and the env_production commands from the main deployment file (deploy.rb) and move them with slight changes to production.rb and playground.rb files. Let’s start with the playground.rb file:
set :deploy_to, "/home/path/to/playground.example.org/"
server "playground.example.org", :app
namespace :myproject_playground do
task :symlink, :roles => :app do
run "touch #{release_path}/env_playground"
end
end
after "deploy:symlink", "myproject_playground:symlink"
So we’ve set the deploy_to and server to the path and server where the WordPress application should be deployed to. We then created a new task under the myproject_playground namespace that is run after deploy:symlink and creates that empty env_playground file used by wp-config.php.
You might have already guessed the contents of the production deployment file (deploy/production.rb):
set :deploy_to, "/home/path/to/example.org/"
server "example.org", :app
namespace :myproject_production do
task :symlink, :roles => :app do
run "touch #{release_path}/env_production"
end
end
after "deploy:symlink", "myproject_production:symlink"
Right, just like the playground file with a little modifications. At this point you’ve got everything set up. A main deployment file which defines our stages and other options, creates the symlink to the shared WordPress uploads directory (note that we didn’t remove that part, only the touch command). We’ve also got two files that specify the routines of deploying to the playground and production servers. Let’s now test this out:
cap deploy
cap playground deploy # same as the command above
cap production deploy # deploys to production
cap deploy:rollback # rolls back the playground release
cap production deploy:rollback # rolls back the production release
That’s all there is to it. If the commands above have worked for you then you’ve done everything right. So now you’re free to cap deploy any time you wish without worrying that you might break things on your production server and when everything’s thoroughly tested you can carry out the deployment on production.
If you need more different scenarios between your playground and production servers you’ll add them to playground.rb and production.rb respectively which will be included by Capistrano based on which deployment has been fired.
Now that you’re comfortable with staging, let’s move over to our next topic.
Deploying with Git Tags
A tag in git is basically a reference to a certain commit in the repository. I like to think of tags as milestones (or markers), making it easier to track different versions of your product or project.
Tagging is especially useful in larger products, when more than one developer is committing and pushing to the repository at any given time, and when there’s a chance that somebody would push more changes right when you’re about to deploy to your production server, resulting in untested code ending up on your live application.
You can use tags to label certain commits in your Git repository and then get Capistrano to deploy that specific tag to your playground and production servers, ignoring all changes pushed into the repository which were made after that tag was created. If you’re not using tags for your Git project yet, start by committing your final changeset, pushing it to your repository and finally tagging it with 1.0 like this:
git tag 1.0
git push --tags
Now let’s get Capistrano to read your available tags and ask you to pick one when you’re about to deploy your WordPress application. We’ll use tags in all the stages so this snippet should go to your main deploy.rb file:
set :branch do
default_tag = `git tag`.split("\n").last
tag = Capistrano::CLI.ui.ask "Tag to deploy: [#{default_tag}] "
tag = default_tag if tag.empty?
tag
end
Note that :branch is just another variable for Capistrano that you can explicitly set to “master” or anything else, just like you set the :deploy_to variable and the others. This snippet though, gets Capistrano to ask which tag to deploy with the latest tag set as the default one. Thanks to Nathan Hoad for this snippet.
There you go, now every time you ask Capistrano to deploy your application, it will ask you for a tag having the latest tag set as the default one. Sometimes you’d want to test code on your playground server without having to create a tag each time so note that you can just type in master and Capistrano will deploy whatever is in the master branch, i.e. your latest commit.
Hopefully that will make your deploys more secure and easier to manage with smaller risks for failing. Let’s now move over to some database security.
Hiding Your Production Database Credentials
If you’re the only person working on the project you wouldn’t really care if you had your production database credentials (username and password) in your WordPress configuration file, assuming your Git repository is secure of course. But when it comes to dealing with multiple developers on one project, you have to get your production database secured.
Restricting access from anywhere but localhost is a good start, but we really want to get that production and playground usernames and passwords out of sight and out of our Git repository, leaving local credentials only. If you recall from the previous tutorial we did some magic to our wp-config.php file that works with staging and looks 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
}
There are several ways to do this, easiest of which is of course to separate the wp-config.php file into wp-config-production.php, wp-config-playground.php and wp-config-local.php, that way you can get rid of the empty env_local, env_playground and env_production files and have wp-config.php run the checks based on the configuration files existence and then require them.
Here’s the edited wp-config.php file to show you what I mean:
if ( file_exists( dirname( __FILE__ ) . '/wp-config-local.php' ) ) {
// Local Environment
define('WP_ENV', 'local');
define('WP_DEBUG', true);
require( 'wp-config-local.php' );
} elseif ( file_exists( dirname( __FILE__ ) . '/wp-config-playground.php' ) ) {
// Playground Environment
define('WP_ENV', 'playground');
define('WP_DEBUG', true);
require( 'wp-config-playground.php' );
} elseif ( file_exists( dirname( __FILE__ ) . '/wp-config-production.php' ) ) {
// Production Environment
define('WP_ENV', 'production');
define('WP_DEBUG', false);
require( 'wp-config-production.php' );
}
The database credentials themselves go into their respective configuration files, while other configuration constants like WP_DEBUG, WP_ENV and WP_CACHE stay in your main wp-config.php file which is under source control. Additionally you should ask .gitignore to ignore your extra WordPress configuration files so that they don’t end up in the Git repository.
At this point you can create a wp-config-local.php file with your local database credentials right next to wp-config.php on your local environment, so the application should now work locally. Next, using SSH sign in to your playground server and browse to the shared folder which contains stuff that is shared between Capistrano releases. If you followed all the previous parts and the previous tutorial you should see the uploads folder there.
Create a new file called wp-config-playground.php and fill it in with your playground database credentials. Next, edit your Capistrano playground.rb file and remove the touch command that adds the env_playground empty file since it is now redundant. Instead of that we’ll create a symlink to our playground configuration file, like this:
namespace :myproject_playground do
task :symlink, :roles => :app do
run "ln -nfs #{shared_path}/wp-config-playground.php #{release_path}/application/wp-config-playground.php"
end
end
after "deploy:symlink", "myproject_playground:symlink"
Test it out on your playground server by deploying and if it works as expected, move over to your production server and carry out the same thing, replacing playground with production in the task namespace, the configuration files and the deploy:symlink hook.
With this approach Capistrano will copy the wp-config-playground.php and wp-config-production.php files when deploying WordPress to your playground and production servers respectively. This means that both configuration files will not be present in your source control and your team mates will not have access to them.
Note that not so sensitive constants should remain in your main WordPress configuration file, since developers might need to add, remove or modify some of them at some point and you don’t want them bugging you to do it on the remote servers.
Conclusion
This brings us to an end of the second part of Deploying WordPress Like a Pro series, where we talked about Capistrano’s multi-stage extension for better code testing before going live, deploying WordPress based on Git tags for more organized and secure deploys and database credentials hiding for better security in larger teams and projects.
Thank you for reading and hope you’ve learned something new today. We really appreciate your feedback, so feel free to ask us any WordPress and Capistrano related questions or just share your thoughts using the comments section below. Don’t forget to subscribe to our feed too!




I’m using assembla.com to host my repository. you get a free private space whereas github is public for the free account
Sweet, looks like you’re limited to one repo only. Whenever I hit the limit on private Github repos I use our own Git server. It’s not too difficult to set up, but you don’t get the issues, milestones, etc goodies. Thanks for the heads up!
Assembla looks awesome and I know a few people happily using their paid group plan for Project Management + Git/SVN. I’ve been meaning to test out a free account myself, but not yet.
Personally I think however that for just private git repos though one is better off setting up their own remote Git server. Personally I host all a dozen or so private git repos on an old shared BlueHost/HostMonster account and then push/pull from there to local/staging/production. I often actually use that same server as staging. (note, none of what I do uses Capistrano, although I’d like it too soon and this article has help move closer to that).
Jon, I agree, unless you really need the extra features that Github gives you in terms of project management, you’re better off with your own hosted Git repositories. But, running the staging server where all your git repositories are hosted is dangerous ;)
In my case I mostly work alone so my local git repo and remote git repo are almost always in sync, as are my local site and staging site. Staging is essentially an off-site backup, but even if it wasn’t I’d be still be curious what the danger would be?
Well staging is made for testing, isn’t it? So most of the weird things happen on local servers and staging servers. And by weird I mean things that break your website or even worse — break your server. You don’t want to end up with a broken server that’s got all your git repositories and backups :)
In part 1 you’d almost convinced me switch from Jaquith’s wp-config setup (require local-config) to yours (if file_exists but keep config info wp-config), but I think I’ll leave it alone.
One thing not covered here, and it’s more a general “local/staging/production” issue than one specific to Capistrano is dealing with absolute URLs. At WCSF Nacin mentioned using an output buffer to filter/replace URL strings. I’ve got it working with some but not perfect success.
In local-config.php I use:
Which works local, but when in dev-config.php I use:
I have trouble login in with it redirecting to the live site… sorry if this seems like a topic hijack just seems closely related.
Jon, yeah there are many different approaches at wp-config and it doesn’t really matter which one you use as long as it works for you :) As for output buffering don’t forget that it buffers all output from your script, but not headers, so
Location: xyzheaders will not be replaced in your code.Anyhow, when dealing with the different domains I simply run my database dump file through a
sed(search and replace) command to replace my production domain to my testing domain and to my local domain. The only thing that breaks is the serialized data, like widgets in WordPress but that’s no big deal. Another option is setting up your servers to reply to your original domain.com, all of them (local, testing, production) and juggle with your local/etc/hostsfile to pick the right one. There was also a Firefox extension for this I used around a year ago.Cheers, and thanks for your comment!