z1

My name is Zhiwan (z-one), a rabbit with a color obsession. A Netherland Dwarf rabbit to be precise. When not frolicking with other like-minded rabbits, I has been known to participate in what one might call artistic endeavors. I’ve been labled a color-field AbEx at heart. But for reals, I have an unhealthy obsession with found objects, paint, and sometimes relational aesthetics. If you would like to hire me for some sort of commercial or artistic labor, but need some sort of official document, I got you covered below:

Setting up Mark Jaquith’s wp-stack and wp-skeleton for Capristrano deployment


After being a cowboy coder for most of my coding career, I finally came across Mark Jaquith’s talk, Scaling, Servers, and Deploys — oh my! and decided to change my ways. I used Evan Solomon’s wonderful post outlining the nginx/apc/batcache configuration I needed. Seeing a lack of tutorials on Mark Jaquith’s setup, I had to figure things on my own. I have documented the process below. For this tutorial, I will be detailing the configurations for Mark Jaquith’s wordpress deployment setup:

You should have basic knowledge of Git, can SSH into your website, and have created subdomains for staging purposes. I also assume you are using the same setup as described by Evan Solomon:

  • Linode 512 MB
  • Debian 6 32-bit
  • PHP-FPM
  • APC
  • nginx
  • Batcache

For the purposes of this tutorial, I will be using the following as my example website:

www.site.dev
yellow code means snippets you have to change based on your settings

Git Init

For my local development, I use Mamp (in the future I would like to use a Vagrant/Puppet setup). Tutsplus has a good tutorial on setting up a decent local development environment with Dropbox. Quickly look through it if you want, but make sure you add this to the bottom of your etc/hosts local file:

# local development
127.0.0.1 www.site.dev

Now create the folder www.site.dev in vhost. cd to www.site.dev directory on terminal and type:

$ git init
$ git remote add origin https://github.com/markjaquith/WordPress-Skeleton.git
$ git pull origin master
$ git submodule update --init

Git will pull the WordPress-Skeleton theme and the latest WordPress into the www.site.dev folder. WordPress-Skeleton is kind of a boilerplate that caters to local and remote development. Remember that all your themes and plugins should be now installed in the content folder, thus keeping the wp WordPress install folder clean and untouched. I have noticed a few plugins failing under this file structure, so test things out at this point before you get in too deep.

Keeping in line with separating our local and remote development credentials, you’ll notice there is a local-config.php and a wp-config.php. Change the local-config.php to your local setup:

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

The WordPress-skeleton will automatically change your credentials thanks to this nifty code in the wp-config.php:

if ( file_exists( dirname( __FILE__ ) . '/local-config.php' ) ) {
define( 'WP_LOCAL_DEV', true );
include( dirname( __FILE__ ) . '/local-config.php' );
} else {
define( 'WP_LOCAL_DEV', false );
define( 'DB_NAME', '%%DB_NAME%%' );
define( 'DB_USER', '%%DB_USER%%' );
define( 'DB_PASSWORD', '%%DB_PASSWORD%%' );
define( 'DB_HOST', '%%DB_HOST%%' ); // Probably 'localhost'
}

You can add the your Salts key codes and change the table prefix for security, but you don’t actually need to change anything else in the wp-config.php file as WP-Stacks will fill in the rest! How cool is that?

Next, we need to create the uploads folder directory. So back in the terminal, add:

$ mkdir shared && cd shared
$ mkdir content && cd content
$ mkdir uploads && cd uploads

This is where WordPress will add the media files. wp-config.php is set to look for the uploads folder under this particular file structure shared > content > uploads, so change this structure at your own risk. That’s it for the WordPress configurations.

If you have correctly set up your local database, you can head over to www.site.dev/wp/wp-admin/install.php on your browser and install WordPress. Because WordPress-Skeleton puts the main WordPress installation in the wp folder, your site URL will read www.site.dev/wp. To get rid of the wp, log into the admin panel of WordPress and go to Settings > General. Where it says WordPress Address (URL), it should say www.site.dev/wp. Leave that. Below, the Site Address (URL), will also read www.site.dev/wp. Delete the wp and make sure it says:

www.site.dev

Cool. Let’s move on to WP-Stacks.

WP-Stacks: config

Grab WP-Stacks and put the files into the root of the of your file structure (www.site.dev). Go into the config folder and open the config.rb file. You want to change the following:

set :application, "WP Stack Site"
set :repository,  "set your git repository location here"

The application name is can be anything you want. Due to the way I pulled wp-skeleton, you will have to reset the repo origin in the terminal:

