Docker Compose & WordPress

You want a website that is easy to set up and update. You want to deploy quickly and anywhere.
Behold, Docker and WordPress. Even if you are not that familiar with Docker or WordPress, this is the ideal entrypoint to start your journey in the world of containers.

How can I create a WordPress website with docker you say!? Well, I asked myself that same question a while ago. And here I am, writing a tutorial about it. On my own website, which of course, is running in Docker!

 

Tutorial

This tutorial will teach you how to create your WordPress website with docker-compose. In the process I will tell you what you are creating. I could find many tutorials that make you copy the ‘code’ but never tell you exactly what you are doing.

(However if you are looking for the compose yaml file only? Jump straight to the final docker-compose.yml )

Prerequisits

 

Let’s do this

Step 1: docker-compose.yml

Create a directory WordPress. In this directory create an empty file docker-compose.yml.

mkdir WordPress && cd WordPress
touch docker-compose.yml

The docker-compose.yml defines the services that make up your app. In this docker-compose.yml you will state which services  you want to create. You’ll also provide options to define them. These services are docker containers that work together. Further on in this when we talk about a service, we are referring to the container which will be running after we start up this service.

 

Step 2: Database service

Let’s start with the database. That’s the place where WordPress stores all your posts. We’ll define this service in the docker-compose.yml

In your ‘docker-compose.yml’ file, entry the following:

version: '3.7'

volumes:
  wp-data:
networks:
  wp-back:

services:

  db:
    image: mysql:5.7
    volumes:
      - wp-data:/var/lib/mysql
    environment:
       MYSQL_ROOT_PASSWORD: rootPassword
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wp-user
       MYSQL_PASSWORD: wp-pass
    ports:
      - 8889:3306
    networks:
      - wp-back

Well what the hell did we just compose? If you already know the syntax or don’t care you can jump the next part.The version: specifies the version of docker-compose you wish to use. At the time of writing this tutorial 3.7 is the most recent one. If you follow along, I advice you to follow the values of that are in my tutorial.

Next we see volumesvolumes specifies the ‘named volumes’ you will use. Ok, but what’s a volume? Volumes are the most used way to persist data in Docker containers and services. Data that your services  use is stored here. And even when your service goes down, the data will still be there the next time you start your service. Docker will place this volume in the default directory that Docker uses for named volumes.

What is networks: Here you indicate the name of a network you wish to set up. When you configure your services you can tell them to use this network. You should think of this as the way that all your services are connected and know each other. Docker-compose will create a network by default if you do not explicitly state it here. But you are not able to chose the name.

Over to the servicesthemselves. I told you we would start with the database. And that is exactly what you are doing here. We specify a service, db, which is configured with the following options:

  • image: which docker image to use for this service. Here we use the mysql database version 5.7 .
  • volumes: Here we are telling the image to use the volume that we just defined in the volumes: section. You should read the value like: Use the wp-data volume on my server to share the content of the var/lib/mysql directory in the docker container. We call this mounting with a volume. We are sharing data between the container and the host computer / server.
  • environment: This sets the environment variables for in your container. We are telling the mysql container the password of the root user, the name of our database, the user and password that the WordPress container (see below) will use to connect with the database;
  • ports: A mysql database runs on port 3306 by default. So, in the db docker container, the database will be accessible at port 3306. But hey, a container is an environment that is seperated from our server/computer. So how will we access this database that exists in the container. We map port 3306 in the container to port 8889 on our computer. You can actually chose which port you want to map to on your own computer. But for the sake of keeping it simple, follow along and map to port 8889.
  • networksThis container has to use the network with name ‘wp-back’. This is the network that we specified on top of the file.
Spin it up!

Save the ‘docker-compose.yml’ file. If you are not already there, cd  into the WordPress directory and start the service by executing these commands:

cd WordPress
docker-compose up -d

This is the way to tell docker to start the services that are defined in the docker-compose.yml file. Starting a service means starting the container that makes up this service. The -d starts the container in detached mode. This means that the container will start, but you and your terminal will stay right where you are in the WordPress directory.

To verify that the service is running:

docker ps

You should see a container that just started.

 

Step 3: phpMyAdmin service

phpMyAdmin is a free software tool intended to handle the administration of MySQL databases.

Add an extra service to your ‘docker-compose.yml’ file which will now look like this:

version: '3.7'

volumes:
  wp-data:
networks:
  wp-back:

services:
  db:
    image: mysql:5.7
    volumes:
      - wp-data:/var/lib/mysql
    environment:
       MYSQL_ROOT_PASSWORD: rootPassword
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wp-user
       MYSQL_PASSWORD: wp-pass
    ports:
      - 8889:3306
    networks:
      - wp-back

  phpmyadmin:
    depends_on:
      - db
    image: phpmyadmin/phpmyadmin
    environment:
      PMA_HOST: db
      MYSQL_USER: wp-user
      MYSQL_PASSWORD: wp-pass
      MYSQL_ROOT_PASSWORD: rootPassword
    ports: 
      - 3001:80
    networks:
      - wp-bac

