The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MongoDB on OVH for WooCommerce
Nginx Configuration for WooCommerce High Traffic
Optimizing Nginx is paramount for serving high-traffic WooCommerce sites. We’ll focus on key directives that directly impact performance and resource utilization on an OVH VPS or dedicated server. This assumes a standard Ubuntu/Debian setup.
Worker Processes and Connections
The worker_processes directive controls how many worker processes Nginx will spawn. A common recommendation is to set this to the number of CPU cores available. For highly concurrent scenarios, tuning worker_connections is also critical. This defines the maximum number of simultaneous connections that each worker process can handle.
Edit your main Nginx configuration file, typically /etc/nginx/nginx.conf:
user www-data;
worker_processes auto; # Or set to the number of CPU cores, e.g., worker_processes 4;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024; # Default is 1024, consider increasing for high concurrency
multi_accept on;
}
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;
# ... other http configurations
}
After modifying nginx.conf, test the configuration and reload Nginx:
sudo nginx -t sudo systemctl reload nginx
Gzip Compression and Caching
Enabling Gzip compression significantly reduces the size of text-based assets (HTML, CSS, JS, JSON), leading to faster page loads. Browser caching via expires headers tells the client’s browser how long to cache specific file types, reducing server load for repeat visitors.
Add or modify these directives within your http block or a specific server block for your WooCommerce site:
http {
# ... other http configurations
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;
# Browser Caching
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public";
}
# ... other http configurations
}
HTTP/2 and TLS/SSL Optimization
Leveraging HTTP/2 offers multiplexing, header compression, and server push, which are crucial for modern web applications. Proper TLS/SSL configuration, including cipher suites and session caching, is also vital for security and performance.
Ensure your server block is configured for HTTP/2 and optimized SSL:
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name your_domain.com www.your_domain.com;
ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
# Modern TLS configuration (e.g., from Mozilla SSL Config Generator)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
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;
ssl_session_cache shared:SSL:10m; # Adjust size as needed
ssl_session_timeout 10m;
ssl_session_tickets off; # Consider security implications
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s; # Use your preferred DNS resolvers
resolver_timeout 5s;
# ... other server configurations (root, index, location blocks)
}
Gunicorn/PHP-FPM Tuning for WooCommerce
The choice between Gunicorn (for Python-based frameworks like Django/Flask, less common for direct WooCommerce but possible with custom setups) and PHP-FPM (standard for WooCommerce) dictates the tuning approach. We’ll cover PHP-FPM as it’s the most relevant.
PHP-FPM Process Manager Settings
PHP-FPM’s process manager controls how worker processes are spawned and managed. The pm setting can be static, dynamic, or ondemand. For a busy WooCommerce site, dynamic or static often provides the best balance.
Edit your PHP-FPM pool configuration file. This is typically located in /etc/php/[version]/fpm/pool.d/www.conf (replace [version] with your PHP version, e.g., 7.4, 8.1).
; /etc/php/8.1/fpm/pool.d/www.conf [www] user = www-data group = www-data listen = /run/php/php8.1-fpm.sock # Or a TCP/IP socket if preferred ; Process Manager settings pm = dynamic pm.max_children = 50 ; Max number of children always running. Adjust based on RAM. pm.start_servers = 5 ; Number of servers started when PHP-FPM is started. pm.min_spare_servers = 5 ; Min number of idle servers. pm.max_spare_servers = 10 ; Max number of idle servers. pm.max_requests = 500 ; Max requests per child process. Helps prevent memory leaks. ; If using static, set a fixed number of children ; pm = static ; pm.max_children = 100 ; If using ondemand, it spawns processes as needed ; pm = ondemand ; pm.max_children = 100 ; pm.process_idle_timeout = 10s ; Other important settings ; request_terminate_timeout = 120s ; Timeout for script execution ; rlimit_files = 1024 ; rlimit_core = 0
Tuning Considerations:
pm.max_children: This is the most critical. Monitor your server’s RAM. If you run out of memory, decrease this. If you have plenty of RAM and see processes waiting, increase it. A common starting point is(Total RAM - OS/Nginx/DB RAM) / Average PHP Process RAM.pm.max_requests: Setting this to a reasonable number (e.g., 500-1000) helps recycle child processes, mitigating potential memory leaks in plugins or themes.pm.start_servers,pm.min_spare_servers,pm.max_spare_servers: These are fordynamicmode. Adjust them to ensure enough idle workers are ready without consuming excessive memory.
After changes, restart PHP-FPM:
sudo systemctl restart php8.1-fpm
Nginx FastCGI Cache for WooCommerce
For static pages (like product listings, category pages, homepage) that don’t change per user, Nginx’s FastCGI cache can dramatically reduce PHP-FPM load and database queries. This is a powerful optimization for WooCommerce.
First, ensure the FastCGI cache module is enabled (it usually is by default). Then, configure it in your Nginx server block.
server {
# ... other server configurations
set $skip_cache 0;
# Don't cache logged-in users or admin pages
if ($http_cookie ~* "wordpress_logged_in_|comment_author_|woocommerce_items_in_cart") {
set $skip_cache 1;
}
# Don't cache AJAX requests or POST requests
if ($request_method = POST) {
set $skip_cache 1;
}
if ($http_x_requested_with = "XMLHttpRequest") {
set $skip_cache 1;
}
# Don't cache specific WooCommerce query parameters (e.g., add-to-cart)
if ($args ~* "(add-to-cart|remove-from-cart|apply_coupon)") {
set $skip_cache 1;
}
# Cache key based on request URI
set $cache_key "$scheme$request_method$host$request_uri";
# Use the cache key for logged-out users
add_header X-Cache-Status $skip_cache; # For debugging
# FastCGI Cache configuration
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock; # Match your PHP-FPM socket
# FastCGI Cache directives
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_valid 200 60s; # Cache successful responses for 60 seconds
fastcgi_cache_valid 301 302 10m; # Cache redirects for 10 minutes
fastcgi_cache_valid 404 1m; # Cache 404s for 1 minute
fastcgi_cache_lock on; # Prevent multiple requests from hitting backend simultaneously
fastcgi_cache_use_stale error timeout updating http_500; # Serve stale cache if backend fails
fastcgi_cache_bypass $skip_cache;
fastcgi_cache_revalidate on; # Revalidate cache before serving stale content
add_header X-FastCGI-Cache $upstream_cache_status; # For debugging
# Other fastcgi params
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Serve static files directly
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public";
access_log off;
try_files $uri =404;
}
# ... other location blocks for WordPress/WooCommerce
location / {
try_files $uri $uri/ /index.php?$args;
}
}
Cache Purging: You’ll need a mechanism to purge the cache when content is updated (e.g., new product, updated price). This can be done via a custom Nginx purge module or by using a WordPress plugin that integrates with Nginx cache purging (e.g., WP Rocket, W3 Total Cache with Nginx helper). A common approach is to use a custom Nginx location block:
location ~ ^/purge(/.*)$ {
allow 127.0.0.1; # Allow purging only from localhost
allow ::1;
allow your_server_ip; # Allow purging from your management IP
deny all;
fastcgi_cache_purge MY_CACHE_ZONE "$scheme$request_method$host$1"; # Replace MY_CACHE_ZONE with your cache zone name
access_log purged.log;
return 204;
}
Reload Nginx after applying these changes:
sudo nginx -t sudo systemctl reload nginx
MongoDB Performance Tuning for WooCommerce
While WooCommerce primarily uses MySQL, many advanced plugins, custom solutions, or analytics platforms might leverage MongoDB. Optimizing MongoDB involves indexing, query analysis, and resource allocation.
Indexing Strategy
Proper indexing is the single most effective way to speed up MongoDB queries. Analyze your slow queries using MongoDB’s profiler.
Enable the profiler (for testing/debugging, disable in production unless actively monitoring):
# Connect to MongoDB shell mongosh # Enable profiling for the 'local' database (or your specific database) db.setProfilingLevel(1) // 0=off, 1=slow queries, 2=all queries db.getProfilingStatus()
Examine slow queries:
db.system.profile.find({ op: "query", millis: { $gt: 100 } }).pretty()
Based on slow queries, create appropriate indexes. For example, if you have a collection orders and frequently query by customer_id and order_date:
// Connect to your WooCommerce MongoDB database
use my_woocommerce_db;
// Create a compound index
db.orders.createIndex( { customer_id: 1, order_date: -1 } )
// Create an index for a common lookup field
db.products.createIndex( { sku: 1 } )
Use explain() to verify if your queries are using the indexes:
db.orders.find({ customer_id: "user123" }).explain("executionStats")
MongoDB Configuration (`mongod.conf`)
The mongod.conf file (typically /etc/mongod.conf) contains crucial settings for MongoDB’s performance and resource usage.
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
logRotate: reopen
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
engine: wiredTiger # Default and recommended engine
# WiredTiger specific cache settings
# The default is 50% of RAM, but can be tuned.
# For a dedicated MongoDB server, you might allocate more.
# For a shared OVH server, be more conservative.
# Example: Allocate 4GB of RAM for WiredTiger cache
# wiredTiger:
# engineConfig:
# cacheSizeGB: 4
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod.pid
# Ensure the user running mongod has correct permissions for dbPath and log paths
net:
port: 27017
bindIp: 0.0.0.0 # Or specific IPs for security
# Security settings (essential for production)
# security:
# authorization: enabled
# Sharding settings (if applicable)
# sharding:
# clusterRole: configsvr
# # or shardsvr
Tuning Considerations:
storage.journal.enabled: Should always betruefor data durability.storage.engineConfig.cacheSizeGB: This is critical. Allocate a significant portion of RAM to the WiredTiger cache, but leave enough for the OS, Nginx, PHP-FPM, and other services. Monitor RAM usage closely.net.bindIp: For security, bind to specific IP addresses rather than0.0.0.0if MongoDB is not intended to be accessible from all interfaces.security.authorization: Enable this in production to control access.
After modifying mongod.conf, restart MongoDB:
sudo systemctl restart mongod
Monitoring and Iteration
Performance tuning is an iterative process. Continuously monitor your system’s health and performance metrics:
- Nginx: Use
ngx_http_stub_status_modulefor active connections, requests per second. Monitor error logs (/var/log/nginx/error.log). - PHP-FPM: Monitor the process manager status (if enabled) and PHP error logs.
- MongoDB: Use
mongostat,mongotop, and the profiler. Monitor system resource usage (CPU, RAM, I/O). - System: Use tools like
htop,vmstat,iostat, and Prometheus/Grafana for comprehensive monitoring.
Regularly review these metrics, identify bottlenecks, and adjust configurations accordingly. For OVH environments, understanding the underlying hardware and network can also inform tuning decisions.