Creating a WordPress Docker Image: A Step-by-Step Guide to Building Your Own Image

For my blog I wanted to create my own WordPress Docker image for it. In this article we will walk through creating a Dockerfile for building a WordPress image. We’ll break down each step, explaining the purpose and significance, so you can understand how to create your own WordPress Docker image. Whether you’re a seasoned developer or just getting started with Docker and WordPress, this guide will provide a clear roadmap.

In today’s software development landscape, Docker has become an indispensable tool for creating, deploying, and managing applications. Its containerization technology ensures consistency across different environments, simplifies deployments, and enhances scalability. For popular platforms like WordPress, Docker offers a fantastic way to streamline setup and management.

Let’s get started with creating our docker image for running WordPress.

Step 1. Choosing the Base Image

Choosing the right base image is crucial for creating an efficient and secure Docker image. For our WordPress image, we’ll start with Debian. Debian is a popular choice for servers because it’s renowned for its stability and security, meaning fewer unexpected issues and a more reliable foundation for your WordPress site.

We’ll be using the bookworm-slim variant of the official Debian image. “Bookworm” is the codename for the current stable release of Debian (version 12 at the time of writing). The -slim suffix indicates a minimized version of the image, containing only the essential packages to run Debian. This is a best practice in Docker: smaller images mean faster downloads, faster deployments, and a reduced attack surface.

So, the first line of our Dockerfile is:

FROM debian:bookworm-slim

Step 2. Updating the Packages

Next we want to make sure that our Docker image is up to date and that we are using the latest packages to ensure that we have the latest security patches and bug fixes. This minimizes vulnerabilities in your WordPress environment.

To achieve this, we’ll use the RUN instruction in our Dockerfile to execute commands within the image. Specifically, we’ll use apt, the package manager for Debian.

First we’ll run the command apt update refreshes the local package index. Think of it like updating the list of available software and their versions. It doesn’t actually install or upgrade anything; it just gets the latest information.

Next, we’ll run the command apt -y upgrade which installs the newest versions of all packages currently installed on the system. The -y flag automatically answers “yes” to any prompts during the upgrade process, allowing the build to proceed unattended, which is essential for automated image builds.

So we now add the following two lines to the Dockerfile.

RUN apt update
RUN apt -y upgrade

Step 3. Installing Supervisord: Managing Multiple Processes

WordPress, when served with NGINX, requires at least two main processes to be running: the NGINX web server itself and PHP-FPM (FastCGI Process Manager) to handle PHP requests. Docker containers are generally designed to run a single main process. To manage multiple processes effectively within a container, we will setup Supervisord.

Creating the Supervisord Configuration File

The first thing that we need to do is create a configuration file for it called supervisord.conf. Below is the contents of the supervisord.conf file to start the Nginx and Php-FPM processes.

