Deploy and Upgrade Wordpress as a docker container with Ansible

Wordpress is the most known and used CMS on the internet. It is said to host more than 50% of all sites. Here I give you the simplest way how to deploy it on your premises with monitoring and backup/restore capability as simple as possible. I am a developer of Lokal - yet another DIY server tool, that uses ansible to manage the services. Wordpress is our most used service so we put a lot of care into the ansible logic to make sure that upgrades are as seamless as possible.

First, I will describe how to install Lokal on your server in the most basic configuration - that is database, monitoring and Wordpress as the front-page. Second, I will go into the technical detail of our ansible script so you can have a confidence in our tool as well.

Install db, monitoring and Wordpress

$ git clone && cd Lokal
$ ansible-playbook -i hosts/local playbook.yml

This is the simplest way how to install basic Lokal (db, monitoring and wordpress) on your local computer 

The wordpress docker container has a startup script that populates two paths with PHP files

  • /var/www/html/ with current wordpress source code
  • /var/www/html/wp-content/ holds customized php files 

The startup script makes changes to those directories only if it considers them empty (they don't contain index.php). We can use this to control when the container should put fresh wordpress code into the app directory and when it should not. We need to have both paths as (bound) volumes. Only then you can easily delete the directory bound to `/var/www/html` when the container is off and /var/www/html/wp-content/ survives.

The problem arises when your wordpress instance is upgraded via the web admin. You need to know the current version to be able to decide whether allow the container to copy in the new code or when to keep the old one. You could say: "I don't care, let's just run the code that is in the contaner", and you would be almost right - just the database is already migrated to the new version of code that might not be backwards compatible with the old version. Hence we have no other option than to go up with the version. Luckily, wordpress stores its current version in /var/www/html/wp-includes/version.php

- name: Get current version (could have been upgraded via web)
    cmd: grep 'wp_version\s*=' wp-includes/version.php
    chdir: "{{project_root}}/wordpress/app" # this is the bind-dir to /var/www/html/
  ignore_errors: true
  register: version_output

- name: Parse out the version
    version_runtime_wordpress: "{{version_output.stdout|regex_search('([\\d\\.]+)')}}"
  when: version_output is defined and version_output.stdout is defined

- name: Upgrade app (if version_wordpress is newer than already running version)
    file: upgrade.yml
  when: version_runtime_wordpress is defined and version_runtime_wordpress is truthy and version_runtime_wordpress is version(version_wordpress, '<')
# Proceed with the installation (ensure directories and DB exists, render docker-compose.yml and up it)
- name: Install wordpress
  include_role: {name: common, tasks_from: install}
    app: wordpress
    mysql_user: "{{mysql_user_wordpress}}"
    mysql_password: "{{mysql_password_wordpress}}"
    mysql_db: "{{mysql_database_wordpress}}"
    - app
    - data
The content of upgrade.yml is really simple - it just removes current container and clears the app/ directory. Therefor it prepares space for the new code to be copied in (while preserving the content of wp-content that is bound to data/ directory).
- name: Remove old container
    cmd: "docker-compose down"
    chdir: "{{project_root}}/wordpress/"

- name: Clear app folder
    path: "{{project_root}}/wordpress/app"
    state: absent

- name: Re-create the app folder
    path: "{{project_root}}/wordpress/app"
    state: directory

- name: Database upgrade
    msg: Please visit https://{{domain}}/wp-admin/upgrade.php to run the DB upgrade