The next service you define is phpmyadmin. Again I’ll guide you through the configuration options that define this service:

  • depends_on: docker-compose will start the service in dependency order. So by saying depends_on, the db service will be started first. Only when this one has started the phpmyadmin service will come up.
  • imageuse the phpmyadmin/phpmyadmin image to build this service from
  • environmentsets the container environment variables. PMA_HOST stands for PhpMyAdmin host, telling the container who is the database host. Here we are referencing our database service ‘db’.
  • portsAgain we want to be able to access the PhpMyAdmin tool. In the container it is running on port 80. We will map port 80 in the container to port 3001 on our host, so that we can access PhpMyAdmin.
  • networksthis service should use the same network as the db mysql service, namely ‘wp-back’.

 

Step 4: WordPress service

Add the wordpress service to your docker-compose.yml file to make it look like this:

docker-compose.yml

version: '3.7'

volumes:
  wp-data:
networks:
  wp-back:

services:

  db:
    image: mysql:5.7
    volumes:
      - wp-data:/var/lib/mysql
    environment:
       MYSQL_ROOT_PASSWORD: rootPassword
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wp-user
       MYSQL_PASSWORD: wp-pass
    ports:
      - 8889:3306
    networks:
      - wp-back

  phpmyadmin:
    depends_on:
      - db
    image: phpmyadmin/phpmyadmin
    environment:
      PMA_HOST: db
      MYSQL_USER: wp-user
      MYSQL_PASSWORD: wp-pass
      MYSQL_ROOT_PASSWORD: rootPassword
    ports:
      - 3001:80
    networks:
      - wp-back

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - 8888:80
      - 443:443
    environment:
       WORDPRESS_DB_HOST: db
       WORDPRESS_DB_USER: wp-user
       WORDPRESS_DB_PASSWORD: wp-pass
    volumes:
      - ./wordpress-files:/var/www/html
    container_name: wordpress-site
    networks:
      - wp-back

By now we know what most of the options that define the service mean. We are dependent on the db service. We use the wordpress:latest image to start our container from. We set the environment variables that the container  will use to access the database. Again we are referring to an other service, db. We make it use the network wp-back.

Ok, I skipped a few:

  • portsHere we are mapping port 80 (for http) and 443 (for https) from our container to ports 80 and 443 on our host machine.
  • container_namewe give this docker container the name wordpress-site
  • volumes: it’s not the first time that we meet this option. The db service also used a volume. However the db service uses a named volume that we defined in the volumes: section on the top of the file. This container is using a volume that is not defined in the named volumes section. We call this a bind-mount. As you can see we are mounting to ./wordpress-files on out host. This is referring to the current directory. So this bind-mount will appear as a wordpress-files directory in the current WordPress directory. We are mounting the /var/www/html directory of our container to WordPress/wordpress-files on our host. This directory contains among others the wp-config.php file and wp-content directory.

 

Step 5: Start the website !

In your WordPress folder, run this simple command.

docker-compose up -d
docker ps

The desired result will look like this:

A couple of remarks:

  • If you look in your WordPress folder, you’ll notice an extra folder has been created.
    WordPress
    |   wordpress-files
    |   +-- docker-compose.yml

Remember the wordpress-files directory is the bind-mount that you defined in the wordpress service.

  • In the last column ‘NAMES’, you see the name ‘wordpress-site’ that you explicitly defined for the wordpress service. The other containers have been given names based on the default naming convention of docker-compose. This means prefixing them with the name of the parent directory of the docker-compose.yml file.

 

Start building your own website!

In your browser go to: localhost:8888

If you just executed the docker-compose up -d command, it can take half a minute before the website is available on your host machine.

 

From here on you can use your WordPress website like any other WordPress website you ever used. Change the theme, add posts, install plugins. All changes will be persisted even after a restart of the services.

Useful instructions

docker-compose

docker-compose up -d       Start your services defined in docker-compose.yml
docker-compose down        Stop services
docker-compose restart  Restart services
docker network ls               Show docker networks
docker volume ls                  Show docker volumes
docker inspect <containerId>  Inspect container with containerId *

*you can see the containerId when you execute the command docker ps.

 

Connect to the database with a database tool

It’s possible to connect to your database with an other tool than the PhpMyAdmin container. In our docker-compose.yml we mapped port 8889 on our host machine to port 3306 of the db container. You can access the database on your host machine via port 8889. Eg with mySQLWORKBENCH:

 

Troubleshooting

If your WordPress or another container is up but you cannot access it, access the logs:

docker logs <containerId>

Error: Port already in use = You probably have another application running on a port from your host that you are mapping to in your docker-compose.yml .

 

You can enter a container with this command:
docker exec -it <containerId> /bin/sh

Questions?

Don’t hesitate to ask in the comments!

Leave a Reply

Your email address will not be published.