Deploying WordPress with Capistrano screencast

I figured it would be useful to have a thread dedicated to this screencast but more important just deploying with Capistrano in general (especially since there was no accompanying blog post).

Screencast here: Deploying WordPress with Capistrano Screencast | Roots | Roots

I went through a lot of files in the screencast and now they are available in a Gist: Files from · GitHub


Thanks for that screencast – I’ve been looking to use Capistrano for awhile now and this is a good starting point.

I am a little confused about putting npm and grunt on the staging/production server since the JS would probably be compiled at that point? I guess there is more to Grunt than just that but I have it being ignored for my .git repo and it seems to be more of a “development only” tool for me. What are some good reasons for putting it on your staging or production environment?

I found an older piece of code last time I was trying Capistrano with Wordpress attempting to migrate the database for WordPress deployment via Capistrano. I was never able to get it to work. ( Do you see anything broken about this code? I’m going to take another look after I’ve wrapped my head around Capistrano a bit more and go through the sceencast again. Is this something you’d recommend doing for a deployment or is this better left to a manual workflow? I can see in certain cases how I wouldn’t want to upload the database to a staging server and most likely never to a production environment but it may be useful sometimes, like for the initial deployment.

This was another interesting article with some helpful tips when I was searching about using Capistrano before this screencast. It’s from 2011 so I don’t know how much things have changed since then for this workflow. (

Hi Scott,

Just finished watching the screencast. There’s a lot to go at here but it all makes sense.

One thing that you didn’t touch on is MySQL: I’m wondering about best practice for moving databases from dev to stage to production and then back to dev again?

I want to manage Wordpress entirely using composer, that is, I don’t want anyone using the standard Wordpress mechanisms for installing and updating plugins and themes. I also want to test Wordpress core upgrades on the staging server before deploying to production.

I’m wondering how I can handle this given that plugin and core upgrades can modify the database.
Also, is it posible to associate a specfic capistrano release with a specific named MySQL database so i can rollback the DB too?

I’m also wondering if it would make sense to add another stage for development, and then define a task that dumps out a copy of the production database, runs a sed command to find and replace the hostname and then updates the MySQL database on my development VM.

I could also use a .maintenance file to temporarily disable the production site while I’m working and prevent anybody from modifying anything.

Obviously I will need to add tasks for the other stages to handle the databases, but that’s fine.

How do you guys handle MySQL for Do you store dump files in git?

Also, not sure if it’s just my copy, but the screencast comes to an abrupt end mid sentence!

Thanks for everything!

Sorry, I can see how that would be confusing. Basically we use Grunt slightly differently on our site than the Roots theme by default does. Roots theme would need the JS compiled already so you’re correct that you wouldn’t need to run Grunt during the deploy. I mostly wanted to show how to use Capistrano’s hook and deploy workflow so Composer and Grunt were good examples.

The way Roots theme does it right now isn’t completely ideal since you need to modify your scripts.php file and commit it. We get around that on by not using WP’s enqueue functionality. Obviously we didn’t want to make that the default option.

There’s a lot of code in that example but I don’t see anything immediately wrong with it. I’d recommend writing/using a Capistrano task for DB migration/syncing but probably not as part of the default deploy flow. It could be a manual task you run whenever you want it. You have to be really careful about overwriting databases if you’re doing it everytime.

Quick glance at that last article and the general concepts apply but all the code is quite different now.

First, sorry about that abrupt end. I actually wasn’t aware of that. There’s also a small audio glitch I found out about as well :(. Unfortunately I overwrote my main project file for the screencast and can’t fix those issues. I almost thought I lost everything at one point but realized I had rendered out a full version thankfully.

Maintenance: wanted to quickly mention there’s an official plugin for that:

DB syncing: This is a giant topic that there’s no correct answer to. It seems to be the one thing everyone asks about most and unfortunately it’s such a big topic that I couldn’t get to it in the screencast.

The release specific named db is an interesting idea… Off the top of my head you could hook into the deploy flow. Maybe after 'deploy:updated' and copy the database to a new one with the release timestamp. Basically, you could duplicate how Capistrano works with its releases directory but for databases. It would definitely take some work but it could be very flexible. You could easily rollback to any one. At a minimum maybe you’d just have a backup and current db.

Your other idea about a development stage and replacing the hostname sounds fine as well. This is why it’s a difficult topic since there’s tons of solutions.

For we actually use so all our content is actually static content files. We do however keep some sql files in Git because we need to sync users which isn’t handled by grunt-wordpress. It’s not ideal but it works. Since we don’t often need to sync the database (thanks to using static content files), we just do it manually when we need to.

Thanks Scott. At least now I know that I’m not completely crazy.

I like the idea of keeping a separate database for every release, up to a mximum of say 5, the Capistrano default.

Most of the sites I’m working with these days are small so there’s no issue there.

I can see why you keep your content in static files, makes things much more straightforward.

Unfortunately it’s not an option for me as most of the sites I’m working with are for non technical clients who like using Wordpress as a CMS.

Thanks again :wink:

Wait, I think you might be. I just took your word for it but I checked now and the video ends as it should. Should be 52:24 long. Last thing I talk about is getting help on the forum. So just make sure the entire thing downloaded.

Duh, just checked my firefox download screen and it says the download failed.

I only missed a couple of seconds though so no worries.

Sorry about the false alarm!

I bought the screencast - really helpful, thanks! I had been paying for Beanstalk to manage my deployments, but since I’m not working with a team, I was looking into switching to Capistrano, so your screencast came along at just the right time!

I did have one question: are you supposed to commit your Capistrano-related files to your Git repository or exclude them? I know Composer/Grunt/etc. are supposed to be committed because they’re deployed, but since the Cap files are really only used by the machine doing the deployment, is it necessary?

Yes! 100% they should be committed. That is part of your project and it’s especially important if you’re working with anyone else who’s also deploying. I guess you could make the argument that they shouldn’t be on your production server, but it doesn’t really matter. You could always exclude them.

Thanks - by exclude, you mean exclude from deployment? How would I go about that?

I did mean that. Capistrano uses git archive now so you can actually ignore files by setting up a .gitattributes file.


The more files you ignore the faster your deploy will be as well.

Hi Scott,

This may be beyond the scope of what you can help with but I’m scratching my head over here and thought I’d ask in case:

I’ve got my files all set up, deploy key on Bitbucket for my hosting, connection set via SSH but I’m getting this error every time I run bundle exec cap staging deploy, I x’d out my IP for privacy below. Not sure where to start with this error, any ideas?

testing git:(master) bundle exec cap staging deploy [deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message. INFO [f15313b9] Running /usr/bin/env mkdir -p /tmp/testing/ on DEBUG [f15313b9] Command: /usr/bin/env mkdir -p /tmp/testing/ INFO [f15313b9] Finished in 1.551 seconds with exit status 0 (successful). DEBUG Uploading /tmp/testing/ 0.0% INFO Uploading /tmp/testing/ 100.0% INFO [5bda3160] Running /usr/bin/env chmod +x /tmp/testing/ on DEBUG [5bda3160] Command: /usr/bin/env chmod +x /tmp/testing/ INFO [5bda3160] Finished in 0.405 seconds with exit status 0 (successful). DEBUG [2a8dbb50] Running /usr/bin/env git ls-remote on DEBUG [2a8dbb50] Command: ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/testing/ /usr/bin/env git ls-remote ) DEBUG [2a8dbb50] fatal: cannot exec '/tmp/testing/': Permission denied DEBUG [2a8dbb50] fatal: unable to fork DEBUG [2a8dbb50] Finished in 1.499 seconds with exit status 128 (failed).

Looks like your /tmp partition is set to noexec. See this question for details:

If that’s your own server you should be able to edit /etc/fstab and remove noexec. If it’s not your own you may not be able to change it so follow the workaround in the link above.

Thanks! It’s not my own server; it’s a shared hosting server so I had a feeling this was going to be a bit more difficult. Thanks for the link!

Just one more quick question – when the deploy command is referring to making the tmp directory (or whatever you choose to use instead, I chose “foobar” just to test it out), that’s getting created on the server you’re deploying to, right? I’m just totally confused by the next few errors I get which is saying it’s uploading ~/foobar/testing/ and it’s failing… not sure why it would be uploading that directory or if it’s uploading TO that directory.

➜ testing git:(master) ✗ bundle exec cap staging deploy [deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message. INFO [bbc85d0d] Running /usr/bin/env mkdir -p ~/foobar/testing/ on DEBUG [bbc85d0d] Command: /usr/bin/env mkdir -p ~/foobar/testing/ INFO [bbc85d0d] Finished in 1.794 seconds with exit status 0 (successful). DEBUG Uploading ~/foobar/testing/ 0.0% cap aborted! scp: ~/foobar/testing/ No such file or directory

I checked and that “foobar” directory is getting created on my server too with rwx for my user… so strange.

That’s correct. Every command that Capistrano runs is happening on the (remote) server you’re deploying to including the tmp directory. It’s a little difficult to tell but it seems like whatever solution you did to change the tmp directory might not be entirely correct. One thing to try since you’ve changed some settings is to completely delete the deploy_to folder (~/foorbar and the tmp dir as well) on the remote server which will make Capistrano basically start from scratch.

Note: it looks like you should just be able to do set :tmp_dir, "~/tmp" in deploy.rb to get a tmp dir in your home directory.

Thanks Scott – I tried setting the :tmp_dir like you mention already in deploy.rb and just erased the folder where it deploys to, but still the error is happening. It’s saying it fails when it uploads the file and that the file or directory doesn’t exist. I’ve verified that the directory does exist and that my testing directory gets created in that specified directory. It’s like it’s only having trouble with this file but I’m not even sure what that is.

This fails much earlier than when I don’t use the :tmp_dir directive in the deploy.rb file though.

Thanks for taking the time to help – I’m going to search around on Google more and try to figure out what’s happening.

I got a bit further this time – up to creating the symlink for the media folder. The reason why it wasn’t getting passed the upload for me before is that I needed to actually spell out the path instead of using ~, so:
set :tmp_dir “~/tmp” is now set :tmp_dir, “/home3/jaace/tmp” and that works fine up to the next error.

Hope that helps anyone else using a shared hosting solution like myself.

Good debugging! This is the explanation behind that: