How to Use an Ansible Playbook To Install WordPress on Ubuntu 18.04 and 16.04

Configuration management is the new shell scripting and Ansible is one of the easiest to use configuration management systems out there. With computers, if you have to do something more than once, you should automate it. Let the computer handle repeated mundane tasks so your mind frees up for challenges fit for the human brain.

One such mundane task is installing WordPress. You might need to install WordPress for testing, development and main production website, and instead of repeating the installation three times we will write one Ansible playbook which can be run from a different location to install WordPress on your target system(s).

Step 1: The Server(s) Setup

Ideally, we would want there to be a server set aside for running Ansible playbooks, we will call this our build-server. Here our Ansible playbooks would reside and then we would have target servers on which we would like to install WordPress. Sticking with the entire point of automation, it doesn’t matter if you want to run it on one server or several, but for the sake of simplicity, we will have only one target server which will be a clean Ubuntu 18.04 LTS server.

To allow Ansible to connect to our WordPress server, you would need to have a non-root user with sudo privileges. To allow this, create ssh keys on your build server.

$ ssh-keygen -b 4096

In doing so you will be prompted with several options, you can just pick the default option by hitting the return key, repeatedly. The result would be something like this:

In the user’s home directory, which is typically /home/username. The keys are created in .ssh folder.
To make the connection possible we will copy the contents of file (which is the public key) into the target WordPress server. Specifically, at the end of file /home/username/.ssh/authorized_keys where username is the non-root user with sudo privileges, that we mentioned before.

Remember, copy the public key from build-server onto the authorized_keys file of your target server.

Once, that is done, you can restart the sshd service on your target server by running:

$ service sshd restart

The next task is to test whether the ssh connection works. From build-server run:

$ ssh [email protected]

If you are logged into it, that means it works! Now, CTRL-D out back to your build-server, leaving the target WordPress server alone from now on.

Step 2: Writing the Ansible Playbook

The playbook, in Ansible terminology, consists of a set of hosts on which the automation is to be performed, roles that are to be played out, for example, a server acting as database, another as front-end and so on.

In our case, the one single host is going to be responsible for all of these roles. All the configuration described below can be found in this GitHub repo.

Okay, first we need to create a directory where all of our configurations will be stored:

$ mkdir wordpress-playbook
$ cd wordpress-playbook
$ mkdir roles
$ touch hosts 
$ touch playbook.yml

Here, we created a roles directory and, two empty files hosts and playbook. First thing to do now would be to open up hosts file and add a desired name (need not be the hostname of target server, just a reasonable label) along with the IP address(es) of the server(s) where WordPress will be installed. This is the format for that:


You can let the first line be the same and just modify the second line with an appropriate ip address. You can put multiple IPs under [wordpress] to install on multiple servers.

Once that is done, let’s define the different roles in the roles sub-directory:

$ cd roles
$ ansible-galaxy init server 
$ ansible-galaxy init php 
$ ansible-galaxy init mysql
$ ansible-galaxy init wordpress

This brings in template configurations for individual components from ansible-galaxy which is a repository for many standard ansible configurations. You will notice there are now 4 folders created inside wordpress-playbook/roles directory named MySQL, PHP, server and WordPress. Now we need to configure these.

Step 3: Creating Roles

Ansible instructions are written in .yml files which are quite human readable. We will be writing a few ourselves, for each individual roles of the LAMP stack and WordPress build on top of it.

1. Playbook.yml

First, we would write the following contents into the file wordpress-playbook/playbook.yml

- hosts: all
  gather_facts: False
  - name: install python 2
    raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)

- hosts: wordpress

    - server
    - php
    - mysql
    - wordpress

This installs Python 2.7 onto your all your target servers (which is an Ansible dependency) and then it goes on to assigning 4 roles to the hosts labelled WordPress.

2. Server Role

