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

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Orchestrating High-Availability WordPress with Docker Swarm and AWS: A Deep Dive into Microservices Architecture

Orchestrating High-Availability WordPress with Docker Swarm and AWS: A Deep Dive into Microservices Architecture

Decoupling WordPress Components with Docker Swarm

Achieving true high availability for WordPress necessitates moving beyond monolithic deployments. We’ll architect a solution using Docker Swarm, orchestrating distinct WordPress components as microservices. This approach enhances scalability, resilience, and maintainability. Our core services will include:

  • WordPress Application (PHP-FPM & Nginx)
  • MySQL Database (with replication)
  • Redis Cache
  • Object Storage (e.g., MinIO for local testing, AWS S3 for production)
  • Optional: Elasticsearch for search

We begin by defining our Docker Compose file, which will serve as the blueprint for our Swarm services. This file outlines the services, networks, and volumes required for our WordPress deployment.

Docker Compose for Swarm

This docker-compose.yml defines the core services. Note the use of Swarm-specific configurations like deploy for scaling and rolling updates, and networks for inter-service communication.

version: '3.8'

services:
  db:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    networks:
      - wp-network
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.role == manager

  redis:
    image: redis:alpine
    networks:
      - wp-network
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure

  wordpress:
    build:
      context: ./wordpress
      dockerfile: Dockerfile
    ports:
      - "80:80"
    volumes:
      - wp_content:/var/www/html/wp-content
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
      WORDPRESS_DB_NAME: wordpress
      REDIS_HOST: redis
      REDIS_PORT: 6379
    networks:
      - wp-network
    depends_on:
      - db
      - redis
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure

  minio:
    image: minio/minio
    ports:
      - "9000:9000"
    volumes:
      - minio_data:/data
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
    command: server /data --console-address ":9001"
    networks:
      - wp-network
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

volumes:
  db_data:
  wp_content:
  minio_data:

networks:
  wp-network:
    driver: overlay
    attachable: true

Building the WordPress Microservice

The WordPress application itself is a composite service, typically comprising Nginx as the web server and PHP-FPM for script execution. We’ll create a custom Dockerfile to bundle these components and configure them for optimal performance and security within the Swarm environment.

WordPress Dockerfile

This Dockerfile sets up a lean Nginx and PHP-FPM environment. It includes essential PHP extensions for WordPress and configures Nginx to serve static assets efficiently and proxy dynamic requests to PHP-FPM. We also install the AWS SDK for S3 integration.

FROM php:8.1-fpm-alpine

