Jeremy Felt

Deployment Workflows, Part 2:

This post is the second in a series of deployment workflows I use to get code into production.

The site you’re reading this on is often a neglected playground of sorts. I’ll run into an interesting method of provisioning the server or maintaining code, apply it halfway and then get distracted with something else.

That said, somewhere around 16 months ago, I tried out Fabric to manage deployment actions for individual sites and decided to stick with it.

A fair warning is in order—I found an immediate, quick way to use Fabric to accomplish a handful of tasks and then let it be. It’s likely much more powerful than a wrapper for rsync, but that’s basically how I’m using it.

Ok. Backing up a bit, I think this workflow makes the most sense when you look at how the code is arranged.

  • www/ is where WordPress and its config files live.
  • www/wordpress is a submodule pointed at so that I can run trunk or a specific branch.
  • content/ is my wp-content directory. 1
  • tweets/ is a submodule pointed at, where I maintain a version controlled copy of my Twitter archive.

The arrangement goes along with the types of code involved:

  • (wp-config, mu-plugins) Code custom or very specific to This should exist in the repository.
  • (plugins, themes) Code that cannot be sanely managed with submodules AND that I want to manage through the WordPress admin. This should exist in the repository.
  • (WordPress, tweets) Code part of sanely available repositories that can be used as submodules.

Anything in a submodule is really only necessary in the working directory we’re deploying from, so the pain points I normally have with submodules go away. I think (assume?) that’s because this is the purpose of submodules. 😉

Ok, all the code is in its right place at this point.

With the file in my directory, I have access to several commands at the command line. Here are the ones I actually use:

  • fab pull_plugins – Pull any plugins from production into the local plugins directory. This allows me to use WordPress to manage my plugins in production while keeping them in some sort of version control.
  • fab pull_themes – Pull any themes from production into the local themes directory. Again, I can use WordPress to manage these in production.
  • fab pull_uploads – Pull my uploads directory from production to maintain a backup of all uploaded content.
  • fab sync_themes – When I update WordPress via git, this command is a nice shortcut to sync over any changes to the default theme(s).
  • fab push_www – Push any local changes in the www directory to production. This is primarily used for any changes to WordPress.
  • fab push_tweets – Push any local changes in the tweets directory to production. This effectively updates
  • fab push_content – Push any plugin and theme updates that I may have done locally to production. I don’t have to separate these actions because I already have them in version control, so I’m not as worried about having a lot happen at once.

An obvious thing I’m missing is a method for backing up the database and syncing it locally. This is really only a few more lines in the fabfile.

I also need to reimplement a previous method I had for copying the site’s Nginx configuration, though that may also be part of another half completed provisioning attempt.

This workflow has been painless to me as an individual maintaining a production copy of code that is version controlled and locally accessible. It allows me to test new plugins and themes before adding them to version control. It also allows me to quickly test specific revisions of WordPress core in production.

I’m not sure how well this would expand for a team of developers deploying code. There are likely some easy ways to tighten up loose ends, mostly around internal communication and defining a release workflow. I am also certain that Fabric is more powerful than how I am using it. I look forward to digging in deeper at some point.

As with other posts in the series, I would love feedback! Please leave a comment or reach out with suggestions or questions.


1: Renaming wp-content/ to content/… Don’t ever do this, ugh. Keeping it a directory up from WordPress is great, but keep it named wp-content. It is possible some of my problems also came from changing my content domain to, but I blame a lot of it on content/. My current favorite is www/wordpress/, www/wp-content/, and www/wp-config.php.

Responses and reactions


Doug Stewart replied on 


At first blush, I'd say that the main difference between a Fabric-style deployment tool and Ansible is that Fabric is focused on deploying software and project-based sorts of affairs, whereas Ansible is really about host configuration management. You technically *could* use Ansible to manage deployments of a software project, but there's really too much systems overhead to the tool -- it's overkill and a ill fit, IMHO.

    Jason Resnick replied on 

    Doug: I would tend to agree with you on all points. The fact that Ansible seems to be overkill is a main reason why I've moved away from it. I may look into Fabric now though since I had been using Capistrano mostly since I came from a Rails background. But Cap has it's own issues and can overly complicate things at times.

    Jeremy: Shiny object syndrome huh? I have a bad case of that as well.

    Jeremy Felt replied on 

    Thanks, Jason!

    I have heard of Ansible and remember originally being head over heels for it. I even started another badly named repo to build a VVV clone at some point - WAVE. There was a period I was trying to figure out the best option for provisioning our servers at WSU. It was around then that I fell in love with Salt and kind of forgot about everything else.

    I think at some level I thought of Ansible as a provisioner and Fabric as a task runner—though I'm sure either can handle either in the end. I do remember really enjoying that things were in YAML format.

    From what I remember, Doug Stewart uses Ansible for some stuff, so I'm going to ping him to chime in if he has thoughts. :)

Leave a Reply

Your email address will not be published. Required fields are marked *

The only requirement for your mention to be recognized is a link to this post in your post's content. You can update or delete your post and then re-submit the URL in the form to update or remove your response from this page.

Learn more about Webmentions.