$ git remote set-url origin git://your.git.repository
$ git push -u origin --all

Make sure your git repository is working. Capistrano cannot work without it. Then back in config.rb, change the following lines:

# This should be the same as :deploy_to in production.rb
set :production_deploy_to, '/srv/www/example.com'

# The domain name used for your staging environment
set :staging_domain, 'staging.example.com'

/srv/www/example.com should point to where your production is located on your server. The way that Capistrano deploys, you should change it to look something like this:

/srv/www/example.com/production

staging.example.com will be the URL to your staging server, ie staging.site.dev. Finally, add the correct credentials to your staging and production server database. These values will be inserted into wp-config.php, so make sure they are correct.

set :wpdb do
	{
		:production => {
			:host     => 'PRODUCTION DB HOST',
			:user     => 'PRODUCTION DB USER',
			:password => 'PRODUCTION DB PASS',
			:name     => 'PRODUCTION DB NAME',
		},
		:staging => {
			:host     => 'STAGING DB HOST',
			:user     => 'STAGING DB USER',
			:password => 'STAGING DB PASS',
			:name     => 'STAGING DB NAME',
		}
	}
end

Now let’s open up staging.rb. Where it says:

# Where should the site deploy to?
set :deploy_to, "/srv/www/example.com"

change /srv/www/example.com to where your staging folder is on your server. It should be something like this:

 /srv/www/example.com/stage

I then added this to the bottom:

server "www.staging.site.com", :web, :memcached

You may have to tweak your settings if you have multiple web servers.

WP-Stacks: lib

In the lib folder, open up deploy.rb. Change deploy to the user that will SSH into your server.

set :user, "deploy"

Next, open up tasks.rb. Change the www-data:www-data to the user that can SSH and has permissions to edit files on your server.

namespace :shared do
	task :make_shared_dir do
		run "if [ ! -d #{shared_path}/files ]; then mkdir #{shared_path}/files; fi"
	end
	task :make_symlinks do
		run "if [ ! -h #{release_path}/shared ]; then ln -s #{shared_path}/files/ #{release_path}/shared; fi"
		run "for p in `find -L #{release_path} -type l`; do t=`readlink $p | grep -o 'shared/.*$'`; sudo mkdir -p #{release_path}/$t; sudo chown www-data:www-data #{release_path}/$t; done"

	end
end

Aaaannnnddd…we are almost done.

Capistrano

We just set up everything that needs to be done for Capistrano to do multi-staging deployments of our local WordPress install. cd to your local www.site.dev directory and type:

$ cap staging deploy:setup

FTP or SSH into your server and see what it did. Capistrano should have created a release folder and shared folder in your remote staging folder. At this point, I had to manually create the shared file structure. Log into your remote server and cd to the shared folder. Then enter this in the terminal:

$ mkdir files && cd files
$ mkdir content && cd content
$ mkdir uploads && cd uploads

You should have a file structure like shared > files > content > uploads. Keep in mind that your local uploads will not sync with Capistrano’s staging and production deploy, so if you created a bunch of posts on your local, in addition to dumping your local database, you’ll have to upload all your media in the remote shared folders. Now you can head back to your terminal on your local computer and enter:

$ git add .
$ git commit -m "commit comments"
$ git push
$ cap staging deploy

Hopefully, no errors appeared on terminal. If there are, go back and recheck everything. Capistrano should have now added a new folder under releases and created a current folder that symlinks to the latest release. Every time you do a cap deploy, a new release is added while keeping the old one. If everything looks good, go ahead and

$ cap deploy:setup

Edit production.rb the same way as staging.rb and create the shared > files > content > uploads folder structure on the production area. Once that is done, go ahead and enter:

$ cap deploy

Now you have a robust WordPress framework coupled with a smooth multi-stage deployment framework! Because current is simply symlinked to the latest release, you can use Capistrano to point to previous version instantly should something bad happen:

$ cap deploy:rollback

Lastly, you can clean up all but the latest five releases. You edit the number of releases saved in deploy.rb:

set :keep_releases, 5

And to cleanup, enter:

$ cap deploy:cleanup

Now, go off and do some safe smart coding!


