• 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 » Scaling WordPress on OVH to Handle 50,000+ Concurrent Requests

Scaling WordPress on OVH to Handle 50,000+ Concurrent Requests

Architectural Foundation: OVH Dedicated Servers & Load Balancing

Achieving 50,000+ concurrent requests for a WordPress site on OVH necessitates a robust, multi-layered architecture. We’ll leverage OVH’s dedicated server offerings for raw performance and their advanced load balancing capabilities to distribute traffic efficiently. This isn’t about tweaking a single server; it’s about building a distributed system.

Dedicated Server Selection & Initial Configuration

For this scale, we’re looking at OVH’s “Infrastructure” dedicated servers. A minimum of two high-core-count servers (e.g., AMD EPYC-based) is recommended for the web tier, with additional servers for the database tier. The exact model depends on the specific workload (CPU-bound vs. I/O-bound), but prioritize ample RAM (128GB+) and fast NVMe storage.

Initial OS setup should be minimal. Ubuntu LTS or CentOS Stream are solid choices. Harden the OS immediately:

  • Disable root SSH login and use key-based authentication for a dedicated admin user.
  • Configure a firewall (e.g., UFW or firewalld) to allow only necessary ports (SSH, HTTP, HTTPS).
  • Install and configure `fail2ban` to protect against brute-force attacks.

Web Server Tier: Nginx & PHP-FPM Optimization

Nginx is the de facto standard for high-performance WordPress serving due to its event-driven architecture. We’ll run multiple PHP-FPM pools, each tuned for concurrency.

Nginx Configuration Snippet (/etc/nginx/nginx.conf):

user www-data;
worker_processes auto; # Set to number of CPU cores
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 8192; # Adjust based on system limits and expected load
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off; # Important for security

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 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;

    # SSL configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';

    # Include site configurations
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

PHP-FPM Pool Configuration (e.g., /etc/php/8.2/fpm/pool.d/www.conf):

We’ll use the ondemand process manager for dynamic scaling, but with aggressive settings. For extreme loads, a static or dynamic pool with a high pm.max_children might be necessary, but requires careful tuning to avoid exhausting server resources.

[www]
user = www-data
group = www-data
listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = ondemand
pm.max_children = 100  ; Start with a high value, monitor and adjust
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.process_idle_timeout = 10s
pm.max_requests = 500 ; Prevent memory leaks

request_terminate_timeout = 60s
request_slowlog_timeout = 30s

catch_workers_output = yes
; rlimit_files = 10240 ; Increase if needed
; rlimit_nofile = 65536 ; Increase if needed

; For WordPress, ensure sufficient memory limit
memory_limit = 512M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 120

Nginx Site Configuration (/etc/nginx/sites-available/your-wordpress-site):

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com www.your-domain.com;

    # Redirect HTTP to HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your-domain.com www.your-domain.com;

    root /var/www/your-wordpress-site/public_html;
    index index.php index.html index.htm;

    # SSL Certificate configuration (using Let's Encrypt example)
    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    # add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none';"; # Uncomment and configure carefully

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

    # Serve static files directly
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp|woff|woff2|ttf|eot)$ {
        expires 30d;
        access_log off;
        add_header Cache-Control "public";
    }

    # Deny access to sensitive files
    location ~ /\.ht {
        deny all;
    }

    # Pass PHP scripts to FastCGI server
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;

        # FastCGI buffer tuning for large requests
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_read_timeout 300s; # Increase for potentially long-running scripts
    }

    # Deny access to wp-config.php
    location ~ wp-config.php {
        deny all;
    }

    # Caching for static assets (e.g., using Nginx cache or FastCGI cache)
    # Example: FastCGI cache for PHP output (requires additional configuration)
    # fastcgi_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
    # fastcgi_cache_key "$scheme$request_method$host$request_uri";
    # add_header X-FastCGI-Cache $upstream_cache_status;
    # location ~ \.php$ {
    #     ...
    #     fastcgi_cache WORDPRESS;
    #     fastcgi_cache_valid 200 60m; # Cache valid pages for 60 minutes
    #     fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
    # }
}

Database Tier: High-Availability MySQL/MariaDB Cluster

A single database server will be a bottleneck. We need a highly available, performant database cluster. OVH’s Managed Databases or self-hosted Galera Cluster on dedicated servers are viable options. For this scale, self-hosting offers more control and potentially better performance tuning.

