Local WordPress Development with Docker and Docker Compose
Setting up a local environment for working with WordPress, or any development project can be time consuming. That typically means setting up a web server, a database, and support for all the languages/tools you’ll need. The problem is that installing this can get tricky, and they may not play nice with each other.
During the years i’ve been using everything from just running built in web server on my Mac, then switched over to using MAMP and then virtual machines using Vagrant. VVV, an open source Vagrant configuration for developing with WordPress is a good tool that we still use for some projects. Also, Trellis from Roots is another great tool for keeping development environments in sync between development, staging and producion servers.
But now it is 2018. I wanted something lighter and fast. Docker was the right choice.
Why Docker?
- Create containers with isolated development environments.
- Use fewer resources than with VMs.
- Share your containers to make collaborations easier.
Once you get your head around this idea of having “containers” and how to “link” those containers, you’ll find out how easy is to build your own developing (or production) environment with docker.
Docker and WordPress
To run WordPress locally we need this to get started:
- PHP
- MySql
- Nginx
- Composer for dependency management (when using Bedrock)
Additional tools such as WP-CLI is also convenient to have. More about that later.
Setup a local domain and create a self signed certificate
We want to use a local domain ex mywebsite.local
and also use a self signed cert for use https in our application. I often have a little cli
folder in the project root with some scripts to get started.
If you like, use my scripts in my starter repo
Use the scripts like this:
- Create a SSL cert in
./certs
usingcd cli && ./create-cert.sh
- Trust the cert in macOS Keychain using
cd cli && ./trust-cert.sh
- Setup vhost in
/etc/hosts
usingcd cli && ./setup-hosts-file.sh
Docker Compose
I’m going to use a tool called Docker Compose which enables you to configure the services you want your container to have and set them up all at once.
Create a file called docker-compose.yml
in your project root.
There is a bunch of things to cover here, so let’s break it down:
Nginx
Nginx (NGiИX) is our web server of choice.
nginx:
image: nginx:latest
container_name: mywebsite-nginx
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx:/etc/nginx/conf.d
- ./src:/var/www/html:rw,cached
- ./certs:/etc/certs
depends_on:
- wordpress
restart: always
Notes:
- Use the nginx image from Docker Hub.
- We are listening on both port 80 for http and 443 for https. More about setting up a local ssl cert later.
- Use three volumes. 1. Load a custom nginx configuration. 2. Mount our
src
folder in/var/www/html
and 3. Use local ssl-certs from./certs
I’m using caching for our volumes to increase the performance
Nginx configuration
In ./nginx
we also want to add our configuration. Very much just standard, and pointing to our certs.
Create the file wordpress_ssl.conf
and add this config
Note: Since we use Bedrock, the web root is
/var/www/html/web
Database
The database service is simple, just using the standard mariadb image and set some environment variables for password and database name.
mysql:
image: mariadb
container_name: mywebsite-mysql
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=mywebsite
restart: always
ports:
- '3306:3306'
WordPress
Our WordPress service configuration in this example is using the wordpress-php7.2-fpm.
wordpress:
image: wordpress:php7.2-fpm
container_name: mywebsite-wordpress
volumes:
- ./src:/var/www/html:rw,cached
environment:
- WORDPRESS_DB_NAME=mywebsite
- WORDPRESS_TABLE_PREFIX=wp_
- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_PASSWORD=password
depends_on:
- mysql
restart: always
Note: Although the default WordPress files will be downloaded in
./src
when running docker-compose up, I’m ignoring them in git and will be using the Bedrock structure. If you are not using Bedrock, just use the defaults.
Composer
I use Bedrock for all WordPress projects, it’s a modern WordPress structure/setup using development tools, easier configuration, and an improved folder structure. Bedrock also offers enhanced security with isolated web root to limit access to non-web files and more secure passwords through wp-password-bcrypt.
Since we use Bedrock we need Composer to manage our WordPress installation and plugins with Composer, a PHP dependency manager. Composer will make development more reliable, help with team collaboration, and it helps maintain a better Git repository.
We set working_dir
to /var/www/html
where our WordPress installation is located.
composer:
image: composer/composer
container_name: mywebsite-composer
working_dir: /var/www/html
restart: 'no'
volumes:
- ./src:/var/www/html:rw,cached
Full compose file
Here is the full docker-compose.yml
file:
version: '3.6'
services:
nginx:
image: nginx:latest
container_name: mywebsite-nginx
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx:/etc/nginx/conf.d
- ./src:/var/www/html:rw,cached
- ./certs:/etc/certs
depends_on:
- wordpress
restart: always
mysql:
image: mariadb
container_name: mywebsite-mysql
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=mywebsite
restart: always
ports:
- '3306:3306'
wordpress:
image: wordpress:php7.2-fpm
container_name: mywebsite-wordpress
volumes:
- ./src:/var/www/html:rw,cached
environment:
- WORDPRESS_DB_NAME=mywebsite
- WORDPRESS_TABLE_PREFIX=wp_
- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_PASSWORD=password
depends_on:
- mysql
restart: always
composer:
image: composer/composer
container_name: mywebsite-composer
working_dir: /var/www/html
restart: 'no'
volumes:
- ./src:/var/www/html:rw,cached
WordPress configuration
All our source code should be placed inside src
folder. Add an existing project or initialize a new Bedrock project.
Environment configuration
Edit .env
file and setup our credentials
DB_NAME=mywebsite
DB_USER=root
DB_HOST=mysql:3306
WP_HOME=https://mywebsite.local
DB_PASSWORD=password
WP_SITEURL=${WP_HOME}/wp
WP_ENV=development
...
Install extra packages and tools
Sometimes we need to use tools not installed in the standard Docker images. We can create our own Dockerfile, build it and use in Docker Compose.
Create a Dockerfile
in our project root. Extend the base image and add your own tools.
Example:
FROM wordpress:php7.2-fpm
# Install sockets for PHP
RUN docker-php-ext-install sockets
# Install wp-cli
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
RUN chmod +x wp-cli.phar
RUN mv wp-cli.phar /usr/local/bin/wp
In our docker-compose.yml
, modify the WordPress service a bit:
wordpress:
build:
context: .
dockerfile: Dockerfile
container_name: mywebsite-wordpress
...
When we make changes in our Dockerfile we can use
docker-compose up -d --force-recreate --build
to build our container again if we change something.
Install WordPress and plugins
Install new plugins with Composer, like this:
cd src
composer install
or
docker-compose run composer require wpackagist-plugin/wordpress-seo
Update WordPress and plugins
cd src
composer update
or
docker-compose run composer update
Create a new Bedrock project
If don’t have an existing composer.json
file you can initialize a Bedrock project like this:
docker-compose run composer create-project roots/bedrock .
Start
docker-compose up -d
You can now browse to https://mywebsite.local and see your WordPress installation dialog!
Useful Docker and Docker Compose Commands
List Docker containers
docker ps
List Docker images
docker image ls
List compose containers
docker-compose ps
Stop
docker-compose stop
Down (stop and remove)
docker-compose down
Cleanup
docker-compose rm -v
Summary
There you go 😊
We have created a modern local WordPress development environment with Docker Compose. Checkout my demo repo on Github.
Let me know if you have any questions!