The beauty of Docker is how portable your applications become. Beyond that it also allows to version control our entire instance, providing a mechanism for quick rollbacks, updates, and audits. This tutorial will show you how to host your WordPress site with Docker by creating an image for it and deploying it.
The simplest example of running a WordPress site in Docker is too pull down the official WordPress image.
docker pull wordpress
If you prefer to use a specific version of WordPress, we can specify that when we pull an image. For example, we can pull down version 4.9.5.
docker pull wordpress:4.9.5
To run a WordPress container from the image we pulled down, we run the following command.
docker run -d -p 80:80 wordpress:4.9.5
Verify that the image is running by using the docker ps command. The output will show you the containers state, name, and network information. If everything looks fine, we can now create your own Docker image based on the WordPress one you’re using.
Creating Your Dockerfile
Create your workspace for building a new image.
mkdir ~/Workspace/Docker/WordPress
Create a new empty file called Dockerfile in the workspace and edit as follows:
FROM wordpress # Set environment variables used by the WordPress image # DB_USER and DB_PASSWORD are included as an example. However, # these should be removed and set during docker run. ENV WORDPRESS_DB_HOST=127.0.0.1 \ WORDPRESS_DB_USER=wpuser \ WORDPRESS_DB_PASSWORD=super-secret-password \ WORDPRESS_DB_NAME=wpsite \ WORDPRESS_TABLE_PREFIX=wp_ COPY plugins/ /var/www/itlc.comp.dkit.ie/htdocs/wp-content/plugins COPY themes/ /var/www/itlc.comp.dkit.ie/htdocs/wp-content/themes COPY uploads/ /var/www/itlc.comp.dkit.ie/htdocs/wp-content/uploads
Now build your custom WordPress image.
docker build -t myblog/wordpress:1.0.0 ~/Workspace/Docker/WordPress
Running Your Custom WordPress Docker Container
Let’s run a container based on our new Docker image. Start a new container based on your image.
docker run -d -p 80:80 myblog/wordpress:1.0.0
You should not encounter any issues. Use docker ps to verify the container is running and open a web browser and check the site is accessible.
Customize Your WordPress Image
We made a new image based on the official WordPress one. However, there’s no difference between the two. Let’s customize ours to match our needs.
We’ll be seeding our new image with our theme pre-installed. We’ll also add a couple of plugins, too.
In your Docker image’s workspace, create a new directory for your theme.
mkdir -p themes/mytheme
Create a new directory for your plugins.
mkdir plugins
Extract your theme into the themes directory or clone it from your repository.
git clone http://github.com/example/mytheme.git themes/mytheme
Extract each plugin in the plugin directory.
cd plugins tar xvf path/to/plugin1.tar.gz tar xvf path/to/plugin2.tar.gz
Use the COPY Dockerfile instruction to copy the theme and plugins to your image during build. Open your Dockerfile and add the following lines:
COPY themes/mytheme /var/www/html/themes/mytheme COPY plugins/plugin1 /var/www/html/plugins/plugin1 COPY plugins/plugin2 /var/www/html/plugins/plugin2
Making Your Themes, Plugins, and Uploads Persistent
The problem with seeding your WordPress image with your themes, plugins, and uploads is that any changes to them will not persist. This is because Docker containers are ephemeral — all changes to it while running will be lost when the container is stopped.
By using Docker’s volumes feature we can ensure all changes to certain directories are preserved when we restart the container.
Add a volume for your themes, plugins. and uploads WordPress directories to your Dockerfile.
VOLUME ["/wp-content/themes/mytheme","/wp-content/plugins","/wp-content/uploads"]
Now build a new version of your WordPress image.
docker build -t myapp:0.0.1 .
Let’s run the new image and test that all changes to themes, plugins, or uploads are persistent.
docker run -d -p 80:80 myapp:0.0.1
Open the WordPress site in a web browser, install a plugin andupload a few images.
Now identify the docker images ID using the docker ps command, and use it with the docker stop command.
docker stop nifty_hopper
Verify that the container is no longer running with docker ps
View the contents of the plugins, themes, and uploads directories.
ls ./plugins ls ./themes ls ./uploads
Now start a new WordPress container based on your image and verify that your plugins and images are still available!
Tip: All volumes are written to an unspecified location on the filesystem managed by Docker when they are created. To specify the location on your filesystem you wish for the volumes to mount from, you can do so using the -v
flag. eg.
docker run -d -p 80:80 -v themes/mytheme:/var/www/itlc.comp.dkit.ie/htdocs/wp-content/themes/mytheme -v plugins:/var/www/itlc.comp.dkit.ie/htdocs/wp-content/plugins -v uploads:/var/www/itlc.comp.dkit.ie/htdocs/wp-content/uploads myapp:0.0.1
Lower Your Container’s Privileges
Your container will run as Root by default. This can lead to unexpected security vulnerabilites that can easily be thwarted by changing which user the container runs as.
Your container will run as Root by default. This can lead to unexpected security vulnerabilites that can easily be thwarted by changing which user the container runs as.
The Dockerfile has a USER instruction that allows you to specify a user with the least amount of privileges required to run your container. If you are mounting volumes from your filesystem, the user or a group it is a member will need access to the directories.
Create a new user for your WordPress container and grant ownership of the themes, plugins, and uploads directory the container will mount from to our new user.
useradd wpuser1 chown -R wpuser1 themes chown -R wpuser1 plugins chown -R wpuser1 uploads
Add the USER directive to your Dockerfile like so:
USER wpuser1
Running Containers in Production
In a production environment we want to ensure that our container is always running. Our WordPress site should be able to survive container failures and system reboots, for example.
A good policy to begin with is the unless-stopped policy. This always ensures the container is scheduled to run, unless we stop it for administrative reasons.
We set the policy when the container is started using the -restart flag followed by the policy. The following example shows you how to set the restart policy to unless-stopped.
docker run -d -p 80:80 -restart unless-stopped myblog:0.0.1
To put it all together (and keep things maintainable) we use Docker Compose, a tool built in Docker that allows us to define the starting conditions of our containers. Our new docker-compose.yml will look something like this:
version: "3.7" services: wordpress: image: wordpress ports: - "80:80" environment: - WORDPRESS_DB_HOST=127.0.0.1 - WORDPRESS_DB_USER=wpuser - WORDPRESS_DB_PASSWORD=super-secret-password - WORDPRESS_DB_NAME=wpsite - WORDPRESS_TABLE_PREFIX=wp_ volumes: - /opt/wpsite/themes:/var/www/itlc.comp.dkit.ie/htdocs/wp-content/themes - /opt/wpsite/plugins:/var/www/itlc.comp.dkit.ie/htdocs/wp-content/plugins - /opt/wpsite/uploads:/var/www/itlc.comp.dkit.ie/htdocs/wp-content/uploads
To start our WordPress site we now only need remember to run docker-compose up. All of the volumes and environment variables needed to run our WordPress site are defined in the docker-compose.yml file.