WordPress from Development to Production using Docker Part II

This post continues where part one left off. Topics include mysql data migration, staging and production docker configurations with optional https.

To perform these steps, you will need to either:

  1. Create the files directly on the server using nano, vim or some other command line editor.
  2. Create the files on your local machine and copy them to the server using scp.

I prefer the latter method. Creating the files locally in a folder structure that mirrors my home directory on the server makes it easier to edit and deploy them to the respective server. Not to mention the local backup this creates. Use scp from the command line or use a GUI application such as FileZilla or WinSCP.

Reverse Proxy

For staging and production, create a docker-compose.yml file that defines a reverse-proxy service using the official Traefik image. It is a good idea to put the Traefik Docker files in its own folder to make it easier when adding more sites later. Create a folder on the server for your Traefik files and save the compose yaml there.

version: "3"

    image: traefik:v1.7
    restart: unless-stopped
    # command: --docker --logLevel=DEBUG
    command: --docker --logLevel=INFO
      - webgateway
      - "80:80"
      - "8080:8080"
      - "443:443"
      - /var/run/docker.sock:/var/run/docker.sock
      - ./certs:/etc/traefik/certs
      # `chmod 600 acme.json`
      - ./acme.json:/etc/traefik/acme.json
      - ./traefik.toml:/etc/traefik/traefik.toml
      # - $PWD/.htpasswd:/etc/traefik/.htpasswd

    driver: bridge

update: note that we’re pulling a traefik version 1 image in the docker-compose.yml above. The traefik:latest image switched to version 2 a little over a year after this post was originally published. A configuration migration guide can be found here should you want to use version 2.

This Traefik docker-compose.yml uses Let’s Encrypt for free SSL certificate renewal. Create a traefik.toml and acme.json file to set that up. If you already have an SSL certificate for your site, use the certs folder to store the certificate files there for mounting to the Traefik container.

defaultEntryPoints = ["http", "https"]

  address = ":80"
  address = ":443"
      # comment these lines if not in use
      # non let's encrypt certificates
      certFile = "/etc/traefik/certs/myothersite.com.crt"
      keyFile = "/etc/traefik/certs/myothersite.com.key"

email = "gilfoyle@piedpiper.com"
storage = "acme.json"
onHostRule = true
# caServer = ""
entryPoint = "https"
  entryPoint = "http"

For staging, comment out the lines for https in traefik.toml as needed. More information on how to do this is included in my recent post: VPS Proof of Concept for Docker and Traefik.

The acme.json file is used by Traefik for certificate storage. Create this file and set the permissions to 600 so only the owner can read and write. For example.

# change to the folder where our Traefik docker files are stored
cd docker/traefik

# create an empty acme.json file
touch acme.json

# set permissions to 600
chmod 600 acme.json


Once your docker image is deployed, you are ready to create a staging and production docker-compose.yml file for mysite.

version: '2'

    image: mysite:4.9.6-1.0
    restart: unless-stopped
      - WORDPRESS_DB_HOST:mysql:3306
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=changeme!
      - WORDPRESS_DB_NAME=wordpress
      - traefik.frontend.rule=Host:local.vm.mysite.com
      - traefik.docker.network=traefik_webgateway
      - app:/var/www/html
      - web
      - backend
      - mysql

    image: mariadb
    restart: unless-stopped
      - "traefik.enable=false"
      - MYSQL_ROOT_PASSWORD=changeme!
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=changeme!
      - mysql:/var/lib/mysql
      - backend

      name: traefik_webgateway
    driver: bridge


For production, replace label traefik.frontend.rule=Host:local.vm.mysite.com with the registered host. You can specify both without and with www, for example: traefik.frontend.rule=Host:mysite.com,www.mysite.com.

To recap, here is how we have structured our Docker files in the users home folder on the server for mounting them to volumes and running the containers with docker-compose. The docker/traefik/certs folder is only needed for non Let’s Encrypt certificate storage, for example, certificates purchased from SSLs.com. Note that we did not create an additional site, e.g., myothersite. It is included below only to demonstrate that multiple sites can be added using this setup and they can use either Let’s Encrypt or purchased certs.

  • docker
    • mysite
      • docker-compose.yml
    • myothersite
      • docker-compose.yml
    • traefik
      • docker-compose.yml
      • acme.json
      • traefik.toml
      • certs


Start the containers on the server using docker-compose. Do this by opening a secure shell using ssh. For example,

ssh gilfoyle@

# change to the directory where you uploaded the
# traefik docker-compose.yml file using scp
cd docker/traefik

# start the traefik container
docker-compose up -d

# change to the directory where you uploaded the
# mysite docker-compose.yml file using scp
cd docker/mysite

# start the app and mysql containers defined in the mysite/docker-compose.yml
docker-compose up -d

To view the site on staging, update your systems hosts file to direct local.vm.mysite.com requests to the staging server IP address. For example:    local.vm.mysite.com

Load the site in a browser and install WordPress, for example, http://local.vm.mysite.com.

Data Migration

Once your WordPress site is installed, you may want to restore the data from another mysql volume. Perhaps your dev server has the data you now want on your staging instance of WordPress.

1. Perform a mysql dump to get the data from the running mysql container on the dev server. For example, using the development environment from part one, our container is named my_wordpress_project_mariadb.

# get the mysql container name by listing all of the containers
docker ps -a

# dump the mysql data into the current directory
# from the running docker container named
# my_wordpress_project_mariadb
docker exec my_wordpress_project_mariadb /usr/bin/mysqldump -u root --password=password wordpress > wordpress.sql

2. Prepare your dev server mysql dump for loading into the staging server. Open the wordpress.sql file in a code editor and replace all instances of the host:port with the staging server host. For example, replace dev.docker.mysite.com:8000 with local.vm.mysite.com.

3. Upload the updated wordpress.sql file to the staging server using scp.

4. ssh into the staging server and load the wordpress.sql into the running mysite mysql container.

# get the mysql container name by listing all of the containers
docker ps -a

# load the mysql data from the current directory
# into the running mysite_mysql_1 docker container
cat wordpress.sql | docker exec -i mysite_mysql_1 /usr/bin/mysql -u root --password=changeme! wordpress

After loading a new Docker image, you will need to remove the pre-existing app volume before bringing up the app container for the new image. Use docker volume ls to list the volumes and docker volume rm to remove the app image. For example, docker volume rm mysite_app.

That’s it!

Part 2 of 2 in the WordPress from Development to Production using Docker series.

WordPress from Development to Production using Docker

comments powered by Disqus