Dockerizing and Orchestrating Legacy WooCommerce Systems on Modern DigitalOcean Infrastructure
Assessing Legacy WooCommerce Dependencies
Before embarking on containerization, a thorough audit of the existing WooCommerce installation is paramount. Legacy systems often harbor implicit dependencies on specific PHP versions, extensions, and even operating system-level libraries that are not immediately obvious. A common pitfall is assuming a direct 1:1 mapping of the current environment to a container. We must identify:
- PHP version and required extensions (e.g.,
mysqli,gd,imagick,zip,intl,mbstring). - Web server configuration (Apache or Nginx) and any custom rewrite rules or directives.
- Database version and specific configurations (e.g., character set, collation, storage engine).
- External service integrations (payment gateways, shipping APIs, CRM hooks) and their communication protocols.
- File system permissions and ownership requirements for uploads, cache, and logs.
Tools like phpinfo(), coupled with manual inspection of wp-config.php, theme/plugin code, and server logs, are essential. For a more automated approach, consider a simple PHP script to list loaded extensions and their versions:
<?php phpinfo(); ?>
Additionally, a script to check for common WooCommerce-required extensions:
<?php
$required_extensions = [
'mysqli', 'gd', 'imagick', 'zip', 'intl', 'mbstring', 'curl', 'openssl', 'dom', 'simplexml', 'xml', 'json', 'session', 'ctype', 'filter', 'hash', 'iconv', 'libxml', 'pcre', 'SPL', 'standard', 'tokenizer', 'zlib'
];
echo "<h2>PHP Extension Check</h2>";
echo "<ul>";
foreach ($required_extensions as $extension) {
if (extension_loaded($extension)) {
echo "<li style='color: green;'>" . htmlspecialchars($extension) . " (Loaded)</li>";
} else {
echo "<li style='color: red;'>" . htmlspecialchars($extension) . " (NOT LOADED)</li>";
}
}
echo "</ul>";
echo "<h2>PHP Version</h2>";
echo phpversion();
?>
Crafting the Dockerfile for WooCommerce
The core of our containerization strategy lies in a robust Dockerfile. We’ll opt for an official PHP image as a base, layering on Nginx for serving static assets and PHP-FPM for processing dynamic requests. This separation is crucial for performance and scalability.
A typical Dockerfile might look like this:
# Use an official PHP image with Apache/Nginx and extensions
# Example: PHP 8.1 with FPM and common extensions
FROM php:8.1-fpm
# Set working directory
WORKDIR /var/www/html
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
unzip \
libzip-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libwebp-dev \
libicu-dev \
libxslt1-dev \
libonig-dev \
libxml2-dev \
libssl-dev \
libcurl4-openssl-dev \
libjpeg62-turbo-dev \
libpng-dev \
libwebp-dev \
libfreetype6-dev \
libzip-dev \
libxslt1-dev \
libonig-dev \
libxml2-dev \
libssl-dev \
libcurl4-openssl-dev \
&& rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install -j$(nproc) zip \
&& docker-php-ext-install -j$(nproc) intl \
&& docker-php-ext-install -j$(nproc) opcache \
&& docker-php-ext-install -j$(nproc) pdo_mysql \
&& docker-php-ext-install -j$(nproc) sockets \
&& docker-php-ext-enable xdebug # Only for development
# Install Imagick (if needed and available)
RUN apt-get update && apt-get install -y libmagickwand-dev --no-install-recommends \
&& pecl install imagick \
&& docker-php-ext-enable imagick \
&& rm -rf /var/lib/apt/lists/*
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Copy WooCommerce and plugins (or manage via Composer)
# For simplicity, we'll copy them here. In production, consider Composer for dependencies.
COPY ./wordpress/ /var/www/html/
COPY ./wp-content/plugins/ /var/www/html/wp-content/plugins/
COPY ./wp-content/themes/ /var/www/html/wp-content/themes/
# Configure PHP-FPM
COPY docker/php-fpm/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf
# Expose port 9000 for PHP-FPM
EXPOSE 9000
# Command to run PHP-FPM
CMD ["php-fpm"]
The zz-docker.conf file is crucial for tuning PHP-FPM for a containerized environment:
; /usr/local/etc/php-fpm.d/zz-docker.conf ; Adjust settings for Docker environment [global] ; Use 'ondemand' or 'dynamic' for better resource utilization in containers ; 'static' can be useful for predictable load but might waste resources. ; For WooCommerce, 'dynamic' is often a good balance. pm = dynamic pm.max_children = 10 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 5 pm.max_requests = 500 ; Restart workers to clear memory leaks ; Increase memory limit for WooCommerce operations memory_limit = 512M ; Increase post_max_size and upload_max_filesize for media uploads post_max_size = 64M upload_max_filesize = 64M ; Set appropriate user/group for file permissions user = www-data group = www-data ; Set error reporting for debugging (adjust for production) error_reporting = E_ALL display_errors = Off log_level = notice ; log_errors = On ; error_log = /var/log/php-fpm/error.log ; Set timezone date.timezone = UTC
Nginx Configuration for Serving WooCommerce
A separate Nginx container will handle incoming HTTP requests, serve static assets, and proxy dynamic requests to the PHP-FPM container. This decouples web serving from PHP processing.
Here’s a sample Nginx configuration for a WooCommerce site:
# /etc/nginx/conf.d/default.conf
# Serve static files directly
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public";
access_log off;
try_files $uri $uri/ =404;
}
# PHP-FPM configuration
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-fpm:9000; # 'php-fpm' is the service name in docker-compose
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# WooCommerce specific optimizations
fastcgi_read_timeout 300; # Increase timeout for long operations
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
}
# Deny access to sensitive files
location ~ /\.ht {
deny all;
}
# WordPress permalinks
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
# add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"; # CSP can be complex, tune carefully
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
# Disable access to wp-config.php
location ~* wp-config\.php {
deny 127.0.0.1;
deny ::1;
deny all;
}
Database Containerization (MySQL/MariaDB)
A dedicated database container is essential. We’ll use an official MySQL or MariaDB image. Persistent storage for the database is critical, achieved through Docker volumes.
# docker-compose.yml snippet for database
services:
db:
image: mariadb:10.6 # Or mysql:8.0
container_name: woocommerce_db
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # Use .env file for secrets
MYSQL_DATABASE: woocommerce_db
MYSQL_USER: woocommerce_user
MYSQL_PASSWORD: ${MYSQL_PASSWORD} # Use .env file for secrets
ports:
- "3306:3306" # Expose only if direct access is needed, otherwise omit for security
networks:
- woocommerce_network
volumes:
db_data:
Ensure your .env file contains the necessary credentials:
# .env file MYSQL_ROOT_PASSWORD=your_super_secret_root_password MYSQL_PASSWORD=your_woocommerce_db_password
Orchestration with Docker Compose
docker-compose.yml is the orchestrator, defining the services, networks, and volumes for our WooCommerce stack. We’ll define at least three services: Nginx, PHP-FPM, and the database.
# docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:stable-alpine
container_name: woocommerce_nginx
ports:
- "80:80"
- "443:443" # If using SSL
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d # Mount custom Nginx config
- ./certs:/etc/nginx/certs # Mount SSL certificates if used
- ./wordpress:/var/www/html # Mount WordPress files (or use a named volume)
- ./logs/nginx:/var/log/nginx # Mount Nginx logs
depends_on:
- php-fpm
restart: always
networks:
- woocommerce_network
php-fpm:
build:
context: . # Path to your Dockerfile
dockerfile: Dockerfile
container_name: woocommerce_php_fpm
volumes:
- ./wordpress:/var/www/html # Mount WordPress files (or use a named volume)
- ./logs/php-fpm:/var/log/php-fpm # Mount PHP-FPM logs
expose:
- "9000" # Expose PHP-FPM port internally
depends_on:
- db
restart: always
networks:
- woocommerce_network
db:
image: mariadb:10.6
container_name: woocommerce_db
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: woocommerce_db
MYSQL_USER: woocommerce_user
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
networks:
- woocommerce_network
networks:
woocommerce_network:
driver: bridge
volumes:
db_data:
To build and run the containers:
# Create .env file with your database credentials cp .env.example .env # If you have a template # Build and start services docker-compose up -d --build # View logs docker-compose logs -f # Stop services docker-compose down
DigitalOcean Infrastructure Setup
On DigitalOcean, we can leverage Droplets to host our Docker environment. For production, consider a managed Kubernetes service (DOKS) for enhanced scalability and resilience, but for a direct Docker Compose deployment, a robust Droplet is sufficient.
- Droplet Configuration: Choose a Droplet size with adequate CPU and RAM. For a moderately trafficked WooCommerce site, a 4GB RAM / 2 vCPU Droplet is a good starting point. Ensure you select a recent Ubuntu LTS version (e.g., 22.04).
- Docker Installation: SSH into your Droplet and install Docker and Docker Compose.
# Update package list
sudo apt-get update
# Install Docker CE
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# Add your user to the docker group to run commands without sudo
sudo usermod -aG docker $USER
newgrp docker # Apply group changes
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# Verify installation
docker --version
docker-compose --version
Deployment Workflow:
- Clone your application code (including Dockerfiles and docker-compose.yml) to the Droplet.
- Ensure your
.envfile is correctly configured on the server. - Run
docker-compose up -d --buildto deploy. - Configure DNS to point your domain to the Droplet’s IP address.
- Set up a firewall (e.g., UFW) to allow HTTP/HTTPS traffic.
# Example UFW configuration sudo ufw allow 'Nginx Full' sudo ufw allow OpenSSH sudo ufw enable
Scaling and High Availability Considerations
For true scalability and high availability, Docker Compose on a single Droplet is insufficient. The next steps involve moving to a container orchestration platform like Kubernetes (DigitalOcean Kubernetes Service – DOKS).
- Horizontal Scaling: DOKS allows you to scale your Nginx and PHP-FPM deployments independently by increasing the number of pods.
- Load Balancing: DOKS integrates with DigitalOcean’s Load Balancers to distribute traffic across your Nginx pods.
- Persistent Storage: Utilize DigitalOcean Block Storage or Spaces for persistent volumes for your database and potentially WordPress uploads.
- Database HA: For critical applications, consider managed database services (like DigitalOcean Managed Databases) or advanced Kubernetes database operators for replication and failover.
- CI/CD Integration: Automate your build, test, and deployment pipeline using tools like GitLab CI, GitHub Actions, or Jenkins, pushing container images to a registry (e.g., Docker Hub, DigitalOcean Container Registry).
Transitioning from Docker Compose to Kubernetes involves rewriting your docker-compose.yml into Kubernetes manifests (Deployments, Services, Ingress, PersistentVolumeClaims). This is a significant architectural shift but necessary for robust, scalable cloud-native applications.