Setup a local WordPress development environment with Docker

Karel - August 30, 2015

This article is part of a series about how to make A slightly less shitty WordPress developer workflow. Check out the other parts if you haven’t already. You can also find the project on Github.

UPDATE March 12, 2016: Thanks to the great contribution of Derek Sifford the project has step its game even more. We updated this repository to reflect the changes.

So before we get started with that actual WordPress workflow, we will first need a development environment. We will use Docker because it is really nice to be able to create whatever development environment you need on your machine without polluting it by installing everything locally.

That said, this article is not about Docker per se. There are hundreds of resources out there to learn Docker if you want to dive more into it. The rest of the article assumes you have Docker and Docker Compose installed and we will:

  1. Run the Docker WP environment
  2. Create your WP theme
  3. Interact with the database
  4. Install the plugins
  5. Setup the uploads/ folder

1. Run the Docker WP environment

Let’s first grab visiblevc/wordpress-starter from Github. Let’s very originally name the project… the-project:

git clone the-project
cd the-project

Pro tip: The project uses the Docker visiblevc/wordpress which is available publicly on the Docker Hub. If you’d like to modify it, the Dockerfile is available in the github repository, feel free to modify it.

With Docker and Docker Compose installed and running, simply run:

docker-compose up
# visit localhost:8080

NOTE for Mac OS: If you are running boot2docker and don’t see anything, you might need to forward the ports from VirtualBox to your local machine. To do so, simply run this command VBoxManage controlvm vm-name natpf1 "tcp8080,tcp,,8080,,8080". Make sure you replace vm-name with the actual name of your vm, if you run boot2docker, it is likely boot2docker-vm and if you run Docker Machine, it is likely default.

Voila! You have a fresh install of WordPress with a clean database. Let’s create a new theme.

2. Create your WP theme

We will create a theme we will very originally name… the-theme. Obviously you can use an existing theme instead.

So now we have a theme at /wp-content/themes/my-theme. But at this point Docker doesn’t know about it because we haven’t told it where to look for. The docker-compose.yml file is where all the orchestration takes place. Put simply, when you run docker-compose up, it takes care of running a mysql server and an apache server with PHP and WordPress installed. And it also is responsible of sharing folders with the host. To make our theme available to our WordPress install, we can modify the volumes section of our wordpress container of the docker-compose.yml file:

# ...
- ./data:/data
- ./wp-content/themes/the-theme:/app/wp-content/themes/the-theme

This tells docker to mount your theme /wp-content/themes/the-theme at /app/wp-content/themes/the-theme on the server. If you are still running the server, you can kill it (ctrl+c) and run it again with docker-compose up so it takes our new mounting into account. This time, your theme will be shared. It means that you can locally modify the theme and the changes will be picked up by the server running with Docker.

3. Interact with the database

When you ran docker-compose up the first time, it configured WordPress for you and created an empty database. It is fine if you want to start from scratch but in our case, we already have a WP website and want to reuse its database.

If there is a /data/database.sql file in your project the first time your run docker-compose up, it will actually use it to populate the database. It is convenient when you need to setup someone quickly to work on the site.

But there are situations when you want to bring your production database locally or vice versa. There is a great plugin named WP Migrate DB that helps with getting dumps of the database. It is especially useful since it takes care of the search and replace for you. For instance your production server might run at but the local one is at localhost:8080, WP Migrate DB will replace them for you.

You might have noticed we share the /data/ folder with the Docker container inside the docker-compose.yml. So if you have a dump at /data/database.sql, you can restore/backup the database with those two commands:

# restore the database with /data/database.sql
docker exec $(docker ps -lq) /bin/bash -c "wp db import /data/database.sql --allow-root"

# dump the database to /data/database_bk.sql
docker exec $(docker ps -lq) /bin/bash -c "wp db export /data/database_bk.sql --allow-root"

4. Install the plugins

You might have noticed that we are not versioning wordpress core file. We won’t version control plugins either. The way this project is setup, we only track the files relevant to our specific project, namely our theme.

We don’t want to store WordPress core files or plugins because they are versioned and can be updated. If you do version them, as soon as you have multiple instances of the project (think development and production), you will find yourself having to sync those core files. Imagine one of your wordpress users (non technical) updates WordPress on your production server, if you were versioning the core files, the repositories would be out of sync… and it sucks! The truth is that 99% of the time, you want the latest version of WordPress and the plugins.

So how do you get the latest version? It is simple, add the plugins you need to the docker-compose.yml file where you can put the name of the plugins, one by line, that you want in your project. When you docker-compose up it will install the plugins. You can also install and uninstall specific plugins:

# install a plugin
docker exec $(docker ps -lq) /bin/bash -c "wp plugin install akismet --allow-root"

# remove a plugins
docker exec $(docker ps -lq) /bin/bash -c "wp plugin uninstall akismet --deactivate --allow-root"

Pro tip: In the event you need a specific version of a plugin, or a plugin that is not available to download automatically from WordPress or that is specific to your project, it is ok to version control it! In that case, you will need to whitelist the specific plugin in your .gitignore:


5. Setup the uploads/ folder

You don’t want to version uploads either because they change in production and syncing the changes with git is a terrible idea. So we are mounting the /wp-content/uploads directory from the server and you can drop them in your local project to have access to them but just don’t version them!

We will see in another article how we store our assets in S3 and Cloudfront anyway for performance.


So we now have a working WordPress install, with a custom theme, a database, and our plugins.

If for some reason you have custom needs (editing the .htaccess or wp-config.php files for instance), you can create theses files and mount them. You are not limited to what was presented above.

In the next article, we will see how we can setup an asset pipeline to make the theme development a lot more pleasant!