Dockerizing a WordPress site with a MySQL database

Posted by in DevOps, last updated on 03 May, 2020

Introduction

I had a couple of WordPress sites I wanted to dockerize and move over to my new server. This is the configuration I used to deploy them to my new server as described here.

I’m using the official wordpress and mysql images and don’t need to build anything, so all I need to deploy the app is a docker-compose.yml file and a couple of .env files.

The docker-compose.yml file

I’m using the wordpress:5.4.1 (also tagged as wordpress:5.4.1-apache) which uses an Apache server and serves the app on port 80. Port 8080 is mapped to my host.

version: '3.7'

services:
  wordpress:
    image: wordpress:5.4.1
    restart: always
    volumes:
      - wordpress:/var/www/html
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
    env_file:
      - wordpress.env
    depends_on:
      - db

  db:
    image: mysql:5.7.30
    restart: always
    volumes:
      - data:/var/lib/mysql
    env_file:
      - db.env

volumes:
  data:
  wordpress:

Note that we need to specify the WORDPRESS_DB_HOST and the name we pass needs to match the service name we’ve given mysql, which is db in this case.

We’re creating two named volumes, one for the WordPress files (wordpress:/var/www/html) and one for the database data (data:/var/lib/mysql).

Lastly we’re using two .env files, db.env and wordpress.env which will hold our database credentials which we’ll later use to connect the site to the database.

The .env files

In the db.env file I’ve specified the following:

MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_DATABASE=your_db_name
MYSQL_USER=your_username
MYSQL_PASSWORD=your_user_password

And in the wordpress.env file:

WORDPRESS_DB_NAME=your_db_name
WORDPRESS_DB_USER=your_username
WORDPRESS_DB_PASSWORD=your_user_password

The above can be any names and passwords you want but they need to match.

Note that the .env files can be named anything you want as long as they corresponds to the name supplied in the docker-compose.yml file.

Note: don’t commit these files to your version control system, I usually ignore all *.env files in my .gitignore file.

Running the blog locally

Next to make sure everything is set up correctly run the app locally with:

docker-compose up

You should be able access the WordPress 5 minute install page by visiting http://localhost:8080. Go through the steps to make sure everything is working and WordPress can connect to the database.

Migrating an existing app

In my case I was moving a standard WordPress installation from SiteGround servers onto my DigitalOcean droplet and dockerizing it. I decided to use the duplicator plugin.

First install the duplicator plugin on your old WordPress site and create and download a new duplicator package which consists of an installer.php file and an archive zip file.

With the free duplicator version you need an empty directory to install the site in, so we’ll need to delete all the files from the /var/www/html/ directory within the container. First find the container name:

docker ps

# output:
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                      NAMES
cd241e74dc25        wordpress:5.4.1         "docker-entrypoint.s…"   4 minutes ago       Up 2 minutes        0.0.0.0:8080->80/tcp       your_project_wordpress_1
33739a43fad5        mysql:5.7.30            "docker-entrypoint.s…"   4 minutes ago       Up 2 minutes        3306/tcp, 33060/tcp        your_project_db_1

Then attach to the process with:

docker exec -it your_project_wordpress_1 bash

# output:
root@cd241e74dc25:/var/www/html#

Next you can delete all the files and directories within the html directory:

rm -rf /var/www/html/*
ls -a
exit

Now copy the archive zip file and installer.php from your host into the html directory (note you’ll need to scp the files into your remote server first and cd into the directory):

docker cp installer.php your_project_wordpress_1:/var/www/html/
docker cp long_name_of_archive.zip your_project_wordpress_1:/var/www/html/

Visit http://yourwebsite.com/installer.php and follow the instructions. You’ll need to fill in the database fields with the credentials you put in the db.env file.

The duplicator files will be deleted once you’re done and you can double check that with:

docker exec your_project_wordpress_1 ls -a

Your website and database should now be all up to date.

Too many redirect error

If you’re setting up SSL on your website (which you definitely should be) you may run into an ERR_TOO_MANY_REDIRECTS error when trying to access some or all of the pages on your WordPress site.

I was running into this issue as I’m using an NGINX reverse proxy to serve my WordPress site and redirect to https. WordPress is then being served by an Apache server (this is how the official wordpress image used above is configured), and I was missing one small configuration to make this setup work.

To fix this edit your wp-config.php file and at the top add:

$_SERVER['HTTPS'] = 'on';

I had another reference to $_SERVER['HTTPS'] = 'on' within an if statement in my wp-config.php file which I deleted as it wasn’t being picked up. Your config file may not have this though.

After that everything worked fine!


Daniel Wachtel

Written by Daniel Wachtel

Daniel is a Full Stack Engineer who outside work hours is usually found working on side projects or blogging about the Software Engineering world.