[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0

[program:php-fpm]
command = /usr/sbin/php-fpm8.2 --force-stderr --nodaemonize
autostart=true
autorestart=true
priority=10
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
stopsignal=QUIT

[program:nginx]
command=/usr/sbin/nginx -g "daemon off; error_log /dev/stderr info;"
autostart=true
autorestart=true
priority=20
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
stopsignal=QUIT

[include]
files = /etc/supervisor/conf.d/*.conf

This supervisord.conf file is used to manage and run Nginx and PHP-FPM within a Docker container, ensuring both services start automatically and keep running. The [supervisord] section configures Supervisord, a process manager, to run in the foreground (nodaemon=true) and disables logging to files by directing logs to /dev/null. The [program:php-fpm] section defines the PHP-FPM process, specifying the command to run it, enabling automatic restarts, and directing logs to standard output and error streams for easier debugging in a containerized environment. Similarly, the [program:nginx] section configures Nginx to run in the foreground (daemon off), ensuring it stays active under Supervisord’s control. Both programs use stopsignal=QUIT, allowing them to shut down gracefully. Finally, the [include] section allows additional configuration files to be loaded dynamically from /etc/supervisor/conf.d/. This setup ensures Nginx and PHP-FPM are properly managed, automatically restarted if they fail, and their logs are accessible in Docker’s logging system.

Adding Supervisord to Your Docker Image

Next we’ll install Supervisord in the Docker Image using the following commands. The commands below install Supervisord using apt -y install supervisor, ensuring that it is available to manage multiple services within the container. A dedicated log directory (/var/log/supervisor) is created to store process logs, although in this setup, logging is redirected to standard output for better integration with Docker logs. Finally, the Supervisord configuration file (supervisord.conf) is copied into /etc/supervisor/conf.d/, defining how Nginx and PHP-FPM will be monitored and managed. This approach ensures both services start automatically, restart if they fail, and remain operational under Supervisord’s control, making the container more robust and reliable.

# Install Supervisord so that we can run multiple processes in the docker container
RUN apt -y install supervisor
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

Step 4. Installing NGIX, PHP-FPM and PHP Extensions

Next, we’ll install Nginx, PHP-FPM, and the necessary PHP extensions required for WordPress in the Docker image. As we are using a Debian base image we’ll use the apt command to install nginx php-fpm and the required php extensions.

We’ll add the lines below to the Dockerfile to install these components. The RUN apt -y install command is used to automate the installation of packages inside the container. The apt package manager is responsible for retrieving and installing software on Debian-based systems, and the -y flag automatically confirms the installation, preventing the need for manual user input. This ensures that Nginx, PHP 8.2-FPM, and the required PHP extensions are installed seamlessly during the image build process.

# Install NGINX
RUN apt -y install nginx
# Install PHP and the php-mysql package
RUN apt -y install php8.2-fpm php-mysql
# Install Additional PHP Extensions for wordpress
RUN apt -y install php-curl php-gd php-intl php-mbstring php-soap php-xml php-xmlrpc php-zip php-imagick php-dom php-exif php-igbinary php-mbstring

Step 5. Removing Default NGINX Site Configurations

By default, NGINX comes with a default site configuration. We want to use our own configuration specifically tailored for WordPress. Next we’ll add the following statements to the Dockerfile to remove the default configurations to prevent conflicts and ensure our custom configuration is the only one active.

# Remove the default site configuration files for nginx
RUN unlink /etc/nginx/sites-enabled/default
RUN rm -f /etc/nginx/sites-available/default

Step 6. Copying Custom NGINX Site Configuration

Next we need to setup the NGINX configuration in the Docker Image.

Creating a Configuration File for Nginx

In this step we need to configure Nginx. Create a file called nginx-site.conf in a folder called conf with the following contents. Replace your_domain with the domain for your website.

server {
    listen 80;
    server_name your_domain www.your_domain;
    root /var/www/wordpress;

    index index.html index.htm index.php;

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

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
     }

    location ~ /.ht {
        deny all;
    }

    location =https://alleria.karunsblog.com/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;
    }

}

This Nginx configuration file sets up a web server to serve a WordPress site. It listens on port 80 and defines the domain name while setting the root directory to /var/www/wordpress, where WordPress files are stored. The index directive ensures that index.php or HTML files are loaded as default pages. The main location / block routes requests, using try_files to ensure requests are properly handled by WordPress. The PHP processing block (location ~ .php$) configures Nginx to forward PHP requests to PHP-FPM via a Unix socket. Security rules are included to block access to hidden files (like .htaccess), and optimizations disable logs for certain static assets and files like favicon.ico and robots.txt. Additionally, caching rules are set for static content like images, CSS, and JavaScript, improving performance. This configuration ensures Nginx properly serves the WordPress site while optimizing speed and security.

Copying the Nginx Configuration File into the Docker Image

For the next step, we need to copy the configuration file into the Docker Image. To do this we add the following commands to the Dockerfile.

# Copy our NGINX Site Configuration File into the image
COPY --chown=www-data:www-data conf/nginx-site.conf /etc/nginx/sites-available/wordpress
RUN ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/wordpress

The COPY command transfers the custom Nginx site configuration file (nginx-site.conf) from the local conf directory into the container’s Nginx configuration directory (/etc/nginx/sites-available/wordpress). The --chown=www-data:www-data flag ensures that the file is owned by www-data, the user under which Nginx operates, preventing potential permission issues. The RUN ln -s command creates a symbolic link in /etc/nginx/sites-enabled/, enabling the WordPress site configuration. This approach follows standard Nginx best practices, allowing multiple site configurations while ensuring the correct one is activated. With this setup, Nginx knows how to serve the WordPress site when the container starts.

Step 7. Downloading and Installing WordPress

Next we’ll download and install WordPress in the Dockerfile.

# Download WordPress
RUN mkdir -p /var/www/wordpress
RUN apt install wget
RUN wget https://wordpress.org/wordpress-6.7.2.tar.gz -O /tmp/wordpress.tar.gz
RUN tar -zxvf /tmp/wordpress.tar.gz -C /var/www

# WordPress Setup
RUN chown -R www-data:www-data /var/www/wordpress

In this section of the Dockerfile, we are downloading and setting up WordPress inside the container. First, we create the necessary directory (/var/www/wordpress) to store the WordPress files. We then install wget, a command-line tool for downloading files, and use it to fetch the latest WordPress package (wordpress-6.7.2.tar.gz) from the official WordPress website. The downloaded archive is extracted into /var/www, making the WordPress files accessible. Finally, we change the ownership of the WordPress directory to www-data, the user that Nginx and PHP-FPM run as, ensuring proper file permissions. This setup ensures WordPress is correctly installed and ready to run inside the container.

Step 8. Making the Blog Accessible: Exposing Port 80

Now that we have our WordPress installation running with Nginx, we need to make it accessible from outside the container. Web servers, like Nginx, typically listen for connections on port 80 (the standard port for HTTP traffic).

To inform Docker that our container listens on port 80, we use the EXPOSE instruction in our Dockerfile and add the following statement to the Dockerfile:

EXPOSE 80

Step 9. Creating a Docker Volume for WordPress

In this step we want to make sure that the owner of the wordpress folder is set correctly and we also want to create a persistent docker volume for WordPress to use.

RUN chown -R www-data:www-data /var/www/wordpress

# Set up a volume for wordpress
VOLUME /var/www/wordpress

These commands ensure proper file permissions and enable persistent storage for the WordPress site inside the Docker container. The RUN chown -R www-data:www-data /var/www/html command recursively changes the ownership of the WordPress files to the www-data user, which is the default user for Nginx and PHP-FPM. This prevents permission issues when the web server tries to read or modify files. The VOLUME /var/www/wordpress directive creates a Docker volume, allowing the WordPress files to persist even if the container is stopped or removed. This setup ensures that any changes made to WordPress, such as theme updates or uploaded media, are not lost when the container restarts, improving the reliability and flexibility of the deployment.

Step 10. Specifying the Startup Command for the Docker Image

We’ll be using supervisord in the docker image. As we discussed earlier, Supervisord is managing NGINX and PHP-FPM. By making Supervisord the CMD, we ensure that when the container starts, Supervisord starts, and Supervisord in turn starts and manages NGINX and PHP-FPM, creating a fully functional WordPress environment.

We’ll add the command below to the Dockerfile. The CMD instruction specifies the default command to run when the Docker container starts. Here, it’s set to ["/usr/bin/supervisord"].

CMD ["/usr/bin/supervisord"]

Step 11. Final Dockerfile

After completing all the steps we have the following Dockerfile for our WordPress Docker image.

FROM debian:bookworm-slim
# Update the list of packages
RUN apt update
# Upgrade the packages
RUN apt -y upgrade

# Install Supervisord so that we can run multiple processes in the docker container
RUN apt -y install supervisor
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# Install NGINX
RUN apt -y install nginx
# Install PHP and the php-mysql package
RUN apt -y install php8.2-fpm php-mysql
# Install Additional PHP Extensions for wordpress
RUN apt -y install php-curl php-gd php-intl php-mbstring php-soap php-xml php-xmlrpc php-zip php-imagick php-dom php-exif php-igbinary php-mbstring

# Remove the default site configuration files for nginx
RUN unlink /etc/nginx/sites-enabled/default
RUN rm -f /etc/nginx/sites-available/default

# Copy our NGINX Site Configuration File into the image
COPY --chown=www-data:www-data conf/nginx-site.conf /etc/nginx/sites-available/wordpress
RUN ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/wordpress

# Download WordPress
RUN mkdir -p /var/www/wordpress
RUN apt install wget
RUN wget https://wordpress.org/wordpress-6.7.2.tar.gz -O /tmp/wordpress.tar.gz
RUN tar -zxvf /tmp/wordpress.tar.gz -C /var/www

# Expose port 80 for NGINX
EXPOSE 80

# WordPress Setup
RUN chown -R www-data:www-data /var/www/wordpress

# Set up a volume for wordpress
VOLUME /var/www/wordpress

CMD ["/usr/bin/supervisord"]

Step 12. Building the Docker Image

To build a docker image with the docker image name mywordpress-image run the following command:

docker build -t mywordpress-image .

Github Repository

All the files that were created as a part of this article are available in the following Github Repository: https://github.com/kdambiec/public-wordpress-docker-image

Leave a reply

Your email address will not be published. Required fields are marked *