Dockerizing WordPress with MariaDB and Nginx as Proxy: A Complete Guide

In the modern era of web development, containerization has become a game changer, allowing developers to package applications and their dependencies into isolated environments for consistent and replicable deployments. In this guide, we will explore the process of dockerizing a WordPress application using MariaDB as the database and Nginx as a reverse proxy. This setup will ensure high performance, security, and ease of maintenance.

Architecture Overview

The architecture consists of three primary services:

  1. MariaDB: A robust database management system that will store all WordPress data.
  2. WordPress: The content management system that powers the web application.
  3. Nginx: A lightweight and powerful web server that acts as a reverse proxy, managing HTTP requests and serving static files efficiently.

Prerequisites

Before diving into the deployment process, ensure you have the following installed on your local development machine:

  • Docker
  • Docker Compose

Project Structure

Create a project directory with the following structure:

your-project/
├── docker-compose.yml
└── nginx/
    ├── database/
    ├── html/
    ├── nginx-conf/
    └── ssl/  # For SSL certificates

Step 1: Create the Docker Compose File

Inside your project directory, create a docker-compose.yml file with the following content to define our services:

version: '3'
services:
  mysql:
    image: mariadb
    volumes:
      - ./nginx/database/mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: SECURE_PASSWORD
      MYSQL_DATABASE: wordpress
      MYSQL_USER: USERNAME
      MYSQL_PASSWORD: SECURE_PASSWORD
    restart: unless-stopped
    networks:
      - docker_network

  wordpress:
    image: wordpress:6.2-php8.0-fpm-alpine
    volumes:
      - ./nginx/html/:/usr/share/nginx/html
    depends_on:
      - mysql
    environment:
      WORDPRESS_DB_HOST: mysql
      MYSQL_ROOT_PASSWORD: SECURE_PASSWORD
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: USERNAME
      WORDPRESS_DB_PASSWORD: SECURE_PASSWORD
      WORDPRESS_TABLE_PREFIX: wp_
    networks:
      - docker_network
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx/nginx-conf:/etc/nginx/conf.d
      - ./nginx/html:/usr/share/nginx/html
      - ./nginx/ssl:/etc/ssl
    ports:
      - 80:80
      - 443:443
    networks:
      - docker_network
    restart: unless-stopped

networks:
  docker_network:
    driver: bridge

Explanation of the Docker Compose File

  • The mysql service uses the official MariaDB image and sets up the database with necessary credentials.
  • The wordpress service uses the official WordPress image and connects to the MariaDB instance.
  • The nginx service uses a lightweight Nginx image, exposing ports 80 and 443 for web traffic.

Step 2: Download WordPress

Navigate to your nginx/html directory and download the latest version of WordPress:

# Move to the HTML directory
cd your-project/nginx/html

# Download the latest version of WordPress
curl -O https://wordpress.org/latest.tar.gz

# Extract the WordPress files
tar -xvzf latest.tar.gz --strip-components=1

# Clean up the tar file
rm latest.tar.gz

Step 3: Create Nginx Configuration

Inside the nginx/nginx-conf directory, create a file named default.conf for your Nginx configuration:

mkdir -p your-project/nginx/nginx-conf
nano your-project/nginx/nginx-conf/default.conf

Copy the following generalized configuration for your domain:

# HTTP Configuration
server {
    listen 80;
    listen [::]:80;

    server_name yourdomain.com www.yourdomain.com;  # Change this to your domain

    location ~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html;  # Point to the web root directory where .well-known is stored
    }

    location / {
        rewrite ^ https://$host$request_uri? permanent;  # Redirect all HTTP traffic to HTTPS
    }
}

# HTTPS Configuration
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;  # Change this to your domain

    index index.php index.html index.htm;

    root /usr/share/nginx/html;  # Point to the web root directory where WordPress is installed

    server_tokens off;

    client_max_body_size 100M;  # Adjust as needed for uploads

    ssl_certificate /usr/share/nginx/ssl/yourdomain.com.fullchain.pem;  # Update with your certificate file
    ssl_certificate_key /usr/share/nginx/ssl/yourdomain.com.privkey.pem;  # Update with your private key

    # Security Headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' data: 'unsafe-eval' 'unsafe-inline';" always;

    # Handle WordPress URL Rewriting
    location / {
        try_files $uri $uri/ /index.php$is_args$args;  # Use WordPress's pretty permalinks
    }

    # Handle PHP Files
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass wordpress:9000;  # Ensure this points to your PHP-FPM service
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    # Deny access to .htaccess and .user.ini files
    location ~ /\.ht {
        deny all;
    }

    location ~ ^/\.user\.ini {
        deny all;
    }

    # Favicon and robots.txt settings
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        log_not_found off;
        access_log off;
        allow all;
    }

    # Cache static content
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }
}

Important Adjustments

  • Domain Name: Replace yourdomain.com with your actual domain in the server_name directives.
  • SSL Certificates: Ensure to provide the correct paths to your SSL certificate and key files.

Step 4: Running Your Application

Once you have set everything up, you can run the application with Docker:

  1. Navigate back to your project directory.
  2. Execute the following command to start the services:
docker-compose up -d
  1. Visit http://localhost or your domain in a web browser.

Step 5: Complete WordPress Installation

Upon visiting your site, you will encounter the WordPress installation wizard. Follow the instructions to set up your site title, username, password, and email.

Conclusion

By dockersing WordPress with MariaDB and Nginx, you achieve a powerful, scalable, and maintainable web environment. This setup simplifies the deployment process and allows you to easily manage updates and security configurations.

With your Dockerized WordPress site now live, feel free to customize it, install themes, and add plugins to suit your needs. Enjoy creating with WordPress in a containerized environment!

Troubleshooting: Migrating Your Docker Instance / Permission Errors

When migrating your Dockerized WordPress application from one computer to another, you may encounter file permission issues, especially if you are using a volume to persist your WordPress data. Here’s how to resolve these issues and ensure your application operates smoothly after the migration.

Step 1: Identify User IDs

Before you migrate your Docker containers, it’s essential to determine the user IDs that Nginx and WordPress run as. This ensures that the file permissions are set correctly in the new environment so that Nginx can serve WordPress files without permission issues.

  1. Access the WordPress Container: To find the user ID for both Nginx and WordPress, you will need to get into the WordPress container:
docker exec -it <wordpress_container_name> /bin/sh

Once inside, Check the running processes to see which user is running the app e.g. webserver:

ps aux

Check the user ID:

id www-data
  1. Repeat for Nginx: Similarly, access the Nginx container:
docker exec -it <nginx_container_name> /bin/sh

Again, check the user ID for www-data:

id www-data

Step 2: Change Ownership and Set Permissions

After identifying the appropriate user IDs, ensure that the ownership and permissions on your WordPress files are correct. This will help prevent issues with file uploads and other file operations.

  1. Set Ownership: While still inside the WordPress container, update the ownership of the html directory:
chown -R www-data:www-data /usr/share/nginx/html
  1. Set Directory Permissions: Set the correct permissions for directories and files within the html directory:
find /usr/share/nginx/html -type d -exec chmod 755 {} \;
find /usr/share/nginx/html -type f -exec chmod 644 {} \;

Step 3: Restart Containers

docker-compose down
docker-compose up -d

Step 4: Verify Your Setup

Check that your WordPress site functions correctly after migration:

  • Navigate to your website and ensure that pages load.
  • Test uploading files through the WordPress admin interface to confirm that permissions are correctly set.
0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x