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
- install docker
- install docker-compose
- GitHub repo: https://github.com/Nxtra/Docker-Compose-Wordpress
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 volumes: volumes 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 services: themselves. 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.
- networks: This 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.
- image: use the phpmyadmin/phpmyadmin image to build this service from
- environment: sets 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’.
- ports: Again 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.
- networks: this 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:
- ports: Here we are mapping port 80 (for http) and 443 (for https) from our container to ports 80 and 443 on our host machine.
- container_name: we 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!