• 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 » Installing and Configuring an Enterprise WordPress Environment on RHEL 9: Complete High-Availability Architecture

Installing and Configuring an Enterprise WordPress Environment on RHEL 9: Complete High-Availability Architecture

Prerequisites and Initial Setup

This guide assumes a RHEL 9 minimal installation with root or sudo privileges. We will deploy a highly available WordPress environment leveraging Nginx as the web server, MariaDB for the database, and Redis for object caching. For high availability, we’ll configure two web servers behind a load balancer (HAProxy in this example) and a primary/replica MariaDB cluster. Ensure all servers have static IP addresses and can resolve each other by hostname. Firewall rules will be adjusted as needed.

On each WordPress web server (node1 and node2):

  • Update the system:
sudo dnf update -y
sudo dnf upgrade -y
  • Install necessary packages:
sudo dnf install -y epel-release
sudo dnf install -y nginx php php-fpm php-mysqlnd php-gd php-xml php-mbstring php-json php-opcache redis

On the database server (db1 and db2):

  • Install MariaDB packages:
sudo dnf install -y mariadb-server mariadb-client

On the load balancer server (lb1):

  • Install HAProxy:
sudo dnf install -y haproxy

MariaDB Galera Cluster Setup

We’ll set up a two-node MariaDB Galera Cluster for synchronous replication. This ensures data consistency across both database servers.

On db1 (Primary):

  • Configure MariaDB for Galera:
# /etc/my.cnf.d/galera.cnf
[galera]
wsrep_on=ON
wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so
wsrep_cluster_name="wp_cluster"
wsrep_cluster_address="gcomm://192.168.1.101,192.168.1.102"  # IPs of db1 and db2
wsrep_node_name="db1"
wsrep_node_address="192.168.1.101" # IP of db1
binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_size=1G

On db2 (Replica):

  • Configure MariaDB for Galera (similar to db1, adjust wsrep_node_name and wsrep_node_address):
# /etc/my.cnf.d/galera.cnf
[galera]
wsrep_on=ON
wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so
wsrep_cluster_name="wp_cluster"
wsrep_cluster_address="gcomm://192.168.1.101,192.168.1.102"  # IPs of db1 and db2
wsrep_node_name="db2"
wsrep_node_address="192.168.1.102" # IP of db2
binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_size=1G

On db1:

  • Start MariaDB and initialize the cluster:
sudo systemctl start mariadb
sudo galera_new_cluster

On db2:

  • Start MariaDB (it will join the existing cluster):
sudo systemctl start mariadb

After starting both, verify cluster status:

sudo mariadb -e "SHOW STATUS LIKE 'wsrep_cluster_size';"

The output should show wsrep_cluster_size as 2.

Secure your MariaDB installation:

sudo mariadb-secure-installation

Create a WordPress database and user. Execute this on either db1 or db2, as changes will replicate.

CREATE DATABASE wordpress_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_user'@'%' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wp_user'@'%';
FLUSH PRIVILEGES;

Nginx and PHP-FPM Configuration

Configure Nginx to serve WordPress and PHP-FPM for processing PHP requests. This configuration will be identical on both web servers (node1 and node2).

Create a WordPress directory:

sudo mkdir -p /var/www/wordpress

Configure PHP-FPM pool for Nginx. Edit /etc/php-fpm.d/www.conf. Ensure the user and group are set to nginx (or the user Nginx runs as).

; /etc/php-fpm.d/www.conf
[www]
user = nginx
group = nginx
listen = /run/php-fpm/www.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.process_idle_timeout = 10s
request_terminate_timeout = 120s
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M
php_admin_value[max_execution_time] = 300

Start and enable PHP-FPM and Nginx:

sudo systemctl start php-fpm
sudo systemctl enable php-fpm
sudo systemctl start nginx
sudo systemctl enable nginx

Create an Nginx virtual host configuration for WordPress. Create /etc/nginx/conf.d/wordpress.conf:

# /etc/nginx/conf.d/wordpress.conf
server {
    listen 80;
    server_name your_domain.com www.your_domain.com; # Replace with your domain
    root /var/www/wordpress;
    index index.php index.html index.htm;

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

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_read_timeout 300; # Increase timeout for long operations
    }

    location ~ /\.ht {
        deny all;
    }

    # Caching for static assets (optional but recommended)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # Deny access to sensitive files
    location ~* (wp-config\.php|wp-settings\.php|wp-load\.php|wp-cron\.php) {
        deny all;
    }
}

Test Nginx configuration and reload:

sudo nginx -t
sudo systemctl reload nginx

WordPress Installation

Download and extract the latest WordPress version on one of the web servers (e.g., node1). The files will be copied to node2 later.

cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
sudo mv wordpress/* /var/www/wordpress/

Set correct ownership and permissions:

sudo chown -R nginx:nginx /var/www/wordpress
sudo find /var/www/wordpress/ -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress/ -type f -exec chmod 644 {} \;

Copy WordPress files to the second web server (node2):

# On node1
sudo rsync -avz /var/www/wordpress/ node2_ip:/var/www/wordpress/

On both web servers (node1 and node2), create the wp-config.php file. Copy wp-config-sample.php and edit it.

# On node1 and node2
sudo cp /var/www/wordpress/wp-config-sample.php /var/www/wordpress/wp-config.php
sudo nano /var/www/wordpress/wp-config.php

Update the database details in wp-config.php. Use the database name, user, and password created earlier. For high availability, point to the Galera cluster’s virtual IP or a DNS entry that resolves to the load balancer for the database.

/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress_db' );

/** MySQL database username */
define( 'DB_USER', 'wp_user' );

/** MySQL database password */
define( 'DB_PASSWORD', 'your_strong_password' );

