Creating a local WordPress development environment using Docker Compose
WordPress is great for quickly getting new projects off the ground – be it a marketing website, a membership portal or an eCommerce platform (see WooCommerce). It has a fairly low entry barrier for development, considering the well-established plugin and theming system.
However, trying to run WordPress locally in order to creating something new (e.g. a theme or a plugin) can be a bit tricky, considering its requirements – PHP, MySQL, Linux-like file system.
Thankfully, Docker comes to the rescue as a way to containerize the WordPress app and its dependencies inside containers, making it easier for you as a developer to focus only on changing PHP code that’s relevant to the plugin or theme you are developing.
Let’s start with an empty project and the following docker-compose.yml file:
version: '3.3'
services:
# we'll list some services here later
This is the standard starting point for any Docker Compose project (a project that consists of multiple Docker containers).
Since we want to create a MySQL database for the WordPress installation and we don’t want to install MySQL locally, we could just use the standard MySQL docker image and create a service around it:
db:
image: mysql:5.7
volumes:
# Make the DB persist to disk after the MySQL container is restarted
- db_data:/var/lib/mysql
# Automatically restart the MySQL container on system restart
restart: always
# Pass some hardcoded values to the MySQL container
# It uses them the first time the container is started, in order to create the first MySQL database, first user, set his password, etc
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
Now let’s define the actual WordPress service and container:
wordpress:
depends_on:
# Wait for the MySQL container to start first
- db
image: wordpress:latest
# Make this container accessible over http://localhost:8000
ports:
- "8000:80"
# Restart the container when you restart the PC
restart: always
# Pass the same values that you passed
# to the MySQL container. Given the two
# containers are linked using "depends_on",
# this container can refer to the other one using
# the "db" hostname/alias
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
- ./wp-content/:/var/www/html/wp-content/ # Plugin and theme development
The important part is the volumes mount of wp-content. This makes the folder wp-content on your computer mounted and synced with the wp-content folder of the WordPress container. This allows you to develop themes and plugins seamlessly as if you are doing it inside the Docker container.
Finally, let’s define the volume that stores the DB data persistently on the disk:
volumes:
db_data: { }
Remember that we referred above to “db_data” while defining the MySQL container. This last bit just tells Docker to create a new “hidden” volume on the filesystem and store the db_data there. This makes the MySQL container persist its data across container restarts and host machine restarts.
The final solution is:
version: '3.3'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
volumes:
- ./wp-content/:/var/www/html/wp-content/ # Plugin and theme development
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: { }