Continuous Delivery of custom WordPress using Vagrant, Ansible and AWS

Vagrant + Ansible + AWS = <3
Vagrant + Ansible + AWS = <3

The website is based on WordPress, with a custom Crisp theme.

This is the story about how we’ve developed our custom WordPress theme, how we’ve made it easy for any Crisper and external consultants to work on the theme, how we’ve setup version control, continuous delivery, staging and production environments on Amazon Web Services (AWS). And how all of this is setup with absolutely no automated tests whatsoever.

Three years ago, we changed our web platform from imCMS to WordPress. We had hired help to build a custom Crisp theme and were quite happy with the improvement. However, contributing to the development of the web site was quite cumbersome, which lead to that it was mostly me out of all the Crispers to did any major work on the theme. I had to setup a full LAMP stack on my machine, install WordPress and configure Apache and mySQL to be able to develop the web site. Not rocket science, but too high of a threshold if you just want to make a few small changes.

Deploying to production was as simple as uploading your changed theme files to production using a sFTP client. Not exactly fool proof. We were hosting at a small swedish web hosting firm, and had little flexibility and control over machine size and memory settings.

Local development environment

In order to make it easier for others to contribute to the web, I started setting up the development environment inside a virtual machine. We are now using Vagrant to spin up a VirtualBox, and then we provision that box using Ansible. Instead of having to install a full LAMP stack, anyone who wants to contribute to the Crisp can now simply get their development environment up by running `vagrant up`. The ansible script will install and configure all the software needed to run WordPress, as well as linking the local copy of our WordPress theme repository to the appropriate location in WordPress. The developer can then simply fire up the code editor of choice, edit the theme files locally, and hit reload in the browser to see the changes. Quick and easy.

Developing the Ansible scripts

Using Ansible make it easy to provision the virtual machine with all the software needed to run WordPress. This includes the main components; Apache, MySQL and PHP, but also Postfix and tools like pip and unzip. Ansible code is usually shared as “roles”. Reusable Ansible roles can be found in Ansible Galaxy ( I’ve found Jeff Geerling to be a great source of reusable Ansible roles. We are using his MySQL role and the Postfix role. Thanks Jeff!

There are some differences between a local development environment and a production environment when it comes to provisioning. Here are a couple I have noted:

  1. On a development environment, you are happy to get a fairly recent copy of the production database. In production, you don’t want to restore any database and just keep what is there.
  2. In production, you want to use real certificates for https. On a development environment, you can live with a self-signed certificate.

In Ansible, there are many different ways to structure your code to support the need to have differences in different environments. (tags, environment files etc.)

We’ve chosen to keep our Ansible script together with the WordPress theme source code. This has kept the development loop very short. There is no “deploy step” to get your changed code onto the Vagrant machine. Instead the source code directory is linked directly into the Vagrant machine. Using a benefit of a script language!

Migration to AWS

What was the rationale behind migrating to AWS? Well, we were not very happy with the stability of our current hosting provider for the Crisp web. Also, with AWS we would have a lot more control over the exact configuration of our machine and can easily change configuration of hardware, network, OS, Apache, PHP, MySQL etc. With more power comes more responsibility… Also, learning to work with AWS was a key motivating factor as well.

Source control and continuous delivery

We use Git for version control and GitHub as our central repository. Whenever there is a push to the master branch of our WordPress web repository, GitHub will notify our Jenkins instance which will run exactly zero tests, and then deploy to production, using the same provisioning scripts as are used in local development. This reduces the likelihood of problems caused by differences in development and production environments. The neat thing is that there is now no additional manual step to deploy to production, and the deployment includes both provisioning (installation and configuration) of all the dependencies of our WordPress installation. Configuration is treated as code.

Overview of workflow

Workflow: From development to production
Workflow: From development to production


No tests?

Yes, well, it’s not stated out of pride. I can just conclude that there havn’t been a lot of problems that would have been caught by automated tests.

What’s next?

There are some areas we would like to work on next.

  • Automated recovery from catastrophic failure
    • What happens if the AWS instance is destroyed?
  • Redundancy
    • What happens if the Amazon zone goes down?
      • How should we handle database state across a clustered environment? Several options exist.
  • Support for HTTP/2
  • Migration of to AWS


2 responses on “Continuous Delivery of custom WordPress using Vagrant, Ansible and AWS

  1. Hey crisp, thanks for your post, i was just looking for something related to CI on wordpress and found it.

    Just one question, how do you manage database migrations, specifically with plugin data like custom fields and that kind of stuff?

    In any new version of any WP site we usually have code changes and plugin record changes, but we can’t just take a mysqldump and restore it on prod because in prod there’s updated content (pages and other content types).

    Do you have a specific tool for doing data-diffs or do you do some sort of code migrations?

    1. Hi David,
      Sadly, I havn’t solved that problem yet. We do have custom fields and such, but have started to use the build-in WordPress taxonomies instead. Currently, we keep track of what we need and do the changes manually on production before we release a new version. It’s not great, but we can’t fix everything at once, can we? 🙂 (I heard working in iterations and incrementally building something is a Good Thing^tm.)

      Going forward, I am looking into scripting WordPress using the WP CLI, see:
      That way, we can perhaps start doing taxonomy changes using scripts.

      If you figure out another good way, please let me know!

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.