Local WordPress Development with Docker


Do you want to drive more traffic to your web? So do I! That's why we created Nelio Content, a new plugin that automates content promotion in social networks. Want to know more?

Happy new year! I hope you enjoyed the holidays (assuming you didn’t have to work) and are now back, eager to learn. I sure am and I’m back with a fantastic tutorial for you: how to use Docker for WordPress development. I actually announced it a few days ago via Twitter (in Catalan):

Let me start with a brief story: I started my journey as a WordPress developer using LAMP (Linux + Apache + MySQL + PHP). Unfortunately, I quickly realized that, when working on more than one project at the same time, the setup was a mess, as they all used the same server, the same database… I then moved to Vagrant (VVV in particular), an environment designed for WordPress development, but it was a pain in the ass: my 6-year old computer had a lot of trouble running multiple Virtual Box instances and everything was extremely slow. I then tried to move to Local by Flywheel, because Antonio seemed to enjoy the environment a lot… but it never arrived to Linux! Wasn’t there a fast, reliable, easy-to-use option for me?

In the end, I decided I had to learn more about Docker and see if this tool I’d heard of would fit my needs. If you want to learn more about Docker too and want to use it in your WordPress developments, don’t miss this guide – learn how to build development environments quickly and efficiently.


Docker is a computer program that performs operating-system-level virtualization, also known as “containerization”. This has two main advantages compared to the classic LAMP setup:

  • containers are isolated from each other and the communication between them is limited, which increases security
  • tools, libraries, config files, and everything the container needs to run is in the container itself, which means we’ll have a clean and tidy setup – once we’re done with the container, we can remove it and everything will be gone.

In my opinion, the main advantage Docker has over other virtualization softwares is the virtualization environment it uses by default: runC. This environment runs all containers on the host OS (instead of running a full virtual machine), which makes things way faster and more lightweight. That means the host (our PC) and the guest (the container) will share a lot of resources and everything will run like a charm in an “old” computer.

Docker Installation

To install Docker on Linux (Debian/Ubuntu), just run the following command:

Follow the instructions on screen and wait until apt is done.

Once Docker is installed, we can use it with the docker command. The only problem with Docker is the fact that you’ll need to run it with admin privileges using sudo. But we can solve this. If you’d rather run docker without sudo (and thus avoid typing your password often), add your user to the docker group:

where your-user is obviously your username in Linux. BTW, you might need to log out and log back in to actually apply this change.

How to Install Docker on Mac or Windows

If you’re using Mac or Windows, you can also install Docker. Just follow the instructions on Docker’s website:

How to Use Docker

So, now that we have Docker set up and ready to be used, it’s time we give it a shot. As I said, Docker is a tool for managing contained apps. If we want to launch a container, we need to run the following command:

For example, try out this command:

to launch the classic Hello World within a Docker container. If everything worked as expected, you’ll first see something like this in your terminal:

This gives us some interesting information. First, Docker looked for an image named hello-world, but it couldn’t find it. Second, it looked for that image in an online image repository, and this time it succeeded and was able to download it. And that’s one of the great things about Docker: it has an image repository with several packed apps we can use as Docker containers (similar to what we have in WordPress, with the plugin and theme directories).

Now, back to our terminal, we can see the actual output of the Hello World container:

And that’s it! You’ve already run your first Docker container 😍

If you now type the following command:

you’ll see the container Docker created using the hello-world image:

To remove it, just type:

making sure that you type in the appropriate CONTAINER ID.

And that’s basically all there is to Docker… So let’s jump into yet another tool (Docker Compose) and learn how to use it as WordPress developers 😉

Docker Compose

As you can imagine, in Docker’s image repository there’s a WordPress image available. You might think that we simply need to pull that image and we’d be able to start a new WordPress site, but that’s actually not true:

  • On the one hand, this image doesn’t include the database system. So, if we want to start our WordPress site, we’ll need to install MySQL somewhere (or use a MySQL container).
  • On the other hand, the WordPress image requires some configuration parameters (such as, for instance, where’s the database and the credentials to access it). So everytime we run the instance, we need to specify those arguments.

Using the docker command alone can be complicated, specially when we have to start multiple containers all at once and some depend on others (as WordPress does). Luckily, there’s a tool called docker-compose that uses a configuration file to describe all the containers we need, the dependencies they have with each other, and their specific setup.

Let’s start by creating a new directory where Docker Compose’s config file will reside. For example, create ~/docker/test and add a file named docker-compose.yml with the following content:

I know this file might seem complicated, but it isn’t. Look carefully: the file simply defines the two services (or containers, if you will) that we need to run WordPress: mysql and wordpress. The former (mysql) contains information about the image we need (which is obviously a MySQL image, version 5.7) and some config parameters. The most relevant are probably the port mapping (we’ll be able to access the database using port 8081 in our host, which maps to 3306 in the guest) and the database setup itself (user, password, and so on).

The latter is WordPress itself (wordpress) and it follows a similar approach. Here we tell Docker Compose that we want WordPress to be accessible via the port 8080 in our host. We also specify that WordPress relies on the other service: mysql. And we finally add some additional configuration parameters (essentially, those to access the database).

Once we’re done, save and exit the file, and type the following command:

and Docker will download the WordPress and MySQL images and will start our WordPress.

Just wait for a couple of minutes and, once it’s done, go to http://localhost:8080 with your web browser (notice how the port we’re using here matches the one we specified in the configuration file) and you’ll see your new WordPress site:

