Deploy WordPress (et al) with Docker and Compose

All the credit on the WordPress/MySQL/Compose stuff goes to this guy. He’s got a wonderful series that takes you step-by-step through the process of deploying WordPress with Docker. I don’t have time to read all that again and again, so the process is condensed here.

The problem

I’ve got one cloud server and a whole bunch of WordPress installations. I want them to all live side-by-side on a single machine. I’ve addressed a similar problem before. This time I’m going to take a different approach to the database end of things:

[System Topology]

I’m giving each WordPress container its own MySQL container for three reasons:

  1. I want to see how the configuration performs
  2. I want to isolate each WordPress installation’s data
  3. I’ve noticed that WordPress and the database sometimes don’t get along. I don’t want all my sites to depend on one flaky database that may need restarting.

I can’t vouch for the general suitability of this approach (yet).

2015-10-5 UPDATE: I didn’t account for data volumes or data-only containers. Though the following technique is still sound, this doesn’t make it easy to persist data when it comes time to move a WordPress container to another domain. An updated configuration is coming soon.

Assumptions

Docker and Compose are already installed on an Ubuntu 14.04 server.

The containers

All the containers needed for the above configuration come pre-cooked:

Nginx

First, get some SSL certificates

You’ll need one for each of your WordPress installations. These can be self-signed or obtained from a Certificate Authority. To self-sign a certificate, execute the following:

1
2
3
4
5
6
mkdir certs
cd certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout sub.example.com.key -out sub.example.com.crt
cd ..
sudo chown -R root:root certs
sudo chmod -R 600 certs

Note the keyout and out options. The jwilder/nginx-proxy Docker image won’t pick up the certificates unless they are named in accordance with the production site’s URL and subdomain (if any). For example, if you have a certificate for example.com, the keyout and out options must be named example.com.key and example.com.crt respectively.

Obtain a certificate for each WordPress container you wish to deploy (or just get one for the purposes of this tutorial).

Then, run the Nginx docker image

Note the app username. Adjust as appropriate.

1
docker run --restart=always --name nginx-proxy -d -p 80:80 -p 443:443 -v /home/app/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy

MySQL + WordPress + Compose

Create a working directory on the server:

1
2
mkdir example.com
cd example.com

Create docker-compose.yml:

1
vim docker-compose.yml

Copy, paste, and save the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
wordpress:
image: wordpress
links:
- mysql
environment:
- WORDPRESS_DB_PASSWORD=secretp@ssword
- VIRTUAL_HOST=example.com
expose:
- 80
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=secretp@ssword
- MYSQL_DATABASE=wordpress

Execute Compose:

1
docker-compose up

I find that WordPress cannot connect to MySQL the first time you execute docker-compose up. I’m not sure why. Executing the command a second time has resolved the issue every time so far. Once you have verified that the site is accessible at your domain, execute docker-compose with the -d option to put the process in the background:

1
docker-compose up -d

All done. Deploy as many WordPress sites as your server can handle. Just remember to obtain certificates and specify a unique VIRTUAL_HOST for each new installation.