How to Build a WordPress Environment Using Docker on Windows

When operating a website, server settings and database management can be a headache. Doing everything manually often leads to mistakes and can be very time-consuming. However, using Docker and a docker-compose.yml file, you can automate the entire setup process and simplify management.

With this single file, you can build and maintain a WordPress and MySQL environment, and even automate regular backups. There’s no need for complex command inputs or configuration changes for backups. This docker-compose.yml file is a powerful tool that ensures your site is built and maintained with just a few commands while keeping your data secure.

Here’s a summary of the convenient features offered by this WordPress environment:

  • Backup function for migration: Automatically backs up the database, allowing you to migrate or restore at any time.
  • Automatic WordPress core updates: Updates the core WordPress files to the latest version automatically when the container is restarted.
  • Data persistence: The wp-content directory and database are persisted on the host side, ensuring that customizations and content are retained even when the container is restarted or updated.
  • Automatic setup of Japanese WordPress: Automatically downloads and sets up the Japanese version of WordPress, making it easy to build a Japanese environment. The system also supports multiple languages, allowing users to automatically install and configure the desired language version based on their needs.
  • Easy-to-manage log function: The Apache logs are stored on the host, allowing you to easily access error logs and other information from outside the container.
  • Scheduled automatic backups: Automatically backs up the MySQL database daily, reducing the risk of losing important data. These backups are scheduled and saved regularly without the need for manual intervention.
  • Smooth container update process: Easily update WordPress and MySQL images, with the rebuilding process automated. The process from building to restarting the container is seamless, making it easy for beginners to keep their environment up to date.
  • Simple management of environment variables: The environment variables are straightforward to configure, allowing centralized management of WordPress and MySQL connection settings, with the flexibility to adjust the environment as needed.

The docker-compose.yml file we’ll introduce next is designed to deploy WordPress easily and automate database backups. It provides a reliable system that allows for simple recovery of your site and data during server migration.


Role and Placement of Four Files and php.ini

The four files and the php.ini file used in this project each play an important role. Placing them in the correct directories will enable you to efficiently build a WordPress environment. Below is the purpose of each file and how to arrange them. I created an appropriate directory in my home directory and placed them there.

The following is an ASCII art example illustrating the structure where there’s a youtube directory under the home directory, containing five files.

/home/username/
    └── youtube/
         ├── docker-compose.yml
         ├── Dockerfile
         ├── .env
         ├── php.ini
         └── entrypoint.sh

File Descriptions:

  • docker-compose.yml: A file that defines multiple containers, such as WordPress and MySQL.
  • Dockerfile: A file that defines the configuration and necessary packages inside the container.
  • .env: A file used to define environment variables (e.g., database username and password).
  • php.ini: The PHP configuration file (used to set upload limits, timezone, etc.).
  • entrypoint.sh: A script that runs when the container starts.

docker-compose.yml

  • Purpose: This file is used to manage multiple Docker containers (e.g., WordPress and MySQL) at once. It defines container settings, networks, volumes, and more.
  • Main Role: It automates the setup of the WordPress web server, database, and backup services, efficiently managing the entire environment.
  • Placement: Place this file in the root directory of the project, and start the environment using the command docker-compose up -d.

.env

  • Purpose: This file manages environment variables. It externalizes important settings, such as the database username, password, and name, making it easy to change settings while maintaining security.
  • Main Role: It simplifies environment settings and facilitates migration between different environments. By modifying the .env file, you can dynamically change the settings for each service.
  • Placement: Place this file in the same directory as docker-compose.yml.

Dockerfile

  • Purpose: This file is used to create a custom WordPress environment. It customizes the foundation for running WordPress, such as specific PHP settings and installing additional packages.
  • Main Role: It automatically builds a customized WordPress environment, simplifying the build process.
  • Placement: Place this file in the same directory as docker-compose.yml.

entrypoint.sh

  • Purpose: This script runs automatically when the container starts. It handles initial setup for WordPress, file copying, and database connection settings.
  • Main Role: It automates the initialization of the WordPress environment, ensuring the container starts properly. It also streamlines the process of configuring the database and copying files.
  • Placement: Place this file in the location referenced in the Dockerfile (e.g., /usr/local/sbin/entrypoint.sh). However, it can be placed in the same directory as the other three files without any issues. The reasoning is explained below.

1. Reference in the Dockerfile

In the Dockerfile, if you use the COPY or ADD command to copy entrypoint.sh into the container, as long as the file path on the host is specified correctly, it can be copied to the container regardless of its location.

For example, if the following is written in the Dockerfile, entrypoint.sh located in the host directory is copied to /usr/local/sbin/entrypoint.sh inside the container.

COPY entrypoint.sh /usr/local/sbin/entrypoint.sh
RUN chmod +x /usr/local/sbin/entrypoint.sh

With this setup, entrypoint.sh will be executed correctly when the container starts.


2. Specifying in docker-compose.yml

In docker-compose.yml, when building the Dockerfile, the build option specifies the context. This context refers to the directory where the Dockerfile exists (which is the same directory as docker-compose.yml). Because of this, files specified in the Dockerfile (such as entrypoint.sh) will be referenced from the same directory, ensuring they function correctly.

If the following configuration is set in docker-compose.yml, files specified in the Dockerfile will be handled properly.

services:
  wordpress:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: wordpress
    restart: unless-stopped
    volumes:
      - ./wordpress:/var/www/html

Here, context: . indicates that the directory where docker-compose.yml exists is specified as the build context.


3. File Placement and Reference Mechanism

Docker copies or mounts files from the host machine into the container. As long as entrypoint.sh is properly placed on the host and correctly referenced in both the Dockerfile and docker-compose.yml, it will work without any issues, regardless of which directory the file is in on the host.