# Install necessary extensions and tools
RUN apk update && apk add --no-cache \
    nginx \
    supervisor \
    gettext-tools \
    libzip-dev \
    libpng-dev \
    libjpeg-turbo-dev \
    freetype-dev \
    icu-dev \
    imagemagick-dev \
    libwebp-dev \
    libxml2-dev \
    zip \
    unzip \
    git \
    curl \
    && docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
    && docker-php-ext-install -j$(nproc) gd zip exif intl opcache \
    && apk del --no-cache libzip-dev libpng-dev libjpeg-turbo-dev freetype-dev icu-dev imagemagick-dev libwebp-dev libxml2-dev \
    && rm -rf /var/cache/apk/*

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

# Install AWS SDK for PHP
RUN pecl install aws-sdk-php && docker-php-ext-enable aws-sdk-php

# Configure Nginx
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf

# Configure PHP-FPM
COPY php-fpm/php.ini /usr/local/etc/php-fpm.conf
COPY php-fpm/www.conf /usr/local/etc/php-fpm.d/www.conf

# Configure Supervisor
COPY supervisor/supervisord.conf /etc/supervisord.conf

# Set up WordPress directory and permissions
RUN mkdir -p /var/www/html && chown www-data:www-data /var/www/html
VOLUME /var/www/html/wp-content

# Copy WordPress core if not using official image (optional, for custom builds)
# COPY wordpress/ /var/www/html/

# Expose ports
EXPOSE 9000

# Start Supervisor
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

Nginx Configuration

The Nginx configuration is crucial for serving static files directly and proxying PHP requests. It also handles SSL termination if you’re using a load balancer.

# nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
}

# nginx/conf.d/default.conf
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.php index.html index.htm;

    server_name _;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    # Serve static files directly
    location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml|zip|tgz|gz|rar|bz2|pdf|txt|swf|flv|mov|mp3|mp4|ogg|wav)$ {
        expires 30d;
        add_header Cache-Control "public";
    }
}

PHP-FPM Configuration

Tuning PHP-FPM is critical for performance. We’ll adjust process management and memory limits.

; php-fpm/php.ini
; Basic settings for WordPress
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 120
date.timezone = UTC
error_reporting = E_ALL && ~E_DEPRECATED && ~E_STRICT
display_errors = Off
log_errors = On
error_log = /var/log/php-fpm/error.log

; Opcache settings for performance
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.validate_timestamps=1
opcache.save_comments=1
opcache.enable_file_override=0

; Session settings
session.save_handler = redis
session.save_path = "tcp://redis:6379"

; Other recommended settings
realpath_cache_size = 4M
realpath_cache_ttl = 600
; php-fpm/www.conf
; For more information on this file, see the following page:
; http://php.net/manual/en/configuration.file.php.php-fpm.php
; This file is managed by WordPress.

[global]
pid = /run/php/php8.1-fpm.pid
error_log = /var/log/php-fpm/error.log
log_level = notice

[www-data]
user = www-data
group = www-data
listen = /run/php/php8.1-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.start_servers = 2
pm.idle_timeout = 10s
request_terminate_timeout = 120
; rlimit_files = 4096
; rlimit_nofile = 4096
; rlimit_core = 0

; chroot = /var/www/html
; insecure_raw_mode = enable

; Accept connections from outside the Docker network (not recommended for production)
; listen.acl_users = www-data

; Specify the user and group to run PHP-FPM as
; user = www-data
; group = www-data

; Set the maximum number of child processes
; pm.max_children = 50

; Set the number of child processes to start at boot
; pm.start_servers = 5

; Set the minimum number of idle child processes
; pm.min_spare_servers = 2

; Set the maximum number of idle child processes
; pm.max_spare_servers = 10

; Set the maximum time in seconds for a script to run
; request_terminate_timeout = 60

; Set the maximum number of requests each child process should execute before respawning
; pm.max_requests = 500

Supervisor Configuration

Supervisor will manage both Nginx and PHP-FPM processes, ensuring they are running and restarting them if they fail.

[supervisord]
nodaemon=true
user=root

[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
priority=10
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx_err.log

[program:php-fpm]
command=/usr/local/sbin/php-fpm --nodaemonize --fpm-config /usr/local/etc/php-fpm.conf
autostart=true
autorestart=true
priority=20
stdout_logfile=/var/log/supervisor/php-fpm.log
stderr_logfile=/var/log/supervisor/php-fpm_err.log

AWS Integration: S3 for Media and RDS for Database

For production environments, we’ll leverage AWS services for persistent storage and a managed database. This offloads critical infrastructure management to AWS, enhancing reliability and scalability.

AWS RDS for MySQL

Instead of running MySQL within Docker Swarm, we’ll provision an AWS RDS instance. This provides automated backups, patching, replication, and high availability. Ensure your RDS instance is configured with Multi-AZ for failover.

  • Create an RDS MySQL instance.
  • Configure security groups to allow inbound traffic from your Docker Swarm nodes on port 3306.
  • Note the RDS endpoint, username, and password.
  • Update your docker-compose.yml to remove the db service and modify the WordPress service’s WORDPRESS_DB_HOST to your RDS endpoint.

AWS S3 for Media Uploads

Storing media uploads directly on container volumes is problematic for stateless microservices. We’ll use AWS S3 (or compatible services like MinIO for local testing) for object storage. This requires a WordPress plugin like “S3-Media-Cloud” or “WP Offload Media Lite”.

MinIO Configuration (Local Testing)

The docker-compose.yml includes a MinIO service for local development. After starting the stack, you’ll need to configure your S3 plugin with MinIO’s endpoint (e.g., http://minio:9000), access key, and secret key.

AWS S3 Configuration (Production)

For production, you’ll need to:

  • Create an S3 bucket.
  • Configure IAM users/roles with appropriate S3 permissions (e.g., s3:PutObject, s3:GetObject, s3:DeleteObject).
  • Install and configure an S3 media offload plugin in WordPress. You’ll provide the AWS region, bucket name, and AWS credentials (ideally via IAM roles attached to your EC2 instances or ECS tasks, or by using environment variables/AWS credentials file).
// Example configuration for WP Offload Media Lite (via WP-CLI or plugin settings)
// This would typically be done via the WordPress admin interface or WP-CLI
// For programmatic setup, you'd interact with the plugin's API.

// Example WP-CLI command (conceptual, actual command may vary by plugin)
// wp plugin install wp-offload-media-lite --activate
// wp rewrite structure '/%year%/%monthnum%/%postname%/' --hard
// wp config set WP_S3_BUCKET 'your-s3-bucket-name'
// wp config set WP_S3_REGION 'your-aws-region'
// wp config set WP_S3_KEY 'YOUR_AWS_ACCESS_KEY_ID' // Use IAM roles in production!
// wp config set WP_S3_SECRET 'YOUR_AWS_SECRET_ACCESS_KEY' // Use IAM roles in production!
// wp offload-media enable --bucket=your-s3-bucket-name --region=your-aws-region --key=YOUR_AWS_ACCESS_KEY_ID --secret=YOUR_AWS_SECRET_ACCESS_KEY

Orchestrating with Docker Swarm

Once your docker-compose.yml is prepared and your AWS configurations are in place, deploying to Docker Swarm is straightforward.

Initializing Docker Swarm

On your manager node:

docker swarm init --advertise-addr <MANAGER_IP>

On your worker nodes, join the swarm:

docker swarm join --token <SWARM_TOKEN> <MANAGER_IP>:2377

Deploying the Stack

Ensure your AWS credentials and other secrets are available as environment variables or in a secrets file. Then, deploy the stack:

# Create a .env file for secrets
echo "MYSQL_ROOT_PASSWORD=your_root_password" >> .env
echo "MYSQL_PASSWORD=your_db_password" >> .env
echo "MINIO_ROOT_USER=minioadmin" >> .env
echo "MINIO_ROOT_PASSWORD=minioadmin" >> .env

# Deploy the stack
docker stack deploy -c docker-compose.yml wordpress_stack

This command will create the services defined in your docker-compose.yml across your Swarm cluster. Docker Swarm will manage the desired number of replicas for each service, handle rolling updates, and restart failed containers.

Load Balancing and Ingress

For external access, you’ll need a load balancer. This can be an AWS Elastic Load Balancer (ELB) or an Nginx/HAProxy instance running as a Swarm service. The load balancer should distribute traffic to the WordPress service’s exposed port (port 80 in our example).

AWS ELB Configuration

Configure an Application Load Balancer (ALB) or Network Load Balancer (NLB) to:

  • Listen on port 80 (and 443 for HTTPS).
  • Create target groups pointing to your Docker Swarm nodes on port 80 (or the NodePort if using Kubernetes-style services).
  • Configure health checks to verify the WordPress application is responsive.
  • Associate an SSL certificate for HTTPS.

Nginx/HAProxy as a Swarm Service

You can deploy an Nginx or HAProxy service within your Swarm to act as the ingress point. This service would have its port published to the host and would route traffic to the WordPress service.

# Example nginx.conf for an ingress load balancer service
# This Nginx instance would be a separate Swarm service,
# routing traffic to the 'wordpress_stack_wordpress' service.

events {
    worker_connections 1024;
}

http {
    upstream wordpress_backend {
        # Use the Swarm service name for load balancing
        # Docker Swarm's internal DNS resolves this to the IPs of healthy tasks
        server wordpress_stack_wordpress:80;
    }

    server {
        listen 80;
        server_name yourdomain.com;

        location / {
            proxy_pass http://wordpress_backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Monitoring and Maintenance

A robust monitoring strategy is essential for maintaining a high-availability WordPress deployment. Key areas to monitor include:

  • Container Health: Docker Swarm’s built-in health checks and logs.
  • Application Performance: WordPress-specific metrics (response times, error rates) using tools like New Relic, Datadog, or Prometheus with Grafana.
  • Database Performance: RDS metrics (CPU, memory, IOPS, connections).
  • Resource Utilization: CPU, memory, and network usage on Swarm nodes.
  • Error Logs: Centralized logging for Nginx, PHP-FPM, and WordPress.

Centralized Logging

To effectively debug issues across distributed services, implement centralized logging. A common pattern is to deploy a logging agent (like Fluentd or Filebeat) as a DaemonSet on each Swarm node, forwarding logs to a central store (e.g., Elasticsearch, Loki, or AWS CloudWatch Logs).

# Example logging agent service in docker-compose.yml (e.g., Filebeat)
# This would be deployed as a DaemonSet to run on every node.
# ... other services ...

  filebeat:
    image: elastic/filebeat:8.5.0
    user: root
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /etc/localtime:/etc/localtime:ro
      - ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
    command: --strict.perms=false
    networks:
      - logging-network
    deploy:
      mode: global # Run on every node
      restart_policy:
        condition: on-failure

Conclusion

By decomposing WordPress into microservices orchestrated by Docker Swarm and leveraging AWS managed services, we achieve a highly available, scalable, and resilient architecture. This approach simplifies management, allows for independent scaling of components, and significantly reduces the operational burden compared to traditional monolithic deployments.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Orchestrating High-Availability WordPress with Docker Swarm and AWS: A Deep Dive into Microservices Architecture
  • Unlocking Serverless PHP 9 with AWS Lambda: A Deep Dive into Cold Starts, Performance, and Cost Optimization
  • Orchestrating Microservices with Docker Swarm: A Performance and Scalability Deep Dive for Production Laravel Applications
  • Beyond Basic Containers: Orchestrating Scalable WordPress Headless with Docker Swarm and AWS ECS for High Availability
  • Leveraging PHP 9’s JIT Compiler and Native AOT for Extreme Performance Gains in Laravel Applications

Categories

  • apache (1)
  • AWS (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (664)
  • Desktop Applications (14)
  • DevOps (86)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (88)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • Performance & Security Optimization (10)
  • PHP (305)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (10)
  • Python (20)
  • Ruby on Rails (1)
  • Security (1)
  • Security & Compliance (650)
  • SEO & Growth (492)
  • Server (118)
  • Softwares (1)
  • Ubuntu (9)
  • Uncategorized (618)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (165)
  • WordPress Plugin Development (728)
  • WordPress Theme Development (357)

Recent Posts

  • Orchestrating High-Availability WordPress with Docker Swarm and AWS: A Deep Dive into Microservices Architecture
  • Unlocking Serverless PHP 9 with AWS Lambda: A Deep Dive into Cold Starts, Performance, and Cost Optimization
  • Orchestrating Microservices with Docker Swarm: A Performance and Scalability Deep Dive for Production Laravel Applications

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (728)
  • Debugging & Troubleshooting (664)
  • Security & Compliance (650)
  • Uncategorized (618)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala