Estimated reading time: 3 minutes
You can use Docker Compose to easily run WordPress in an isolated environmentbuilt with Docker containers. This quick-start guide demonstrates how to useCompose to set up and run WordPress. Before starting, make sure you haveCompose installed.
Step 1 - Install Docker. We will start from scratch, by installing docker and docker compose manually with the apt command. Before we begin, update the Ubuntu repository and install latest updates: sudo apt-get update sudo apt-get upgrade. By default, docker is available in the Ubuntu repository, so we can continue to install it right away. In order to install WordPress in a docker container, you must have docker and docker compose installed in your Ubuntu. If you already have docker and docker compose, you can now follow these steps to install WordPress in a docker container. Step1: Create a new directory for WordPress: $ mkdir /wordpressdocker/ if it is saved How to Install WordPress on Docker Container in Ubuntu 20.04.
Define the project
Create an empty project directory.
You can name the directory something easy for you to remember.This directory is the context for your application image. Thedirectory should only contain resources to build that image.
This project directory contains a
docker-compose.ymlfile whichis complete in itself for a good starter wordpress project.
Tip: You can use either a
.yamlextension forthis file. They both work.
Change into your project directory.
For example, if you named your directory
docker-compose.ymlfile that starts your
WordPressblog and a separate
MySQLinstance with volumemounts for data persistence:
The docker volumes
wordpress_datapersists updates made by WordPress to the database, as well as the installed themes and plugins. Learn more about docker volumes
WordPress Multisite works only on ports
Build the project
docker-compose up -d from your project directory.
docker-compose up in detached mode, pullsthe needed Docker images, and starts the wordpress and database containers, as shown inthe example below.
Note: WordPress Multisite works only on ports
443.If you get an error message about binding
0.0.0.0 to port
443(depending on which one you specified), it is likely that the port youconfigured for WordPress is already in use by another service.
Bring up WordPress in a web browser
At this point, WordPress should be running on port
8000 of your Docker Host,and you can complete the “famous five-minute installation” as a WordPressadministrator.
Note: The WordPress site is not immediately available on port
8000because the containers are still being initialized and may take a couple ofminutes before the first load.
If you are using Docker Desktop for Mac or Docker Desktop for Windows, you can use
http://localhost as the IP address, and open
http://localhost:8000 in a webbrowser.
Shutdown and cleanup
docker-compose down removes thecontainers and default network, but preserves your WordPress database.
docker-compose down --volumes removes the containers, defaultnetwork, and the WordPress database.
More Compose documentationdocumentation, docs, docker, compose, orchestration, containers
Running WordPress sites within a Docker container has grown in popularity since the inception of Docker. Doing so has many obvious benefits, especially for those developing themes and plugins. And while containerizing a WordPress site is not a stren
In this tutorial you will be progressively guided through each step for running a container in productions, from building the initial image to running it securely and reliabily in production.
Running WordPress Containers
WordPress publishes an official Docker image to Dockerhub. It is a bare bones, light weight container running on Alpine Linux. Pull the image down into your local repository.
docker pull wordpress
Notice that no release version was specified in our pull command. The default action performed by docker pull when no release tag is specified is to pull down the latest image (or <image-name>:latest>. To pull down a specific version of WordPress add the version tag to the docker pull command.
docker pull wordpress:5.2
Let’s run the base image to show the container in action. We will use the -p flag to expose the container on port 80 and use the -d flag to daemonize the container to run in the background.
docker run -d -p 80:80 wordpress
For a typical WordPress install one of the first actions you take will be to configure your database. The base image accepts a number of environment variables used to configure WordPress. The key variables to know are for configuring the database endpoint.
Docker provides a flag to set a list of environment variables. The following is an example of running the base WordPress image by setting the database related environment variables.
Now, that isn’t likely something you are going to want to type over and over. Thankfully, Docker has a feature for setting environment variables via a text file. Create a new file called wp_vars and then add the following contents. Ensure you set the values to match your environment.
To use the environment variables file when running the WordPress container we use the –env-file flag. Run the base image and point the –env-file to the wp_vars file.
You have successfully used the base image to run WordPress as a Docker container. Must sites do not run a vanilla install of WordPress, so in the next section we will look into customizing an image for a site.
Customizing the WordPress Image
Dockerfile is a file used by Docker to template the build of a new Docker image. Most images build on top of existing images to extend their configurations. We will do the same by building a new image for a WordPress blog on top of the official WordPress docker image.
Create workspace on your filesystem to store your WordPress docker project.
Within the workspace, create a new file named Dockerfile and then add the following contents to the Dockerfile.
Our Dockerfile has two steps: FROM and ENV. The FROM step instructs Docker to build a new image based on the wordpress image. The ENV step allows us to set the envirnonment variables for WordPress. Notice how the WORDPRESS_DB_PASSWORD variable is missing from our Dockerfile. Storing sensitive information, also known as secrets, within our configuration files is very insecure. Instead, we will set the variable when the container is started.
Let’s build our new custom image. We will tag our image with a name and version to maintain a history of changes. Since this is our first build, we will tag the image with myblog:1.0.0.
After a successful build, our image will be available in our local Docker repository. We can verify this by running the docker images command.
Let’s run our first image. We will set the WordPress database password using the -e flag. Alternatively, we could have used and environment variables file as we did earlier.
Adding Plugins and Themes
While a vanilla instance of WordPress might satisfy some, most customize WordPress via additional plugins and themes. Both can be installed via the admin portal. However, since running containers are ephemeral all changes are lost when the container is stopped.
There are two solutions available. The solution will be covered in this section, and that is to add the plugins to the build process. The second option, attaching peristent storage to the container, will be covered in a section below.
Docker provides to commands to add contents to an image build – ADD and COPY. While both can add downloads plugins and themes to the WordPress image, the ADD command will automatically extract archives to the target.
In your workspace create directoreis to store themes and plugins, and then download some themes and plugins into the appropriate directories.
Modify the Dockerfile to add the themes and plugins to the WordPress install within your image. For each item we specify a source, on the local machine, and then a target within the image itself.
ADD plugins/plugins-a-1.0.0.tar.gz /var/www/html/wp-content/plugins
Save your changes and then run a new build. If desired, increment your image version by one.
Run your updated Docker image and verify that the themes and plugins you installed are available.
Adding plugins and themes to your build is convienent, but it creates a few problems. Plugins, for example, usually have a large volume of releases to address bugs and security issues. You could update the plugin from within the running container, however, since the container is ephemeral they updates will not be perserved when the container is restarted. Since updates can introduce database schema changes, your site will fail to load correctly with the outdated containter.
You could generate a new image build with every plugin update, except that will likely become an adminstrative burden. A better solution is to store your plugins and themes in persistent storage, which is mounted every time a new container is started. We cover this topic in the next section.
Persistent Storage for Content
Docker is able to mount directories on the host filesystem into the container at runtime. This feature allows data to persist beyond the lifecycle of a container, which is ephemeral (temporary). With the volumes feature we can install our plugins and themes on the local host’s filesystem, and all updates will be preserved.
In this section will use the directory structure we created earlier to host our plugins and themes. We will then mount the directory into our container.
To mount volumes we must use the Docker run -v flag. In the example below we providing a list of target mount points within the container. A source directory will automatically be created by Docker under the /var/lib directory when we don’t include the source.
Let’s mount our volumes again, but this time we will use the directories we created earlier as our sources.
Log into the admin area of WordPress and verify that the plugins and themes we placed in the source directory are available. Now stop the container and run again.
docker stop c68d32
Once again verify the plugins and themes are available. We have now successfully preserved changes to our container without having to add anything to our Docker build.
We are now free to update our plugins easily without being forced to rebuild our image. We are also free to install plugins and themes from within the admin portal, providing a more natural way of using WordPress. Alternatively, you may still download them to the source directory, where they will be available to the running container.
Try to install a new plugin from the Admin portal. You will likely be prompted for FTP server information. The reason WordPress behaved in this manner is because the volumes we mounted are owned by the root user. WordPress, running under the context of the www-data user does not have write access. We’ll look at solving this issue in the next section.
Running Container With Non-Privileged User
A large number of images available from Dockerhub, including the official WordPress image, run as root. Not surprising, this is not a secure way to run a container. Containers should only ever run with the least level of privileged to function. Going back to our issue writing to mounted volumes in then last section, our volumes are mounted as root and are, therefore, owned by the same account.
Docker has provided a USER option for the Dockerfiles, which will allows us to run our container as a non-privileged account. The caveat to this is the user account must also exist on the host file system. If it doesn’t already exist, we will have to create it.
The base WordPress container runs Apache Web Server, and that means WordPress is running as www-data. Let’s modify our Dockerfiles so that our container will also run as www-data.
Build a new version of your WordPress image and then restart the container.
Notice that your container has failed to load, as it wasn’t able to bind Apache to port 80. Only privileged users are allowed to bind to port 80, so will will have to instruct our container to allow binding by non-privileged accounts.
Restart your container and verify that it runs successfully. You will now be able to install and update plugins stored on the mounted volume.
Let’s face it, nothing is impervious to failure. There’s a good chance your container will fail for one reason or another, bringing your site offline. Obviously, this is undesirable since our uses expect nothing short of 100% uptime. Docker has several restart policies that can be applied to a container at runtime. These policies will attempt to restart a container after it has either stopped or failed.
Running the Container in Production
A container should only run with the least level of privilege needed. Unfortunately, many images found on
The output will display the user id, group id, and associated groups that container runs as. In our example below, we can see that the WordPress container is running as root.
Docker provides a USER option for the Dockerfile that allows us to specify the user or uid we want the container to run as. Whichever user is set here must also exist on the host server. You should map the user to that of the service running within the container, and for the WordPress image, which uses Apache Web Server, that means the www-data account. When creating the user on the host system it is important to map it to the same uid used in the image, which is 33.
Create the www-data user on the host server, if it doesn’t already exist.
Update the Dockerfile to add `USER www-data` to instruct Docker to run the container under the www-data user context.
If you attempted to restart your container with the latest changes, you will note that it will fail to launch successfully. The reason for this is that we are now running unprivileged, preventing Apache from binding to a system port (80). We can update our docker-compose.yml file to instruct the container to allow unprivileged port binding.
Add the following to your docker-compose.yml file under the service (blog) entry.
Your docker-compose.yml file should now look like the example below.
Rebuild your Docker image via docker-compose and then restart it.
Safely Handling Secrets
We’ve address running a Docker container reliably on a production server by utilizing docker-compose. We haven’t, however, addressed the elephant in the room, which is securely handling secrets. Unfortunately, with WordPress there isn’t an easy solution for handling database credentials securely. Whether we are storing this information in our docker-compose.yml file, storing it within our Dockerfile, or entering it as an env variable when executing docker run, the credentials are easily discoverable.
Wordpress Docker Compose
While docker provides a built-in secrets service for handling sensitive information, it is only available in swarm mode. We have not covered docker orchestration solutions in this tutorial, but to address this area of concern you will want to investigate running the container