By placing these files in an appropriate directory and executing the commands, you can easily set up a WordPress environment, with data management and backups automated.

Below is the content of docker-compose.yml, followed by a step-by-step explanation of each setting and configuration.

version: '3.7'

services:
  wordpress:
    build: 
      context: .
      dockerfile: Dockerfile
    container_name: wordpress
    restart: unless-stopped
    ports:
      - "8888:80"
    environment:
      - WORDPRESS_DB_HOST
      - WORDPRESS_DB_USER
      - WORDPRESS_DB_PASSWORD
      - WORDPRESS_DB_NAME
    volumes:
      - ./php.ini:/usr/local/etc/php/conf.d/php.ini
      - ./wordpress:/var/www/html  # Persist WordPress files on the host
      - ./logs/apache2:/var/log/apache2  # Mount log files externally

  db:
    image: mysql:latest
    container_name: wordpress-db
    restart: always
    environment:
      - MYSQL_DATABASE
      - MYSQL_USER
      - MYSQL_PASSWORD
      - MYSQL_ROOT_PASSWORD
    volumes:
      - ./db_data:/var/lib/mysql  # Persist MySQL data

  wpsql:
    image: mysql:latest
    container_name: wpsql
    depends_on:
      - db
    environment:
      MYSQL_HOST: db
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - ./backup:/backup  # Directory for backups
    command: >
      /bin/bash -c "
      while ! mysqladmin ping -h \"$$MYSQL_HOST\" --silent; do
        sleep 1;
      done;
      while true; do
        echo 'Starting backup...';
        MYSQL_PWD=$$MYSQL_PASSWORD mysqldump -h $$MYSQL_HOST -u $$MYSQL_USER ${MYSQL_DATABASE} > /backup/${MYSQL_DATABASE}_backup.sql;
        echo 'Backup complete.';
        sleep 86400;
      done"
    restart: on-failure

volumes:
  db_data: {}
  backup: {}  # Added volume for backups

1. WordPress Service

  • build: context: . indicates that a custom WordPress image will be built using the Dockerfile.
  • container_name: The container is named “wordpress” for easy identification.
  • ports: Maps host port 8888 to container port 80, allowing external web access.
  • environment: The database hostname, username, password, and database name are set as environment variables.
  • volumes:
    • Mounts ./php/php.ini to the PHP configuration file in the container, allowing you to customize PHP settings.
    • Mounts ./wordpress to /var/www/html, persisting WordPress files on the host.
    • Saves Apache logs externally by mounting ./logs/apache2.

2. Database Service (db)

  • image: Uses the latest MySQL image to provide the database service.
  • container_name: The database container is named “wordpress-db”.
  • volumes: Mounts ./db_data to the MySQL data directory, ensuring data persistence.

3. Backup Service (wpsql)

  • container_name: This container is named “wpsql” and is responsible for automatically backing up the MySQL database.
  • volumes: Saves database backups as .sql files in the ./backup directory.
  • command: The backup process runs daily, dumping the database every 86,400 seconds (24 hours) and storing the backup.

4. Volume Persistence

  • db_data: Persists the database data.
  • backup: Stores the database backups.

This docker-compose.yml file automatically sets up WordPress and MySQL and also takes care of backing up the database. By backing up the database in .sql format, migrations become much easier.


Contents and Explanation of the .env File:

# WordPress Configuration
WORDPRESS_DB_HOST=db
WORDPRESS_DB_USER=exampleuser
WORDPRESS_DB_PASSWORD=examplepass
WORDPRESS_DB_NAME=exampledb

# MySQL Configuration
MYSQL_DATABASE=exampledb
MYSQL_USER=exampleuser
MYSQL_PASSWORD=examplepass
MYSQL_ROOT_PASSWORD=rootpassword

The .env file is a crucial file used to externalize and manage the settings of the Docker environment. The information set in this file is referenced within docker-compose.yml, allowing the configuration of each service (WordPress, MySQL) to be handled dynamically.


1. WordPress Configuration

  • WORDPRESS_DB_HOST=db
    • Explanation: Specifies the hostname of the database that WordPress will connect to. Here, the database service name db is used as the hostname.
  • WORDPRESS_DB_USER=exampleuser
    • Explanation: The username that WordPress will use to access the database. In this case, the user is set as exampleuser.
  • WORDPRESS_DB_PASSWORD=examplepass
    • Explanation: The password that WordPress will use to access the database. Here, the password is set as examplepass.
  • WORDPRESS_DB_NAME=exampledb
    • Explanation: Specifies the name of the database that WordPress will use. Here, the database is named exampledb.

2. MySQL Configuration

  • MYSQL_DATABASE=exampledb
    • Explanation: The name of the MySQL database that will be created. WordPress will store its data in this database.
  • MYSQL_USER=exampleuser
    • Explanation: The MySQL username that will access the database. It is set as exampleuser.
  • MYSQL_PASSWORD=examplepass
    • Explanation: The password for the MySQL user. This password secures access to the database.
  • MYSQL_ROOT_PASSWORD=rootpassword
    • Explanation: The password for the MySQL root (administrator) user, used for overall database management.

Role of the .env File:

By using this .env file, you can manage important information such as the database name, username, and password in a single place, making it easy to modify settings depending on different environments.


Next, I’ll provide the translation and explanation for the contents of the Dockerfile.

FROM wordpress:latest

# Set UID and GID to match the host environment
ARG UID=1000
ARG GID=1000

RUN usermod -u ${UID} www-data && groupmod -g ${GID} www-data

# Create /var/log/apache2 and set permissions
RUN mkdir -p /var/log/apache2 && chown -R www-data:www-data /var/log/apache2