Galera Cluster Setup (Conceptual):

  • Minimum of 3 nodes for quorum.
  • Use Percona XtraDB Cluster or MariaDB Galera Cluster.
  • Configure `wsrep_provider`, `wsrep_cluster_address`, `wsrep_cluster_name`, `wsrep_sst_method` (e.g., `xtrabackup-v2`).
  • Tune `innodb_buffer_pool_size` aggressively (e.g., 70-80% of available RAM).
  • Set `innodb_flush_log_at_trx_commit = 2` for better write performance, understanding the slight risk of data loss on a crash.
  • Use `sync_binlog = 0` or `sync_binlog = 1` with caution, depending on RPO requirements.
  • Optimize `max_connections` based on application needs and server resources.
  • Consider dedicated read replicas if read load is significantly higher than write load.

MySQL/MariaDB Configuration Snippet (my.cnf):

[mysqld]
# General
user                    = mysql
pid-file                = /var/run/mysqld/mysqld.pid
socket                  = /var/run/mysqld/mysqld.sock
datadir                 = /var/lib/mysql
log-error               = /var/log/mysql/error.log
# General Log disabled for production
# general_log             = 0
# general_log_file        = /var/log/mysql/mysql.log

# Galera Provider Configuration
wsrep_on                = ON
wsrep_provider          = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name      = "my_galera_cluster"
wsrep_cluster_address   = "gcomm://192.168.1.101,192.168.1.102,192.168.1.103" # IPs of your cluster nodes
wsrep_node_address      = "192.168.1.101" # Specific to each node
wsrep_node_name         = "node1" # Specific to each node
wsrep_sst_method        = xtrabackup-v2
wsrep_sst_auth          = "sstuser:sstpassword"

# InnoDB Configuration
innodb_engine                   = InnoDB
innodb_buffer_pool_size         = 96G  ; Adjust based on server RAM (e.g., 70-80%)
innodb_log_file_size            = 1G
innodb_log_buffer_size          = 128M
innodb_flush_log_at_trx_commit= 2    ; Performance vs. durability trade-off
innodb_flush_method             = O_DIRECT
innodb_io_capacity              = 4000 ; Tune based on disk speed
innodb_io_capacity_max          = 8000
innodb_file_per_table           = ON
innodb_stats_on_metadata        = OFF

# Replication & Concurrency
binlog_format                   = ROW
default_storage_engine          = InnoDB
max_connections                 = 1000 ; Adjust based on load and server resources
thread_cache_size               = 50
table_open_cache                = 4000
table_definition_cache          = 1000
query_cache_type                = 0    ; Query cache is deprecated and often problematic
query_cache_size                = 0
slow_query_log                  = 1
slow_query_log_file             = /var/log/mysql/mysql-slow.log
long_query_time                 = 2