Installing WordPress on a Docker Container
Installing WordPress on a Docker Container.

From this moment on, if we want to create new WordPress instances, you’ll simply have to repeat the steps we’ve discussed. That is, you’ll create a new directory in ~/docker/, you’ll add the docker-compose.yml file, and you’ll set it up. Just make sure that you’re using different ports for this new instance, or you won’t be able to run them both at the same time (for example, use 8082 for WordPress and 8083 for MySQL).

Once you’re done, you can stop the container running the following command:

Just make sure you use stop instead of down:

as down will not only stop the container, but also remove it completely. That is, if you restart a container using docker-compose up after you shut it down using the down command, your WordPress will start from scratch (an empty database, an uninstalled WordPress, etc).

Docker and WordPress Development

Great! You almost have all you need to develop WordPress plugins and themes using Docker effectively. I hope my explanations so far have been helpful and you now better understand what Docker is and how it works.

In my opinion, there are only two things missing to be 100% effective with this setup:

  • How to add your plugin or theme in the Docker container.
  • How to use domain names like http://content.local instead of http://localhost:port with Docker.

Adding Your Project into a Docker Container

Every time I have to work on a new plugin or theme, I create a new Docker container. If you follow the guide so far, you’ve probably realized that the WordPress installation created by Docker is completely empty and doesn’t contain any of our plugins or themes. So, assuming I’m working on a new plugin, how do I add that plugin in the wp-content/plugins/ folder that lies in the container?

There are multiple options to expose directories from the container and make them available in our host machine. The one I like the most maps the directory of our project (and only that directory) to a directory in WordPress. Let’s see this with a concrete example.

Assume I’m working on my plugin with my laptop. This plugin is currently in ~/dev/nelio-content/. I obviously want this plugin to be included in my development environment, so that I can test it and see that all the changes I apply work as expected. The first thing I’ll do is add a docker-compose.yml file in my plugin. The content of said file will be an exact copy of what we’ve already seen, but with one extra option:

Essentially, we simply added a new directive named volumes and we specify the mapping we want. That is, we want the current directory (namely, our plugin’s directory, identified with a dot .) mapped to /var/www/html/wp-content/plugins/nelio-content (which is a directory in the WordPress container). Easy, right? After all, the syntax we’re using is the same we used for port mapping, but we’re applying it to directories now.

And that’s it! If we now start our container, we’ll see that our plugin is available in the Dashboard » Plugins screen.

Using Domain Names

I personally don’t like accessing development installations using localhost and a port. I think using domain names like http://content.local is way easier. So, how can we achieve that? Well, we need a few things…

First, we need to tell our computer that a certain domain name (for instance, content.local) is the computer itself. This is as easy as editing the /etc/hosts file and mapping this new domain name to the localhost IP:

Great! Right now http://content.local is exactly equivalent to http://localhost. But that’s not exactly what we want… What we want is to map http://content.local to http://localhost:8080. To do that, we need a proxy server that maps requests to the former address to the latter. This is also very easy to achieve. Just create a new folder named ~/docker/proxy with the following docker-compose.yml file:

and start it using docker-compose up -d. This will install the proxy that’ll do all the magic.

Finally, we simply need to modify our WordPress container so that it automatically notifies the proxy about its existence:

Okay, so we’ve done a few things here. Let’s take a closer look at all the changes we applied:

  • In the WordPress environment section we added two new attributes: VIRTUAL_HOST and VIRTUAL_PORT. These are the attributes that our proxy will use to map the VIRTUAL_HOST to localhost:VIRTUAL_PORT.
  • Since we want our WordPress service to talk to our proxy, we need to make sure both containers are in the same network. This is pretty easy: we simply add a networks option in WordPress and include the frontend network (you can use whatever keyword you want). Then, at the end of the file, I added a few more rules. In particular, I added a networks section and specified that there’s an external network identified by the keyword frontend with the name proxy. Notice this external network is the same one we used in the proxy’s docker-compose.yml.
  • Finally, I want to make sure that WordPress and MySQL can talk to each other too, so I have to make sure they’re also in a common network. To do that, I added them both in another network named backend, which is internal and, therefore, nobody else can access.

And that’s it! You now know everything I know about this tool. I hope you enjoyed this guide and, if you did, please share it with your colleagues and let me know in the comment section below!

Featured Image by Abigail Lynn.

PoorMehGoodVery GoodAwesome! (2 votes, average: 5.00 out of 5)


He obtained his PhD in Computer Science at UPC. David leads the analysis and design of our services and the user support area. He's interested in a variety of areas, including conceptual modeling, virtual reality, and 3D digital printing. He contributes to the WordPress community by participating in meetups, seminars, and the WCEU.

4 thoughts on “Local WordPress Development with Docker

  1. thanks for this great tutorial but I can’t access to content.local, please record a video for this tutorial

    1. Hey Akbar! Glad you liked the tutorial. We might record a video in the future; in the meantime, please make sure you followed all the instructions AND edited /etc/hosts to map content.local to

Leave a Reply

Your email address will not be published. Required fields are marked *

I have read and agree to the Nelio Software Privacy Policy

Your personal data will be located on SiteGround and will be treated by Nelio Software with the sole purpose of publishing this comment here. The legitimation is carried out through your express consent. Contact us to access, rectify, limit, or delete your data.