Skip links

Automating WordPress Deployment with Docker Compose 04/2024

Introduction

WordPress is a free and open-source Content Management System (CMS) built on a MySQL database with PHP processing. Thanks to its extensible plugin architecture and templating system, most of its administration can be done through the web interface. This is a reason why WordPress is a popular choice when creating different types of websites, from blogs to product pages to eCommerce sites. However, setting up a new web host environment can be time-consuming especially if you need to do it often. Docker Compose manages to simplify the installation process to a single deployment command greatly reducing the time and effort required.

In this blog, I will build a multi-container WordPress testing installation. containers will include a MySQL database, an Nginx web server, Wp-cli , and WordPress itself.

Docker Compose

Let's start! For this localhost deployment, we're using a .env file as a convenient way to manage environment variables across multiple Docker Compose services or containers. we're also going to use wp-cli for automating the first installation of WordPress. in fact this site is developed and designed by me using WordPress!

# Database #
MYSQL_DATABASE=wordpress
MYSQL_ROOT_PASSWORD=devops
MYSQL_USER=wordpress
MYSQL_PASSWORD=devops

# Site Settings #
SITE_URL=localhost
SITE_TITLE=test
SITE_ADMIN_USER=test
SITE_ADMIN_PASSWORD=test
SITE_ADMIN_EMAIL=test@test.com

Let's break down the services We're using in the docker-compose.yml file

Mysql:

version: '3'

services:
  db:
    image: mysql:5.7
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    volumes: 
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network
Services

Content #1

Mysql
  • db: MySQL database service responsible for storing WordPress data.

WordPress:

  wordpress:
    build:
      context: ./docker/wordpress
    depends_on: 
      - db
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=${MYSQL_USER}
      - WORDPRESS_DB_PASSWORD=${MYSQL_PASSWORD}
      - WORDPRESS_DB_NAME=${MYSQL_DATABASE}
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network

WordPress Dockerfile:

FROM wordpress:6.3-fpm

RUN docker-php-ext-install mysqli pdo pdo_mysql
RUN apt-get update && apt-get install -y sendmail
COPY php.ini /opt
COPY php.ini /usr/local/etc/php/conf.d/php.ini
Services

Content #1

WordPress
  • wordpress: the wordpress offical php-fpm version.

WordPress service built from a custom Dockerfile located in the ./docker/wordpress directory.

WordPress php.ini file:

file_uploads = On
max_input_vars = 4000
upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 512M
max_execution_time = 1200
max_input_time = 600
allow_url_fopen = on
allow_url_include = on

Webserver:

  webserver:
    depends_on:
      - wordpress
    image: nginx:latest
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
    networks:
      - app-network
Services

Content #1

Webserver
  • webserver: Nginx service serving as a reverse proxy for the WordPress application.

Nginx Conf file:

server {
        listen 80;
        listen [::]:80;

        server_name localhost;

        index index.php index.html index.htm;

        root /var/www/html;
        client_max_body_size 100M;
        fastcgi_read_timeout 300;
        proxy_read_timeout 300;

        location ~ /.well-known/acme-challenge {
                allow all;
                root /var/www/html;
        }

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_path_info;
        }

        location ~ /\.ht {
                deny all;
        }
        
        location = /favicon.ico { 
                log_not_found off; access_log off; 
        }
        location = /robots.txt { 
                log_not_found off; access_log off; allow all; 
        }
        location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
                expires max;
                log_not_found off;
        }
}
listen

Defines the port to listen on. In this case, it's listening on port 80 for both IPv4 and IPv6 connections.

server_name
  • Specifies the hostname of the server. In this case, it's set to localhost.
index
  • Defines the default files to serve when a directory is requested.
root

Sets the root directory for serving files.

Php parameters

client_max_body_size: Sets the maximum allowed size of the client request body.

fastcgi_read_timeout: Defines the maximum time for reading a response from the FastCGI server.

proxy_read_timeout: Defines the maximum time for reading a response from the proxied

location

Defines rules for handling different URI patterns.

Wp-cli:

Wp-cli is a powerful tool for managing WordPress installations from the command line. It provides a wide range of commands to perform various tasks such as installing WordPress, managing plugins and themes, importing and exporting content, and interacting with the database.

  wp-cli:
    build:
      context: ./docker/wp-cli
    depends_on:
      - db
    container_name: wp-cli
    restart: "no"
    env_file: .env
    command: sleep infinity
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=${MYSQL_USER}
      - WORDPRESS_DB_PASSWORD=${MYSQL_PASSWORD}
      - WORDPRESS_DB_NAME=${MYSQL_DATABASE}
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network
Services

Content #1

WordPress
  • wp-cli: service for managing WordPress installations and configurations.

Entrypont bash script for automation wordpress first installation, managing plugins, themes.

#!/bin/bash

LOCK_FILE=/var/www/html/.wp_installed

if [ ! -f "$LOCK_FILE" ]; then
    # Run WordPress installation commands
    until mysqladmin ping -h"db" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" --silent; do
        echo "MySQL server is not ready yet..."
        sleep 2
    done
    wp core install --path=/var/www/html --url=${SITE_URL} --title=${SITE_TITLE} --admin_user=${SITE_ADMIN_USER} --admin_password=${SITE_ADMIN_PASSWORD} --admin_email=${SITE_ADMIN_EMAIL}
    wp rewrite structure '/%postname%/'
    wp user update ${SITE_ADMIN_USER} --admin_color=modern
    wp plugin install elementor --activate --path=/var/www/html
    wp plugin install woocommerce --activate --path=/var/www/html
    wp plugin install /opt/plugins/elementor-pro_3.18.2.zip --activate --path=/var/www/html
    wp theme install blocksy --activate
    wp plugin install all-in-one-wp-migration --activate --path=/var/www/html

    # Create a lock file to indicate that WordPress is installed
    touch "$LOCK_FILE"
fi

sleep infinity

Following this, it proceeds to install the requested plugins, themes, and activate them. In this instance, we are installing the "Blocksy" theme and ecommerce plugins for an ecommerce site. I have developed various wp-cli scripts tailored to different types of sites, including an LMS site (Learning Management System), Ecommerce, appointment, and others. This systematic approach enables me to automate site deployment, aligning precisely with my clients' requirements. Moreover, it significantly reduces the time spent manually searching for and activating each plugin, particularly beneficial when the WordPress site necessitates a substantial number of plugins.

The script starts by defining the path to a lock file (LOCK_FILE) located at /var/www/html/.wp_installed. This lock file serves as an indicator that WordPress has been installed. It then checks if the lock file exists. If it doesn't exist, it proceeds with the WordPress installation commands.

The script waits until the MySQL server is ready by continuously pinging it with the mysqladmin command. This ensures that the database is available before proceeding with the installation.

The script uses wp core install command to install WordPress with specified parameters from our .env file such as site URL, site title, admin username, password, and email.

It then updates the permalink structure using the wp rewrite structure command. Next, it updates the admin user's color scheme with wp user update command. for my favorite color sheme for the wordpress backend 🙂

This website uses cookies to improve your web experience.
View
Drag