# Galera specific tuning
innodb_autoinc_lock_mode        = 2 ; For better concurrency with Galera
```

Caching Strategy: Multi-Layered Approach

Caching is paramount. We’ll implement a multi-layered strategy:

  • Object Cache (Redis/Memcached): Essential for reducing database load. Use a robust WordPress plugin like W3 Total Cache or WP Rocket configured with Redis. Deploy Redis on separate, powerful servers.
  • Page Cache (Nginx FastCGI Cache or Varnish): Nginx’s built-in FastCGI cache can serve static HTML directly, bypassing PHP entirely for many requests. Varnish offers more advanced features but adds complexity.
  • CDN (Content Delivery Network): Offload static assets (images, CSS, JS) to a CDN like Cloudflare, Akamai, or OVH’s own CDN. This dramatically reduces load on your origin servers.
  • Browser Cache: Leverage HTTP headers (`Expires`, `Cache-Control`) configured in Nginx to instruct browsers to cache static assets.

Redis Configuration Snippet (/etc/redis/redis.conf):

# General
daemonize yes
pidfile /var/run/redis/redis-server.pid
logfile /var/log/redis/redis-server.log
dir /var/lib/redis

# Network
bind 127.0.0.1 -::1 # Bind to localhost if only used locally, or specific IPs if accessed by web servers
protected-mode yes
port 6379

# Memory Management
maxmemory 16gb # Adjust based on available RAM
maxmemory-policy allkeys-lru # Evict least recently used keys when maxmemory is reached

# Persistence (disable for pure cache, enable if data persistence is needed)
save ""
appendonly no

# Replication (if setting up Redis Sentinel or Cluster)
# replica-serve-stale-data yes
# replica-read-only yes

# Security
# requirepass your_strong_redis_password # Uncomment and set a strong password
# rename-command CONFIG "" # Disable dangerous commands
# rename-command FLUSHALL ""

OVH Load Balancer Configuration

OVH’s load balancer is critical for distributing traffic across your Nginx web servers and handling SSL termination. We’ll configure it for HTTP/2 and sticky sessions if necessary (though ideally, WordPress is stateless).

Key Load Balancer Settings:

  • Frontend Configuration: Listen on ports 80 and 443. Terminate SSL here using your certificates. Enable HTTP/2.
  • Backend Pool: Add your Nginx web servers.
  • Load Balancing Algorithm: Round Robin is a good default. Least Connections can be effective if server loads vary significantly.
  • Health Checks: Configure robust health checks (e.g., checking for a specific HTTP status code on a health check URL like /healthz) to automatically remove unhealthy servers from rotation.
  • Session Persistence (Sticky Sessions): Generally avoid for WordPress unless absolutely necessary due to plugin dependencies. If required, configure cookie-based persistence.
  • WAF (Web Application Firewall): Enable OVH’s WAF for an additional layer of security against common web attacks.

WordPress Optimization & Security Plugins

Even with a strong infrastructure, WordPress itself needs tuning:

  • Caching Plugin: W3 Total Cache, WP Rocket, or LiteSpeed Cache (if using LiteSpeed web server). Configure object caching (Redis), page caching, and asset optimization.
  • Image Optimization: Use plugins like Smush Pro or ShortPixel to compress images on upload.
  • Database Optimization: Regularly clean up post revisions, transients, and optimize database tables using plugins like WP-Optimize.
  • Security Plugin: Wordfence or Sucuri Security for malware scanning, firewall rules, and brute-force protection.
  • Disable Unused Features: Turn off pingbacks, trackbacks, and XML-RPC if not needed.
  • Optimize Theme & Plugins: Choose well-coded themes and plugins. Audit and remove any unnecessary or poorly performing ones.

Monitoring & Performance Tuning Workflow

Continuous monitoring is non-negotiable. Set up comprehensive monitoring for:

  • Server Resources: CPU, RAM, Disk I/O, Network traffic (using tools like `htop`, `vmstat`, `iostat`, Prometheus/Grafana).
  • Nginx: Active connections, request rates, error rates (e.g., using `stub_status` module).
  • PHP-FPM: Process manager status, request latency, slow requests.
  • Database: Query performance, connection counts, replication lag, buffer pool hit rate.
  • Application Performance Monitoring (APM): Tools like New Relic, Datadog, or open-source alternatives like Jaeger/Zipkin integrated with WordPress.

Tuning Workflow:

  • Establish Baselines: Understand normal traffic patterns and resource utilization.
  • Load Testing: Use tools like `k6`, `JMeter`, or `ApacheBench` (`ab`) to simulate traffic and identify bottlenecks *before* they occur in production.
  • Analyze Slow Queries: Regularly review the MySQL slow query log.
  • Profile PHP Code: Use tools like Xdebug with a profiler (e.g., KCacheGrind) to identify slow functions or plugin bottlenecks.
  • Iterative Tuning: Adjust Nginx worker connections, PHP-FPM pool sizes, database buffer pool, and caching durations based on monitoring data and load test results.
  • Review Logs: Regularly check Nginx, PHP-FPM, and system logs for errors or warnings.

Conclusion

Scaling WordPress to handle 50,000+ concurrent requests on OVH is an exercise in distributed systems engineering. It requires a high-performance hardware foundation, meticulous configuration of Nginx, PHP-FPM, and a robust database cluster, complemented by aggressive multi-layered caching and continuous monitoring. This architecture provides the necessary horsepower and resilience to serve a demanding audience.

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

  • Disaster Recovery 101: Architecting Auto-Failovers for Redis and PHP Deployments on OVH
  • How We Audited a High-Traffic WooCommerce Enterprise Stack on Google Cloud and Mitigated Race conditions during high-concurrency payment processing
  • Disaster Recovery 101: Architecting Auto-Failovers for Elasticsearch and Magento 2 Deployments on DigitalOcean
  • An Auditor’s Checklist for Securing WordPress Backends on OVH
  • Step-by-Step: Diagnosing Perl script high CPU throttling due to unoptimized regular expressions on AWS Servers

Copyright © 2026 · Vinay Vengala