Using your favourite text editor (for example nano or vim), open the file wordpress-playbook/roles/server/tasks/main.yml and write the following contents into it.

# tasks file for server
- name: Update apt cache
  apt: update_cache=yes cache_valid_time=3600
  become: yes

- name: Install required software
  apt: name={{ item }} state=present
  become: yes
    - apache2
    - mysql-server
    - php7.2-mysql
    - php7.2
    - libapache2-mod-php7.2
    - python-mysqldb

Note: The first two lines would be there by default.

2. PHP

Next, we need to install additional PHP modules for that write the following contents to the file wordpress-playbook/roles/php/tasks/main.yml

# tasks file for php
- name: Install php extensions
  apt: name={{ item }} state=present
  become: yes
    - php7.2-gd 
    - php7.2-ssh2

4. MySQL

MySQL would need some extra information before it starts creating our database. In the file wordpress-playbook/roles/mysql/defaults/main.yml

# defaults file for mysql
wp_mysql_db: wordpress
wp_mysql_user: wordpress
wp_mysql_password: randompassword

Obviously, we urge you to put a really strong password in place of “randompassword” in the last line.
After this, we configure our main MySQL task of creating a MySQL user, database and granting that user access to the newly created database. In the file, wordpress-playbook/roles/mysql/tasks/main.yml write the following:

- name: Create mysql database
  mysql_db: name={{ wp_mysql_db }} state=present
  become: yes

- name: Create mysql user
    name={{ wp_mysql_user }} 
    password={{ wp_mysql_password }} 

  become: yes  

5. WordPress

This is probably the most complex role in this configuration. You will have to get WordPress tar file from the official site, extract it and modify the wp-config.php with appropriate data. To do that, write the following contents into your wordpress-playbook/roles/wordpress/tasks/main.yml

- name: Download WordPress

- name: Extract WordPress
  unarchive: src=/tmp/wordpress.tar.gz dest=/var/www/ copy=no
  become: yes

- name: Update default Apache site
  become: yes
    regexp="(.)+DocumentRoot /var/www/html"
    line="DocumentRoot /var/www/wordpress"
    - restart apache

- name: Copy sample config file
  command: mv /var/www/wordpress/wp-config-sample.php /var/www/wordpress/wp-config.php creates=/var/www/wordpress/wp-config.php
  become: yes

- name: Update WordPress config file
    regexp="{{ item.regexp }}"
    line="{{ item.line }}"
    - {'regexp': "define\\('DB_NAME', '(.)+'\\);", 'line': "define('DB_NAME', '{{wp_mysql_db}}');"}        
    - {'regexp': "define\\('DB_USER', '(.)+'\\);", 'line': "define('DB_USER', '{{wp_mysql_user}}');"}        
    - {'regexp': "define\\('DB_PASSWORD', '(.)+'\\);", 'line': "define('DB_PASSWORD', '{{wp_mysql_password}}');"}
  become: yes

And finally, because we would need to restart Apache to see WordPress work, add the following snippet to your wordpress-playbook/roles/wordpress/handlers/main.yml

# handlers file for wordpress
- name: restart apache
  service: name=apache2 state=restarted
  become: yes

Step 4: Running Ansible
Hopefully, you have executed the above steps correctly, if so then running the following command, from the directory wordpress-playbook, would install WordPress into your target host:

$ ansible-playbook playbook.yml -i hosts -u username -K

Where username is to be replaced by the literal username on the host system who has sudo privileges. If everything goes right, you would see an output like following:

Anytime, you need to install WordPress onto a server, add its IP under the wordpress-playbook/hosts file and then run the above command again. Upon visiting the IP address of your target server, using a web browser, you will be greeted by WordPress:


Hopefully, this introduction was motivating enough that you would try installing WordPress using Ansible and try to extent its capabilities. We urge you to look into how you would encrypt your database password instead of leaving it as plain text. Similarly, you might want to try having salted passwords for securing your installation for production.