21 thoughts on "Setting up Mark Jaquith’s wp-stack and wp-skeleton for Capristrano deployment"

  1. This looks like a great tutorial. I’ll try to follow it. So far I’ve got Skeleton installed and WordPress as a submodule in git. Can the git repository that Capistrano uses be the same one as the one being used for local development, or does it have to be an separate external one?

    • It should be the same one. I’m not sure what would happen if you tried to have a different repo. I use the same one for both local development and Capistrano.

  2. This was pretty helpful. Thanks. I am curious though, do you ignore WP-Stack or do you add those files to your repo as well. I am still wrapping my head around this.

    • I leave WP-Stack to my repo, but it’s really up to you. I guess for absolute security you can ignore all of WP-Stack. Out of the box, WP-Stack ignores the key important files: config.rb, production.rb, and staging.rb.

  3. Thanks for the good writeup. It in truth used to be a
    entertainment account it. Glance complicated to far brought agreeable
    from you! However, how could we be in contact?

  4. Have you tried to setup NFS shared folders to sync media (files in /uploads aka images) from you local environment to production and staging? Combine that with puppet & vagrant and you’d have the ultimate dev. environment.

    • No, but I wish I could. I was in the middle of trying to figure out how to integrate puppet and vagrant when I started grad school and haven’t been able to go all the way through. If you end up writing a tutorial about this process in a WordPress environment, I’d love to check it out. Cheers!

  5. How do you maintain WordPress itself? I’m trying to set it up as a submodule, and it seems to be working OK locally, but when I cap deploy, my remote server won’t update WordPress. Have you seen anything like this in your setup?

    • I tend to maintain WordPress by updating it locally and then pushing to my server. You can also update WordPress by logging in to the backend locally and update that way as well. I hope that answered your question.

  6. Hay great tutorial, it was just what I was looking for and has saved me much time. Hopefully my live edits will be a thing of the past :)

    After initial configuration hiccups (hosting environment related) Ive got everything working quite well.

    Although I’ve two questions that you may be able to help me with if you have time

    1. I have a highly customize theme that I manage in its own git repository. Currently I develop in my local deployment, when Im happy I tidy up the code commit it to my main site repository and push to staging and live. Any changes that I have made then get merged into the theme repository so I can can keep track of the changes to just the theme.
    Is there any way to add the theme as a sub-module like the wordpress files are. It would simplify the work flow?

    2. I can see there is functionality that appears to dump the production database and replicate this to staging? I can not seem to make it work correctly. Again I have a feeling that is related to the hosting environment. When the msqldump command runs using the production credentials it does not seem to have access/permission.
    Have you got this feature working? I would like to have this feature working so If you use it I can do some additional research to try and resolve my issue.

    Again thanks for the great tutorial.

  7. Hey, some great further insight to WP-Stack but one thing I noticed.

    You start off doing all this on your local config, you put in some destination folders on your server, but you never enter a server IP address or anything. cap deploy:setup is going to do anything because you haven’t told it where your remote server/s are…

    Its this point I’m wondering if I should run deployment from my staging server or my remote server – as getting the users correct across all servers could be tricky – id have to create a “deploy” user on every server and make sure they owned all the directories to write to from what I can tell, this bit is very unclear in the original documentation. Im doing local dev on OSX, so i’d need to create the “deploy” user there, but there is no deploy user then on my servers so i’d need another one – and I use AWS so id need to figure out a way to SSH in without the AWS key…all quite tricky.

  8. Thanks for this write-up. Automating WordPress deployments is a goal of mine this year, and this article has helped me a great deal.

    I am still having problems getting Capistrano to work. I followed your instructions on how to modify WP-Stack files, but I am getting a Ruby error. I don’t know if I missed something, or if I have a conflict with the Ruby I have installed.

    Even doing “… –dry-run, I get:
    cap aborted!
    NoMethodError: undefined method `instance’ for Capistrano::Configuration:Class
    (stack trace)
    cap aborted!
    NoMethodError: undefined method `deploying?’ for #
    (another stack trace)

    To even get it to run, I tried installing these gems, based on an article by Konstantin Kovshenin over on theme.fm:
    sudo gem install capistrano
    sudo gem install railsless-deploy
    sudo gem install capistrano-ext

    I know very little about Ruby, Rails, or deploying with Capistrano in its original environment, so any help or advice you have, I would greatly appreciate.

  9. Simply wish to say your article is as astonishing.
    The clearness in your post is just nice and i could
    assume you are an expert on this subject.
    Fine with your permission let me to grab your feed to keep updated with
    forthcoming post. Thanks a million and please continue the
    enjoyable work.

  10. Hey just wanted to give you a quick heads up.
    The text in your content seem to be running off the screen in Safari.
    I’m not sure if this is a formatting issue or something to do with browser
    compatibility but I thought I’d post to let you know.

    The design and style look great though! Hope you get the issue solved soon. Cheers

Leave a reply


*