# Create html directory and set ownership
RUN mkdir -p /var/www/html && chown -R www-data:www-data /var/www/html

# Install necessary packages
RUN apt-get update && apt-get install -y \
    mariadb-client \
    wget \
    unzip \
    rsync \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Set entrypoint.sh
COPY entrypoint.sh /usr/local/sbin/entrypoint.sh
RUN chmod +x /usr/local/sbin/entrypoint.sh

# Add ServerName
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf

ENTRYPOINT ["/usr/local/sbin/entrypoint.sh"]

Dockerfile is a configuration file used to create a custom WordPress environment. It contains commands, packages, and settings necessary to properly run WordPress. Below is an explanation of each part.


FROM wordpress

  • Explanation: This specifies the base Docker image. It uses wordpress:latest to build the environment based on the latest WordPress image.

# Set UID and GID to match the host environment

ARG UID=1000
ARG GID=1000
RUN usermod -u ${UID} www-data && groupmod -g ${GID} www-data
  • Explanation: This section sets the user ID (UID) and group ID (GID) of the www-data user and group inside the container to match the host environment. This prevents issues with file permissions and ownership by aligning the IDs with those of the host system. This means you don’t need to manually change ownership on the host.

# Create /var/log/apache2 and set permissions

RUN mkdir -p /var/log/apache2 && chown -R www-data:www-data /var/log/apache2
  • Explanation: This creates the directory /var/log/apache2 where Apache logs will be saved and sets its ownership to the www-data user. This ensures that Apache can correctly output its logs.

# Create the html directory and set ownership

RUN mkdir -p /var/www/html && chown -R www-data:www-data /var/www/html
  • Explanation: This creates the directory /var/www/html, where WordPress HTML files will be stored, and sets its ownership to the www-data user. This ensures that WordPress can operate on these files without permission issues.

Installing and Optimizing Necessary Packages

RUN apt-get update && apt-get install -y \
mariadb-client \
wget \
unzip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

1. Package Installation

  • Explanation: Installs necessary packages such as the MariaDB client, wget, and unzip. These packages are required for proper operation, including the ability to connect WordPress to MySQL, download files, and unzip them.

2. apt-get clean

  • Explanation: Clears out the package manager’s cached files to avoid leaving unnecessary package files on the disk.
  • Purpose: Reduces the size of the Docker image, helping to maintain a lightweight and efficient setup. This is a key step for ensuring efficient operation.

