• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Dockerizing and Orchestrating Legacy WooCommerce Systems on Modern Linode Infrastructure

Dockerizing and Orchestrating Legacy WooCommerce Systems on Modern Linode Infrastructure

Assessing the Legacy WooCommerce Monolith

Before embarking on containerization, a thorough assessment of the existing WooCommerce installation is paramount. This involves identifying dependencies, database schemas, file system structures, and any custom plugins or themes that might pose challenges in a containerized environment. Legacy systems often have implicit dependencies on specific PHP versions, extensions, or even operating system-level libraries. Documenting these is the first step to a successful migration.

Key areas to scrutinize:

  • PHP version and required extensions (e.g., gd, imagick, mysqli, curl, mbstring).
  • Web server configuration (Apache or Nginx) and any custom rewrite rules.
  • Database version and specific configurations (e.g., character set, collation).
  • File permissions and ownership for the WordPress/WooCommerce directory.
  • Any external services or APIs the store relies on.
  • Custom code, plugins, and themes – these are often the most complex to containerize.

Crafting the Dockerfile for WooCommerce

We’ll start with a robust base image and layer our WooCommerce installation on top. For this example, we’ll use an official PHP image with Apache, as many legacy setups are Apache-centric. We’ll also include common PHP extensions required by WordPress and WooCommerce.

Create a file named Dockerfile in your project’s root directory:

# Use an official PHP image with Apache
FROM php:8.1-apache

# Install necessary PHP extensions and system packages
RUN apt-get update && apt-get install -y \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libwebp-dev \
    unzip \
    git \
    && docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-install zip \
    && docker-php-ext-install pdo_mysql \
    && docker-php-ext-install mysqli \
    && docker-php-ext-install curl \
    && docker-php-ext-install mbstring \
    && docker-php-ext-install exif \
    && a2enmod rewrite \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Set working directory
WORKDIR /var/www/html

# Copy WordPress and WooCommerce files
# Assuming you have a 'wordpress' directory in the same location as your Dockerfile
COPY wordpress/ .

# Copy custom Apache configuration if needed
# COPY apache/000-default.conf /etc/apache2/sites-available/000-default.conf

# Ensure correct permissions for Apache to write to the web root
RUN chown -R www-data:www-data /var/www/html && chmod -R 755 /var/www/html

# Download and install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Install WordPress/WooCommerce dependencies if using Composer for plugins/themes
# If your legacy setup doesn't use Composer, this step might be skipped or adapted.
# COPY composer.json composer.lock ./
# RUN composer install --no-dev --optimize-autoloader

# Expose port 80
EXPOSE 80

# Start Apache in the foreground
CMD ["apache2-foreground"]

Explanation:

  • We start with a PHP 8.1 Apache image. Adjust the PHP version if your legacy system requires an older one (e.g., php:7.4-apache).
  • Essential system packages and PHP extensions are installed. The gd extension is configured with freetype, jpeg, and webp support, crucial for image manipulation in WooCommerce.
  • a2enmod rewrite enables Apache’s rewrite module, necessary for WordPress permalinks.
  • The working directory is set to Apache’s default web root.
  • We copy the WordPress and WooCommerce files. It’s highly recommended to have your entire WordPress installation (including plugins and themes) in a local directory named wordpress alongside your Dockerfile.
  • Permissions are set for the Apache user (www-data) to write to the web root.
  • Composer is installed globally, useful for managing PHP dependencies. If your legacy setup relies heavily on Composer for plugins or custom code, uncomment and adapt the Composer installation steps.
  • Port 80 is exposed.
  • apache2-foreground ensures Apache runs in the foreground, which is standard for Docker containers.

Database Containerization and Configuration

A separate container for the database is essential for a robust, scalable setup. We’ll use the official MySQL image. For legacy systems, ensuring compatibility with the existing database version is critical. If your legacy system uses an older MySQL version, consider using a specific tag (e.g., mysql:5.7).

For local development and testing, a docker-compose.yml file is invaluable. This file defines and links our services (WooCommerce app and database).

version: '3.8'