/** MySQL hostname */
// For Galera, use a virtual IP or DNS that points to your HAProxy DB load balancer
// If not using a DB load balancer, you might need to configure WordPress to connect to one node
// and rely on Galera's automatic failover, but a dedicated DB load balancer is recommended.
define( 'DB_HOST', '192.168.1.200' ); // Example: Virtual IP for DB HAProxy

/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );

/** The Database Collate type. Get this in your phpMyAdmin or by running "SHOW COLLATION;". */
define( 'DB_COLLATE', '' );

/**#@-*/

/**
 * WordPress Database Table prefix.
 *
 * You can have multiple installations in one database if you give each a unique
 * prefix. Only numbers, letters, and underscores please!
 */
$table_prefix = 'wp_';

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 */
define( 'WP_DEBUG', false );

/* Add Redis Object Cache */
define( 'WP_REDIS_HOST', '127.0.0.1' ); // Assuming Redis is on the same server for simplicity
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_PASSWORD', '' ); // Set if you have a password
define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_CACHE_KEY_PREFIX', 'wp_' );
define( 'WP_CACHE', true );

/* That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', __DIR__ );
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

Generate unique security keys and salts. You can get them from https://api.wordpress.org/secret-key/1.1/salt/. Replace the placeholder section in wp-config.php with the generated keys.

Redis Object Caching

Install and configure Redis for object caching on each web server. This significantly improves WordPress performance by reducing database load.

On node1 and node2:

  • Start and enable Redis:
sudo systemctl start redis
sudo systemctl enable redis

Install the Redis Object Cache plugin for WordPress. Download the latest release from GitHub or use WP-CLI.

# On node1 and node2
cd /var/www/wordpress/wp-content/plugins/
wget https://github.com/rhubarbgroup/redis-cache/archive/refs/tags/2.1.5.tar.gz # Replace with latest version
tar -xzf 2.1.5.tar.gz
mv redis-cache-2.1.5 redis-cache
rm 2.1.5.tar.gz
chown -R nginx:nginx redis-cache

Activate the plugin via the WordPress admin dashboard or WP-CLI:

# On node1 (or any server with WP-CLI installed)
cd /var/www/wordpress/
wp plugin activate redis-cache --allow-root

Ensure the Redis configuration in wp-config.php (shown in the previous section) is correct. You should see the Redis object cache status in the WordPress admin area under “Settings” -> “Redis”.

HAProxy Load Balancer Configuration

Configure HAProxy to distribute traffic between the two Nginx web servers and optionally between the two MariaDB servers.

Edit the HAProxy configuration file: /etc/haproxy/haproxy.cfg.

# /etc/haproxy/haproxy.cfg
global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000

frontend http_frontend
    bind *:80
    default_backend http_backend

backend http_backend
    balance roundrobin
    option httpchk GET /
    server node1 192.168.1.11:80 check
    server node2 192.168.1.12:80 check

# Optional: Database Load Balancing (if using a separate HAProxy for DB)
# If you are using a dedicated DB load balancer, configure it here.
# For simplicity, we'll assume WordPress is configured to use a virtual IP
# that points to a DB load balancer or a single DB node with Galera handling failover.
# If you want HAProxy to load balance DB traffic directly:
# mode tcp
# option tcp-check
# server db1 192.168.1.101:3306 check
# server db2 192.168.1.102:3306 check

Start and enable HAProxy:

sudo systemctl start haproxy
sudo systemctl enable haproxy

Ensure firewall rules allow traffic on port 80 (HTTP) and potentially port 3306 (MySQL) if HAProxy is load balancing the database.

# On lb1
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

# On web servers (node1, node2) - allow traffic from HAProxy
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.200/32" port port="80" protocol="tcp" accept' # Replace with LB IP
sudo firewall-cmd --reload

# On DB servers (db1, db2) - allow traffic from HAProxy (if DB LB is used)
# sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.200/32" port port="3306" protocol="tcp" accept' # Replace with LB IP
# sudo firewall-cmd --reload

Final WordPress Configuration and Security

Access your WordPress site via the IP address or domain name configured in HAProxy. Complete the WordPress installation wizard.

Security Best Practices:

  • HTTPS: Implement SSL/TLS certificates (e.g., Let’s Encrypt) on your web servers and configure Nginx to use HTTPS. Update HAProxy to forward HTTPS traffic or handle SSL termination.
  • File Permissions: Regularly audit and maintain strict file permissions. The nginx:nginx ownership and 755/644 permissions are a good starting point.
  • WordPress Updates: Keep WordPress core, themes, and plugins updated to patch security vulnerabilities.
  • Security Plugins: Consider using security plugins like Wordfence or Sucuri for additional protection.
  • Database Security: Regularly back up your MariaDB cluster. Use strong, unique passwords for your database user. Restrict access to the database server from trusted IPs only.
  • PHP Hardening: Further harden PHP settings in php.ini (e.g., disable dangerous functions, set appropriate resource limits).
  • Nginx Hardening: Implement rate limiting, block common exploits, and configure security headers in Nginx.
  • Fail2Ban: Install and configure Fail2Ban on all servers to protect against brute-force attacks.

This setup provides a robust, scalable, and highly available WordPress environment. Monitoring is crucial for maintaining performance and uptime. Implement monitoring tools (e.g., Prometheus, Grafana, Nagios) to track server health, resource utilization, and application performance.

Reader Interactions

Leave a Reply Cancel reply

You must be logged in to post a comment.

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

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store
  • How to refactor legacy event ticket registers queries using modern WP_Query and custom Transient caching
  • Step-by-Step Guide: Offloading high-frequency member profile directories metadata writes to a Redis KV store

Categories

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

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (726)
  • Debugging & Troubleshooting (662)
  • Security & Compliance (647)
  • SEO & Growth (492)

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