3. rm -rf /var/lib/apt/lists/*

  • Explanation: Deletes the package lists (index files) maintained by apt-get after installation.
  • Purpose: Since these lists are no longer needed after the installation, deleting them further reduces the image size for more efficient operation.

Why This is Important

A smaller Docker image is more efficient for deployment and transfer. Removing unnecessary files provides the following benefits:

  • Reduced image size: By removing caches and lists, the image becomes smaller, reducing disk usage and improving transfer times during deployment.
  • Improved performance: A smaller image results in faster container startup and downloads, ensuring smoother operation.

This command is crucial for cleaning up the system and enhancing efficiency.


# Set entrypoint.sh

COPY entrypoint.sh /usr/local/sbin/entrypoint.sh
RUN chmod +x /usr/local/sbin/entrypoint.sh
  • Explanation: Copies the entrypoint.sh script from the host to the container’s /usr/local/sbin/entrypoint.sh and grants execute permissions. This script plays a key role in automatically setting up WordPress during container startup.

# Add ServerName

RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
  • Explanation: Adds ServerName localhost to Apache’s configuration file to avoid warnings related to the server name.

ENTRYPOINT [“/usr/local/sbin/entrypoint.sh”]

  • Explanation: Specifies the script that will run when the container starts. In this case, entrypoint.sh is executed, which handles WordPress setup and initialization.

This Dockerfile correctly builds a WordPress and MySQL environment and installs the necessary packages and permissions. It is particularly notable for using entrypoint.sh to automatically perform initial setup when the container starts.


Next, I’ll provide the translation and explanation for the contents of entrypoint.sh.

#!/bin/bash
set -e

echo "Starting entrypoint.sh script..."

# Set permissions for the HTML directory
echo "Setting permissions for the html directory..."
chown -R www-data:www-data /var/www/html || { echo "Failed to set permissions"; exit 1; }
chmod -R 755 /var/www/html || { echo "Failed to change permissions"; exit 1; }

# If wp-config.php does not exist, copy the WordPress files
if [ ! -f /var/www/html/wp-config.php ]; then
  echo "wp-config.php does not exist. Copying WordPress files for the first time."
  cp -rv /usr/src/wordpress/* /var/www/html/ || { echo "Failed to copy files"; exit 1; }

  # Rename wp-config-sample.php to wp-config.php
  if [ -f /var/www/html/wp-config-sample.php ]; then
    echo "Renaming wp-config-sample.php to wp-config.php."
    mv /var/www/html/wp-config-sample.php /var/www/html/wp-config.php || { echo "Failed to rename file"; exit 1; }
  fi
fi

# Download and extract Japanese version of WordPress
if [ ! -d /var/www/html/wp-content/languages ]; then
  echo "Downloading Japanese version of WordPress..."
  if ! wget https://ja.wordpress.org/latest-ja.zip -O /tmp/latest-ja.zip; then
    echo "Failed to download"
    exit 1
  fi
  echo "Extracting Japanese version of WordPress..."
  if ! unzip /tmp/latest-ja.zip -d /tmp/wordpress-ja; then
    echo "Failed to extract"
    exit 1
  fi
  
  echo "Copying Japanese WordPress files..."
  cp -rv /tmp/wordpress-ja/wordpress/* /var/www/html/ || { echo "Failed to copy files"; exit 1; }
fi

# Update the WordPress core files to the latest version
echo "Updating WordPress core files..."
if ! wget https://ja.wordpress.org/latest-ja.zip -O /tmp/latest-ja.zip; then
  echo "Failed to download WordPress core files"
  exit 1
fi
if ! unzip -o /tmp/latest-ja.zip -d /tmp/wordpress-ja; then
  echo "Failed to extract WordPress core files"
  exit 1
fi

# Copy core files while excluding the wp-content directory
rsync -a --exclude 'wp-content' /tmp/wordpress-ja/wordpress/ /var/www/html/ || { echo "Failed to copy WordPress core files"; exit 1; }

# Apply environment variables to wp-config.php
if [ -f /var/www/html/wp-config.php ]; then
  echo "Applying environment variables to wp-config.php."
  sed -i "s/database_name_here/${WORDPRESS_DB_NAME}/" /var/www/html/wp-config.php
  sed -i "s/username_here/${WORDPRESS_DB_USER}/" /var/www/html/wp-config.php
  sed -i "s/password_here/${WORDPRESS_DB_PASSWORD}/" /var/www/html/wp-config.php
  sed -i "s/localhost/${WORDPRESS_DB_HOST}/" /var/www/html/wp-config.php
fi

echo "Contents of /var/www/html:"
ls -la /var/www/html

echo "Exiting entrypoint.sh script."

exec apache2-foreground

entrypoint.sh is a script that runs automatically when the container starts, and it simplifies the initial setup of WordPress and database connection. This script is mainly used to handle permission settings, file copying, and WordPress environment configuration automatically. Below is an explanation of each section. The update of WordPress core files will be explained later.


#!/bin/bash
set -e
  • Explanation: At the beginning of the script, set -e is used. This ensures that if any error occurs in the script, execution stops immediately. This prevents errors from being overlooked and ensures the script runs safely.

echo "Starting entrypoint.sh script..."
  • Explanation: A message indicating the start of the script. It is logged to help track the script’s execution status.

Setting Permissions for the HTML Directory

echo "Setting permissions for the html directory..."
chown -R www-data:www-data /var/www/html || { echo "Failed to set permissions"; exit 1; }
chmod -R 755 /var/www/html || { echo "Failed to change permissions"; exit 1; }
  • Explanation: This sets the owner and group of the /var/www/html directory to www-data and grants appropriate file permissions. This ensures that WordPress can operate correctly with the required file access permissions.

Copying WordPress Files if wp-config.php Does Not Exist

if [ ! -f /var/www/html/wp-config.php ]; then
echo "wp-config.php does not exist. Copying WordPress files for the first time."
cp -rv /usr/src/wordpress/* /var/www/html/ || { echo "Failed to copy files"; exit 1; }

# Rename wp-config-sample.php to wp-config.php
if [ -f /var/www/html/wp-config-sample.php ]; then
echo "Renaming wp-config-sample.php to wp-config.php."
mv /var/www/html/wp-config-sample.php /var/www/html/wp-config.php || { echo "Failed to rename file"; exit 1; }
fi
fi
  • Explanation: If wp-config.php does not exist, it copies the initial WordPress configuration files and renames wp-config-sample.php to wp-config.php. This generates the configuration file required for WordPress to run for the first time.

Downloading and Extracting the Japanese Version of WordPress

if [ ! -d /var/www/html/wp-content/languages ]; then
echo "Downloading Japanese version of WordPress..."
if ! wget https://ja.wordpress.org/latest-ja.zip -O /tmp/latest-ja.zip; then
echo "Failed to download"
exit 1
fi
echo "Extracting Japanese version of WordPress..."
if ! unzip /tmp/latest-ja.zip -d /tmp/wordpress-ja; then
echo "Failed to extract"
exit 1
fi

echo "Copying Japanese WordPress files..."
cp -rv /tmp/wordpress-ja/wordpress/* /var/www/html/ || { echo "Failed to copy files"; exit 1; }
fi

Applying Environment Variables to wp-config.php

if [ -f /var/www/html/wp-config.php ]; then
echo "Applying environment variables to wp-config.php."
sed -i "s/database_name_here/${WORDPRESS_DB_NAME}/" /var/www/html/wp-config.php
sed -i "s/username_here/${WORDPRESS_DB_USER}/" /var/www/html/wp-config.php
sed -i "s/password_here/${WORDPRESS_DB_PASSWORD}/" /var/www/html/wp-config.php
sed -i "s/localhost/${WORDPRESS_DB_HOST}/" /var/www/html/wp-config.php
fi
  • Explanation: This applies environment variables, defined in .env or elsewhere, to the wp-config.php file. This dynamically sets the database connection information, ensuring WordPress operates correctly.

echo "Contents of /var/www/html:"
ls -la /var/www/html
  • Explanation: Displays a list of files and directories in /var/www/html to verify that the files have been copied correctly.

echo "Exiting entrypoint.sh script."
exec apache2-foreground
  • Explanation: A message indicating the script has completed successfully. Then, Apache is started in the foreground, launching the web server.

entrypoint.sh Script Summary

The entrypoint.sh script automates the initial setup of WordPress, including copying files, configuring database connections, and setting up file permissions. This makes the initialization process fast and eliminates the need for manual setup.


PHP.ini Configuration and Placement

When setting up a WordPress environment, it is important to have a php.ini file, which controls key PHP settings. The php.ini file should be placed in the same directory as docker-compose.yml and Dockerfile, as mentioned earlier, making it easy to manage and reflect configuration changes immediately.


1. Example of php.ini

Below is a basic example of a php.ini configuration. The settings for post_max_size, upload_max_filesize, and date.timezone are particularly important as they affect file uploads and date/time handling. In this article’s example, the following values have been adjusted to handle larger themes:

; File upload limits
post_max_size = 64M
upload_max_filesize = 200M

; Timezone setting
date.timezone = "Asia/Tokyo"
  • post_max_size: Specifies the maximum amount of data that can be sent in a POST request, such as file uploads. Here it is set to 64MB, but you can adjust this value as needed.
  • upload_max_filesize: Defines the maximum size of a file that can be uploaded. If you need to handle large files, increase this value.
  • date.timezone: Sets the timezone used by PHP. In this case, it is set to Asia/Tokyo, but you can change it to your region (e.g., America/New_York for the US).

2. Customizing Settings for Your Environment

PHP settings vary depending on the environment. Adjust the values for post_max_size, upload_max_filesize, and date.timezone to suit your working environment or project requirements.

  • File upload limits: If large file uploads are required, increase upload_max_filesize.
  • Timezone: Ensure that the PHP timezone matches your server’s timezone for accurate date/time handling.

3. Mounting the php.ini File in docker-compose.yml

To ensure that the php.ini file is properly reflected in the container, it is mounted as shown in the previous docker-compose.yml example:

services:
wordpress:
volumes:
- ./php.ini:/usr/local/etc/php/conf.d/php.ini # Mount the php.ini file

With this configuration, the settings from php.ini are used inside the container and are immediately applied.


How to Start the Docker Container

Here is an easy-to-follow guide for beginners on how to set up a WordPress environment with Docker. By following these steps, you’ll be able to get WordPress running quickly.

1. What You’ll Need

  • A computer with Docker and Docker Compose installed.
  • The docker-compose.yml file (this defines the WordPress environment).
  • The php.ini file (PHP configuration file).
  • Dockerfile
  • entrypoint.sh
  • .env

2. Step 1: Verify the Docker Compose Configuration File

First, check the docker-compose.yml file. This file contains settings for WordPress, MySQL, and more. It will be used to start the containers. The content of docker-compose.yml is the same as the one shown above and should work without any issues.

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8888:80"
    volumes:
      - ./php.ini:/usr/local/etc/php/conf.d/php.ini
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword

Step 2: Starting the Containers

Using Docker Compose to start the containers is very simple. You only need to run two commands.


Building the Container Image

Open a terminal or command prompt and navigate to the directory where the docker-compose.yml file is located. Then, execute the following command:

docker-compose build

What Happens?

When this command is executed, Docker will create the necessary containers (WordPress and MySQL). After waiting for a while, the containers will be ready.

The command docker compose build builds the image based on the build section defined in the docker-compose.yml file, using the specified Dockerfile. For example, if the following is specified:

services:
wordpress:
build:
context: .
dockerfile: Dockerfile
  • context: .: Specifies the context directory for the build (usually the directory where the Dockerfile is located). Files and directories in the context are referenced during the image build process.
  • dockerfile: Dockerfile: Specifies the Dockerfile used for the build. This Dockerfile defines how the container’s contents will be constructed.

The image is built step by step according to the instructions in the Dockerfile. Each instruction (e.g., FROM, RUN, COPY) is built as a separate layer, and each layer is cached.

For example:

  • FROM wordpress: Uses the latest WordPress image as the base.
  • RUN apt-get update && apt-get install: Installs necessary packages.
  • COPY entrypoint.sh: Copies a file from the host to the container.

Using Cache in the Build Process

During the build process, caching is used. If the same step was built previously, Docker uses the cached result instead of executing the step again, speeding up the build process. However, if you want to skip the cache and rebuild all steps, you can use the --no-cache option:

docker compose build --no-cache

The build process applies to all services defined in the docker-compose.yml file. For example, if the file includes both a WordPress service and a MySQL service, each will be built separately.


Once the Build is Complete

When the build finishes, a new Docker image is created locally. This image can be launched as a container using the docker compose up command. In other words, the docker compose build command constructs the image according to the Dockerfile’s instructions and saves it locally, preparing the image to be run later with the docker compose up command.


Starting the Container

After the build is complete, run the following command:

docker-compose up -d

What Happens?

This command launches the WordPress and MySQL environments in the background. Once the environment is up and running, you can access the WordPress setup page by opening your browser and navigating to http://localhost:8888.

Step 3: Verifying the Containers

To check if the containers are running correctly, run the following command:

docker ps

This command displays a list of currently running containers, allowing you to verify that the WordPress and MySQL containers are operational.

Step 4: Stopping the Containers

To stop the containers, run the following command:

docker-compose down
  • All containers will be stopped: All containers defined in the docker-compose.yml file will be stopped.
  • Containers will be removed: The stopped containers will be removed from the system.
  • Network removal: Any custom networks created by docker-compose.yml will also be deleted (if the network was automatically created).

Optionally Removing Volumes

If you specify docker compose down --volumes, the data volumes that have been persisted with the containers will also be deleted.

However, the image itself is not deleted, so the containers can be restarted with docker compose up the next time.


Important Notes on Volume Removal

If you use docker compose down --volumes, the volumes are deleted, which means the data in the mounted volumes will also be deleted.

Specifically:


1. If the Directory is Mounted on the Host

For example, if a directory like ./db_data:/var/lib/mysql is mounted on the host side, running docker compose down --volumes will not delete the data in the ./db_data directory on the host.

While the volume itself is deleted, the data on the host remains, so it can be reused when the container is restarted.


2. If Only the Volume is Used

If the data is persisted purely in a Docker volume (without being mounted to a host directory), running docker compose down --volumes will delete the volume, and the data in the database will also be deleted.

In this case, the data will not remain when the container is restarted, meaning the data will be lost.


Clarifying the Optional Volume Removal in Step 5

Running docker compose down --volumes deletes the Docker-managed storage volumes. These “volumes” refer to Docker’s internal storage areas.

However, when a directory is mounted on the host, the data is directly stored on the host’s file system. In such cases, even if the container or volume is deleted, the data on the host is not deleted.


Example Comparison:

Here’s a clearer explanation of how the two scenarios differ:

1. When Mounting a Directory on the Host (./db_data:/var/lib/mysql)

services:
  db:
    volumes:
      - ./db_data:/var/lib/mysql

In this case, the ./db_data directory on the host is mounted to /var/lib/mysql inside the container. This means that the database data is saved in the host’s directory.

Since the data is saved on the host directory, even if the container or volume is deleted, the data remains on the host.

Even if you run docker compose down --volumes, the data on the host (./db_data directory) will not be deleted.


2. When Using Docker’s Internal Volume (db_data:/var/lib/mysql)

services:
  db:
    volumes:
      - db_data:/var/lib/mysql
volumes:
  db_data:

In this case, the Docker-managed volume (db_data) is mounted to /var/lib/mysql inside the container. The database data is stored in the Docker-managed volume, not in the host directory.

Since the data is not stored on the host file system, it is only saved in Docker’s internal volume.

If you run docker compose down --volumes, the volume is deleted, and the database data is completely erased.


Simple Summary:

  • ./db_data:/var/lib/mysql (Stored on the host):
    • The data is stored on the host’s ./db_data directory, so even if the container or volume is deleted, the data remains.
    • Running docker compose down --volumes will not delete the data on the host.
  • db_data:/var/lib/mysql (Stored in Docker’s volume):
    • The data is stored in Docker’s internal volume db_data, so running docker compose down --volumes will delete both the volume and the data.
    • When the container is restarted, the data will be gone and cannot be recovered.

Conclusion:

If you want to store the data on the host, you should use a setting like ./db_data:/var/lib/mysql to mount the host directory.

Be cautious when managing data with only Docker volumes, as running docker compose down --volumes will erase the data.


To summarize, docker compose down stops and deletes the containers, removes the network, but does not delete the image.

With these steps, you can easily set up a WordPress environment using Docker. By simply running the commands, you can quickly try WordPress in your own environment.

Managing the containers is straightforward, as you can start them with docker-compose up and stop them with docker-compose down, making it easy and accessible even for beginners.

Will the Data Be Reset When the Container is Restarted?


1. Basic Understanding

Although Docker containers run as temporary environments, if properly configured, the data will not be lost when the container is restarted. For example, even if the container is stopped and then restarted, the posts and theme settings will remain intact.


2. Why Isn’t the Data Lost?

The reason the data isn’t reset is due to data persistence. In the docker-compose.yml file, WordPress files and the database data are saved on the host, meaning the data is retained even when the container is restarted.

volumes:
- ./wordpress:/var/www/html # Persist WordPress files on the host
- ./db_data:/var/lib/mysql # Persist MySQL data on the host
  • ./wordpress: This directory stores WordPress themes and post data. Since it is saved on the host, it remains intact even if the container is restarted.
  • ./db_data: This directory stores the MySQL database data. Since it is also saved on the host, there is no risk of losing posts or other data. Even running the docker compose down --volumes command will not delete it.

3. Example: Behavior When Restarting the Container

Even if the container is stopped and restarted, the data remains as follows:

  • Stopping the container:
    docker-compose down
  • Restarting the container:
    docker-compose up -d

In this process, the data stored on the host is automatically remounted to the container, so the previous state is preserved. Any theme changes or posts will remain unchanged.


4. Cases Where Data May Be Reset

If the data is reset, the following issues might be the cause:

  • Incorrect volume settings: If the volumes for saving data to the host are not properly set in docker-compose.yml, the data will not be retained, and it may be reset after a restart.
  • Host directory deleted: If the data stored on the host is deleted for any reason, the data may be reset when the container restarts.

By ensuring that data is saved on the host, there is no concern about data being reset when restarting Docker containers. With proper volume settings in the docker-compose.yml file, changes to posts or themes will remain intact, allowing you to confidently restart the container.


How to Apply the Latest WordPress State on Subsequent Restarts


1. Automatic Updates with entrypoint.sh

By adding a script to entrypoint.sh, WordPress core files are automatically updated to the latest version each time the container is restarted. This script updates everything except the wp-content directory, ensuring that theme and plugin customizations are preserved while only the core files are updated automatically when the container is restarted.

# Update WordPress core files to the latest version
echo "Updating WordPress core files..."
wget https://ja.wordpress.org/latest-ja.zip -O /tmp/latest-ja.zip
unzip -o /tmp/latest-ja.zip -d /tmp/wordpress-ja

# Overwrite everything except the wp-content directory
rsync -a --exclude 'wp-content' /tmp/wordpress-ja/wordpress/ /var/www/html/
  • Advantages: WordPress core files are automatically updated to the latest version simply by restarting the container, eliminating the need to manually download and copy files.
  • Protection of the wp-content Directory: Customized themes and plugins are not affected, as they are excluded from the update process.

2. Using docker pull and Rebuilding

By using docker pull to get the latest WordPress image and then restarting the container with docker-compose up, the new image will be applied. This allows you to use the latest version of WordPress, but files mounted on the host (such as /var/www/html and wp-content) are retained.

  • Advantages: Not only WordPress but also other container services like MySQL may be updated to the latest versions, resulting in an overall system update.
  • Important Note: Even after running docker pull, WordPress files, themes, and plugins mounted on the host will not be overwritten. You will still need to use a script like entrypoint.sh to update the core files.

Automatic Updates (Recommended)

Using entrypoint.sh, you can automatically update the WordPress core files when the container restarts. Themes and plugins in the wp-content directory are preserved and remain unaffected.


Manual Updates

If you choose not to use automatic updates, you can manually copy the latest version of WordPress files to the host to perform the update.

1. Updating the Docker Image

Using the docker pull command, you can fetch the latest WordPress image from Docker Hub or a private repository. This updates the image stored locally to the latest version. However, there are a few points to keep in mind:

  • New WordPress Version: The new image contains the latest WordPress core files, so when you restart the container with docker-compose up, this new image will be used.

2. Impact on Files Mounted on the Host

Files and directories mounted on the host through the docker-compose.yml file are not overwritten when the image is updated. Here’s how it works:

  • /var/www/html Directory: If this directory is mounted on the host, even after updating the image with docker pull, the files on the host are preserved. Therefore, the update to WordPress core files is not automatically reflected in the files on the host.
  • wp-content Directory: This directory, where themes, plugins, and uploaded images are stored, is persisted on the host. As a result, running docker pull does not change it, and customizations and settings are retained.

3. Behavior of entrypoint.sh (Automatic WordPress Core Updates)

The script added to entrypoint.sh automatically updates the WordPress core files to the latest version every time the container is restarted. The key point is that the wp-content directory is excluded from the update, so theme and plugin customizations are not lost.

# Update WordPress core files to the latest version
echo "Updating WordPress core files..."
wget https://ja.wordpress.org/latest-ja.zip -O /tmp/latest-ja.zip
unzip -o /tmp/latest-ja.zip -d /tmp/wordpress-ja

# Overwrite everything except the wp-content directory
rsync -a --exclude 'wp-content' /tmp/wordpress-ja/wordpress/ /var/www/html/
  • Protection of the wp-content Directory: This script uses rsync to overwrite everything except the wp-content directory. The important thing is that customized files such as themes and plugins are safely retained.

4. How to Apply the Latest WordPress Core Files

There are two ways to apply the latest WordPress core files:

  • Automatic Update (Recommended): The script added to entrypoint.sh automatically fetches and applies the latest WordPress core files when the container restarts. This removes the need to manually copy the files.
  • Manual Update: You can manually copy the latest WordPress files to the ./wordpress directory on the host and overwrite them as needed. However, be careful to preserve the wp-content directory.

Since the files mounted on the host are retained even after running docker pull, the themes, posts, and plugin settings will not be lost.

To reflect the latest WordPress core files, it is recommended to use the script added to entrypoint.sh for automatic updates.

The entrypoint.sh script runs every time the container restarts, ensuring that WordPress core files are always up to date without affecting theme or plugin customizations.

Steps to Perform Regularly


1. Fetch the Latest Version of the Docker Images

To regularly update the WordPress and MySQL images to the latest versions, run the following commands:

docker pull wordpress
docker pull mysql

2. Stop the Containers

After updating the images, stop the containers:

docker compose down

3. When Rebuild is Necessary

A rebuild is necessary under the following conditions:

  • If the Dockerfile is edited: For example, when adding new packages or changing settings within the Dockerfile.
  • If entrypoint.sh or configuration files are edited: For instance, if you modify the WordPress auto-update script or change PHP settings.

In such cases, rebuild without using the cache by running the following command:

docker compose build --no-cache

4. Restart the Containers

After rebuilding the image or simply restarting the container, start the containers in the background with the following command:

docker compose up -d

Summary of Regular Steps:

  • Use docker pull to get the latest images and then stop the containers with docker compose down.
  • If files or settings have been modified, rebuild the containers with docker compose build --no-cache.
  • If no changes were made, simply restart the containers with docker compose up -d.

Issues with File Mounting and Directory Creation in Docker

When trying to mount files in Docker, if the file does not exist on the host, a directory is created instead of the file. This is due to Docker’s default behavior, and appropriate countermeasures are needed. Below, I’ll explain the reasons and solutions for this issue.


1. Difference Between File and Directory Mounting

  • Directory Mounting: When mounting a directory in Docker, if the directory does not exist on the host, Docker automatically creates the directory.
  • File Mounting: On the other hand, when attempting to mount a file, if the file does not exist on the host, Docker creates a directory instead of a file. This behavior can lead to unexpected results.

2. Conditions Under Which the Problem Occurs

This issue occurs in the following scenarios:

  • File Does Not Exist on the Host: For example, when there is a file mount setting in docker-compose.yml, and the file does not exist on the host, Docker creates a directory at that location instead of the file.yamlコードをコピーするvolumes: - ./php/php.ini:/usr/local/etc/php/conf.d/php.ini If ./php/php.ini does not exist on the host, Docker creates a directory called php.ini on the host.
  • File Expected in the Container: While the container expects php.ini to be a file, a directory is mounted instead, causing unexpected behavior in the container.

3. Cause of the Issue

The cause of this issue lies in Docker’s default behavior. When a file intended for mounting does not exist on the host, Docker automatically creates a directory. Therefore, it is crucial to create the file on the host beforehand.


4. Solutions

To avoid this issue, the following measures are effective:

  • Create the File on the Host in Advance: By creating the file on the host beforehand, you can prevent Docker from mistakenly creating a directory. For example, you should prepare the php.ini file on the host from the beginning.
  • Check File Existence in entrypoint.sh: Another effective solution is to add a check in your script to see if the file exists on the host, and create a dummy file if necessary.

When mounting files in Docker, the mount might not behave as expected if the file doesn’t exist on the host, causing Docker to create a directory instead. To prevent this, it is important to prepare the files you intend to mount on the host beforehand. This is especially important for configuration files like php.ini, as having them on the host from the start ensures stable behavior from Docker.


Why Default Language Settings May Differ with the Same WordPress Image

Even when using the same WordPress Docker image, the default language settings may vary. This can be due to the following factors:


Possible Causes

  • Differences in Environment Variables: When using docker run, Japanese locale may be set automatically, but when using docker-compose, the default language settings may differ if environment variables are not properly configured in docker-compose.yml.
  • Impact of Themes or Plugins: The theme or plugins being used may influence language settings. Some themes or plugins may default to English.
  • Internet Connection Differences: WordPress automatically downloads necessary translation files via the internet during the initial installation. If the internet connection is unstable or restricted, this download may fail, causing the default display to be in English.

Overwriting wp-includes and wp-admin Directories

Overwriting the wp-includes and wp-admin directories is generally safe. These directories contain files related to WordPress core functionality, and users rarely need to customize them directly.


Roles of Each Directory

  • wp-includes: Contains libraries and scripts that provide the internal functionality of WordPress. These files support essential WordPress functions.
  • wp-admin: Contains files related to the WordPress admin dashboard, supporting the display and operation of administrative functions.

Reason for Overwriting

These directories contain core files that should be updated when WordPress is upgraded. Overwriting them during the installation of a new version of WordPress applies the latest features and security patches.


Directories to Be Cautious About

  • wp-content: This directory contains themes, plugins, and user-uploaded files. Since it holds custom settings and content, care must be taken to avoid overwriting it.

Conclusion

Overwriting wp-includes and wp-admin, which contain WordPress core functionality, is safe and should be done when updating to the latest version. However, be careful not to overwrite the wp-content directory, which contains themes, plugins, and user-uploaded files.

By distinguishing between files that should and should not be overwritten when updating or configuring WordPress, you can safely maintain an up-to-date WordPress environment.

Why Is a Separate Container Needed? (Regularly Saving the Database as a .sql File)

Simply using a mounted database can make data migration and restoration a bit complicated. Below, I’ll explain the specific reasons and the advantages of using a backup container.


Why Migrating a Mounted Database Is Difficult:


Complexity of Direct Data Handling:

While mounted data is saved in the host’s ./db_data directory, simply copying this directory is not sufficient for migrating the database.

Since database binary files depend on the specific MySQL version and settings, migrating them to a different environment can be challenging.


MySQL Version and Configuration Compatibility:

When migrating between different servers or MySQL versions, there can be compatibility issues with the binary data.

Because of this, there is a risk that a simple file copy may not successfully migrate the data.


Ensuring Data Consistency Is Difficult:

When migrating the data of a running database, the database often needs to be temporarily stopped to ensure data consistency.

Especially for large databases, copying files while the database is running can result in incomplete data migration.


Advantages of Using a Backup Container:


Ease of Migration:

  • .sql files are MySQL’s standard export format, making them highly compatible when importing into other MySQL instances. This allows for smooth migration to different environments or servers.
  • Even when MySQL versions or configurations differ, migrating with a .sql file is highly reliable.

Simple Backup and Restoration:

  • By regularly backing up the database as a .sql file, you can easily restore the data whenever necessary.
  • Additionally, like a snapshot, you can maintain a specific point-in-time version of the data, making it easy to revert to a previous state if an issue arises.

Cross-Environment Flexibility:

  • .sql files are text-based database dumps, making them easy to migrate to other servers or local environments.
  • Even when migrating data between different server environments, .sql files offer flexibility and reliability.

Conclusion:

While a mounted database allows for real-time data storage, it is more convenient to regularly back up the database in .sql format to facilitate easy migration and restoration. Using a backup container increases data integrity and reduces risks during migration.


If You Want to Connect to the Database via Command Line

To connect to a MySQL container running in Docker from an external source, you typically use the following command. If the MySQL container’s port is correctly exposed in the docker-compose.yml file, external connections will be allowed.


Connecting to the MySQL Container from the Host Machine

To connect to the MySQL container from the host machine, use the following command:

mysql -u root -p -h 127.0.0.1 -P 3306
  • -u root: Specifies the MySQL username. Here, the default root user is used.
  • -p: Prompts you to enter the password.
  • -h 127.0.0.1: Specifies the host’s IP address. Normally, when connecting from the host machine to the container, 127.0.0.1 (the loopback address) is used.
  • -P 3306: Specifies the MySQL port number. By default, MySQL uses port 3306.

Why External Connections Are Enabled

In a MySQL container running in Docker, if the port is exposed in the docker-compose.yml file, external connections are enabled by default. Unlike a regular MySQL server, there is no need to manually modify the bind-address setting, making it easy to allow external connections. Use the password set in the environment variable MYSQL_ROOT_PASSWORD.

For example, the following docker-compose.yml configuration exposes MySQL’s port:

services:
db:
image: mysql:latest
ports:
- "3306:3306"

This configuration maps port 3306 on the host machine to port 3306 in the MySQL container, allowing external connections.


Accessing from Another PC

If you want to connect to the MySQL server on the Docker container from another PC, you need to specify the IP address of the host machine instead of 127.0.0.1 (localhost). For example, if the host machine’s IP address is 192.168.1.100, you would connect using the following command:

mysql -u root -p -h 192.168.1.100 -P 3306

In this case, 192.168.1.100 is the host machine’s IP address within the local network. Using this IP address, you can connect to the MySQL container on the host from another PC.


Important Notes

  • When connecting from another PC, make sure that port 3306 is open in the host machine’s firewall settings.
  • Additionally, if the ports are not properly exposed in docker-compose.yml, the connection from other PCs might be blocked. Ensure that port mapping is correctly set up as shown below:
ports:
- "3306:3306"
https://github.com/superdoccimo/wpbk