services:
  db:
    image: mysql:8.0 # Or your legacy MySQL version, e.g., mysql:5.7
    container_name: woocommerce_db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password # Change this!
      MYSQL_DATABASE: woocommerce_db
      MYSQL_USER: woocommerce_user
      MYSQL_PASSWORD: woocommerce_password # Change this!
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
      - ./mysql/initdb.d:/docker-entrypoint-initdb.d # For custom initialization scripts

  wordpress:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: woocommerce_app
    restart: always
    ports:
      - "8080:80" # Map host port 8080 to container port 80
    depends_on:
      - db
    environment:
      WORDPRESS_DB_HOST: db:3306 # Service name 'db' is the hostname
      WORDPRESS_DB_NAME: woocommerce_db
      WORDPRESS_DB_USER: woocommerce_user
      WORDPRESS_DB_PASSWORD: woocommerce_password # Must match db service password
    volumes:
      - ./wordpress:/var/www/html # Mount your local wordpress directory for development
      # For production, consider named volumes for better performance and persistence
      # - woocommerce_files:/var/www/html

volumes:
  db_data:
  # woocommerce_files: # Uncomment if using named volume for app files

Database Initialization (Optional but Recommended):

To ensure correct character sets and collations, especially if your legacy database uses specific settings, create a directory named mysql/initdb.d in your project root and place SQL files there. For example, mysql/initdb.d/01-init.sql:

-- Set character set and collation for the database
CREATE DATABASE IF NOT EXISTS woocommerce_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Grant privileges to the user
GRANT ALL PRIVILEGES ON woocommerce_db.* TO 'woocommerce_user'@'%';
FLUSH PRIVILEGES;

Explanation:

  • We define two services: db (MySQL) and wordpress (our WooCommerce app).
  • The db service uses a MySQL image, sets root and database credentials, and maps port 3306. A named volume db_data is used for persistent database storage. The docker-entrypoint-initdb.d directory allows custom SQL scripts to run on first container startup.
  • The wordpress service builds from our Dockerfile. It depends on the db service, ensuring the database is available before the app starts.
  • Environment variables are used to pass database connection details to WordPress. Crucially, WORDPRESS_DB_HOST is set to the service name db, which Docker’s internal DNS resolves to the database container’s IP.
  • For development, we mount the local ./wordpress directory into the container. For production, consider using named volumes (e.g., woocommerce_files) for better performance and management.
  • The application port 80 is mapped to host port 8080 to avoid conflicts with any existing web server on the host.

Building and Running the Containers

Navigate to your project’s root directory (where Dockerfile and docker-compose.yml reside) in your terminal.

Build the Docker images:

docker-compose build

Start the containers in detached mode:

docker-compose up -d

You can check the logs for each service:

docker-compose logs -f wordpress
docker-compose logs -f db

Once the containers are running, you should be able to access your WooCommerce store at http://localhost:8080 (or the IP address of your Linode instance if deploying there directly). The initial WordPress setup wizard will guide you through the final steps.

Migrating Data to Linode Infrastructure

For production deployment on Linode, you’ll typically use a managed Kubernetes service (like Linode Kubernetes Engine) or deploy directly onto Linode Compute Instances with Docker Compose. The principles remain similar, but orchestration becomes more critical.

Database Migration:

  • Backup existing database: Use mysqldump to create a full backup of your current WooCommerce database.
  • Transfer backup: Securely transfer the backup file to your Linode instance.
  • Import into containerized DB: If using Docker Compose on a Linode instance, you can exec into the running database container and import the dump, or use the initdb.d mechanism with a pre-compressed dump. For managed databases (like Linode’s Managed Databases), follow their import procedures.
# On your Linode instance with Docker Compose running
# Assuming your dump file is named 'wp_backup.sql.gz'
docker exec -i woocommerce_db sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' < wp_backup.sql.gz

File Migration:

The wp-content/uploads directory is the most critical for file migration. Use rsync to efficiently transfer these files to the persistent volume designated for your WordPress application on Linode.

# On your Linode instance, assuming you've configured persistent volumes
# and your local uploads are in 'local_wp_content/uploads'
rsync -avzP local_wp_content/uploads/ /var/lib/docker/volumes/woocommerce_files/_data/wp-content/uploads/

Orchestration with Docker Compose on Linode

For a single Linode Compute Instance, deploying with docker-compose is straightforward. Ensure your docker-compose.yml is configured for production:

  • Use named volumes for database and application files for better persistence and management.
  • Consider using a reverse proxy (like Nginx or Traefik) as a separate container to handle SSL termination, load balancing (if you scale horizontally), and routing requests to your WooCommerce container.
  • Secure your database credentials and root passwords. Use environment variables injected securely, not hardcoded.

