Setting up Mark Jaquith’s wp-stack and wp-skeleton for Capristrano deployment
published
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!
18 thoughts on "Setting up Mark Jaquith’s wp-stack and wp-skeleton for Capristrano deployment"
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.
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.
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?
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!
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.
This website was… how do I say it? Relevant!! Finally I have found something that
helped me. Appreciate it!
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.
I’d like to second Andrew’s question… is there a good way to add a custom theme as a submodule?
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.
Hey in this video http://wordpress.tv/2013/10/14/deploying-wordpress-with-wpstack/
Mark mentions that the shared/content/uploads directory doesn’t exist. Why did you create it? I’m not sure what he’s doing to deploy static content.
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.
[…] use the Mark Jaquith’s WP-Stack CDN plugin to conduct the tests. You’ll have to manually install the plugin, since it’s not available in the WordPress plugin repository. Again, thanks to Tim for […]
[…] and I'm getting this error. I'm not very familiar with terminal was following this tutorial to set this up – http://design.zhiwan.is/setting-up-mark-jaquiths-wp-stacks-and-wp-skeleton-for-capristrano-deploymen…. […]
[…] and I’m getting this error. I’m not very familiar with terminal was following this tutorial to set this up – http://design.zhiwan.is/setting-up-mark-jaquiths-wp-stacks-and-wp-skeleton-for-capristrano-deploymen…. […]