Image alt

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: { }