Example docker-compose.yml for Production (simplified):

version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: woocommerce_db_prod
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # Use .env file
      MYSQL_DATABASE: woocommerce_db
      MYSQL_USER: woocommerce_user
      MYSQL_PASSWORD: ${MYSQL_PASSWORD} # Use .env file
    volumes:
      - db_data_prod:/var/lib/mysql

  wordpress:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: woocommerce_app_prod
    restart: always
    ports:
      - "80:80" # Map to host port 80 for direct access or reverse proxy
    depends_on:
      - db
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: woocommerce_db
      WORDPRESS_DB_USER: woocommerce_user
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} # Match db service password
    volumes:
      - woocommerce_files_prod:/var/www/html # Use named volume

volumes:
  db_data_prod:
  woocommerce_files_prod:

Create a .env file in the same directory as your docker-compose.yml to store sensitive credentials:

MYSQL_ROOT_PASSWORD=your_super_secret_root_password
MYSQL_PASSWORD=your_super_secret_db_password

Then, deploy using:

docker-compose -f docker-compose.yml up -d

Advanced Considerations: Linode Kubernetes Engine (LKE)

For true scalability and resilience, orchestrating with Kubernetes on Linode Kubernetes Engine (LKE) is the next step. This involves defining Kubernetes manifests (Deployments, Services, PersistentVolumeClaims, Secrets).

Key Kubernetes Objects:

  • Deployment: Manages the WooCommerce application pods, ensuring a desired number of replicas are running.
  • StatefulSet: Often preferred for databases to guarantee stable network identifiers, persistent storage, and ordered deployment/scaling.
  • Service: Provides stable IP addresses and DNS names for accessing your database and application pods. An Ingress controller will manage external access to the WooCommerce service.
  • PersistentVolumeClaim (PVC): Requests storage from Linode’s block storage for your database and WooCommerce files.
  • Secret: Stores sensitive information like database credentials.

Your Dockerfile remains the same. You would then create Kubernetes YAML files. For instance, a simplified WooCommerce Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: woocommerce-app
  labels:
    app: woocommerce
spec:
  replicas: 3 # Scale as needed
  selector:
    matchLabels:
      app: woocommerce
  template:
    metadata:
      labels:
        app: woocommerce
    spec:
      containers:
      - name: woocommerce
        image: your-docker-registry/woocommerce:latest # Push your image here
        ports:
        - containerPort: 80
        env:
        - name: WORDPRESS_DB_HOST
          value: "mysql-service:3306" # Service name for your DB
        - name: WORDPRESS_DB_NAME
          valueFrom:
            secretKeyRef:
              name: woocommerce-secrets
              key: db-name
        - name: WORDPRESS_DB_USER
          valueFrom:
            secretKeyRef:
              name: woocommerce-secrets
              key: db-user
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: woocommerce-secrets
              key: db-password
        volumeMounts:
        - name: woocommerce-persistent-storage
          mountPath: /var/www/html # Or your specific WordPress root
      volumes:
      - name: woocommerce-persistent-storage
        persistentVolumeClaim:
          claimName: woocommerce-pvc

You would also define a corresponding StatefulSet for your MySQL database, a Service for internal communication, a PersistentVolumeClaim for storage, and a Secret for credentials. An Ingress resource would then expose your WooCommerce application to the internet, often with SSL termination handled by a cloud controller (like Nginx Ingress Controller).

This approach provides high availability, automatic scaling, and robust management for your legacy WooCommerce system on modern cloud infrastructure.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Step-by-Step: Diagnosing indexing lock conflicts and high CPU during bulk stock updates on DigitalOcean Servers
  • How to Debug and Fix memory leaks and socket exhaustion in daemon processes in Modern C++ Applications
  • Infrastructure as Code: Provisioning Secure PHP Clusters on DigitalOcean Using Terraform
  • Fixing Slow Largest Contentful Paint (LCP) caused by unoptimized database queries in Legacy Laravel Codebases Without Breaking API Contracts
  • An Auditor’s Checklist for Securing Laravel Backends on Google Cloud

Copyright © 2026 · Vinay Vengala