The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and Redis on OVH for Magento 2
Nginx Configuration for Magento 2 on OVH
Optimizing Nginx is paramount for serving Magento 2 efficiently, especially on OVH infrastructure where resource allocation and network latency are key considerations. We’ll focus on directives that directly impact request handling, caching, and static file delivery.
Core Nginx Performance Directives
The nginx.conf file, typically located at /etc/nginx/nginx.conf or within /etc/nginx/conf.d/, is the primary configuration point. Ensure your worker_processes directive is set to the number of CPU cores available. For a typical OVH VPS with 4 cores, this would be:
worker_processes 4; # Or auto to let Nginx decide # worker_processes auto;
The worker_connections directive controls the maximum number of simultaneous connections that each worker process can handle. A common starting point is 1024, but this can be increased based on expected load and system limits. Ensure your system’s file descriptor limit (ulimit -n) is high enough to accommodate this.
events {
worker_connections 4096; # Increased from default 1024
multi_accept on;
}
Magento 2 Specific Nginx Configuration
Magento 2 requires specific Nginx configurations for static file serving, caching, and proxying to the PHP-FPM or Gunicorn backend. The recommended configuration is usually provided by Magento or third-party modules, but understanding the key components is crucial.
Static File Serving and Caching
Leveraging Nginx’s ability to serve static files directly is a significant performance win. Configure aggressive caching for static assets like CSS, JS, and images. The expires directive controls the Cache-Control and Expires headers.
location ~ ^/(media|static)/ {
expires 30d; # Cache static assets for 30 days
add_header Cache-Control "public, immutable";
access_log off; # Optionally disable access logs for static files
try_files $uri $uri/ /index.php?$args; # Fallback for dynamic content if file not found
}
For the static directory, Magento generates files. Ensure the try_files directive correctly points to the PHP handler if a static file is not found, allowing Magento to serve it dynamically.
Proxying to PHP-FPM/Gunicorn
The core of Magento 2’s dynamic content is handled by PHP-FPM (for PHP) or Gunicorn (for Python-based frameworks, though less common for Magento). Nginx acts as a reverse proxy. Key directives include proxy_pass, proxy_set_header, and timeouts.
location ~ \.php$ {
# For PHP-FPM
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # Adjust PHP version and path as needed
fastcgi_read_timeout 300; # Increase timeout for long-running PHP scripts
# For Gunicorn (if applicable)
# proxy_pass http://unix:/var/run/gunicorn.sock;
# 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_read_timeout 300s;
# proxy_connect_timeout 75s;
# proxy_send_timeout 300s;
}
For PHP-FPM, fastcgi_read_timeout is crucial. Magento operations like indexing or complex product imports can take a long time. Setting this to 300 seconds (5 minutes) is a reasonable starting point.
Buffering and Timeouts
Disable client request body buffering if you encounter issues with large uploads or POST requests. Adjust proxy timeouts to prevent premature disconnections during long operations.
proxy_buffering off; proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600;
Gunicorn Configuration for Magento 2 (if applicable)
While Magento 2 is primarily PHP-based, some custom setups or related services might use Python with Gunicorn. The configuration focuses on worker processes, threads, and binding.
Gunicorn Worker Processes and Threads
The number of worker processes should generally be (2 * number_of_cores) + 1. Threads can be used to handle more concurrent requests per worker, but can also increase memory usage. Start with a conservative number of threads.
# Example command line for Gunicorn gunicorn --workers 5 --threads 2 --bind unix:/var/run/gunicorn.sock myapp:app
For a 4-core CPU, 5 workers is a good starting point. If using threads, 2 threads per worker is a common balance.
Gunicorn Timeouts
Similar to Nginx, Gunicorn has its own timeout settings. These should be aligned with Nginx’s proxy timeouts to avoid conflicts.
# Example command line with timeouts gunicorn --workers 5 --threads 2 --bind unix:/var/run/gunicorn.sock --timeout 300 myapp:app
The --timeout 300 directive sets the worker timeout to 300 seconds.
Redis Configuration for Magento 2 Caching
Redis is essential for Magento 2’s caching mechanisms (sessions, cache types). Tuning Redis involves memory management, persistence, and network settings.
Memory Management
The maxmemory directive is critical. Set it to a value that leaves sufficient RAM for the OS and other services. Magento can consume significant memory, especially during high traffic or intensive operations.
# redis.conf maxmemory 2gb # Adjust based on available RAM and Magento's needs maxmemory-policy allkeys-lru # Eviction policy: LRU is generally good for Magento cache
The maxmemory-policy determines how Redis evicts keys when maxmemory is reached. allkeys-lru (Least Recently Used) is a common and effective choice for caching scenarios.
Persistence and RDB/AOF
For caching purposes, disabling or minimizing persistence is often preferred to reduce I/O overhead. If you need persistence for other reasons, configure it carefully.
# redis.conf save "" # Disable RDB snapshots if Redis is purely for cache and sessions appendonly no # Disable AOF if not needed for durability
If persistence is required, consider the trade-offs. RDB snapshots are more compact but can cause latency during saving. AOF logs every write operation, providing better durability but potentially larger files and higher I/O.
Network and Client Settings
Ensure Redis is accessible only from trusted sources. Binding to a specific IP or using a Unix socket can enhance security. Adjust client timeouts if necessary.
# redis.conf bind 127.0.0.1 # Bind to localhost if Nginx/PHP-FPM are on the same server # Or use a Unix socket for local communication # unixsocket /var/run/redis/redis-server.sock # unixsocketperm 770 tcp-keepalive 300 # Adjust keepalive for long-lived connections
If using a Unix socket, ensure the user running Nginx/PHP-FPM has the correct permissions to access it (e.g., by adding them to the redis group).
Monitoring and Diagnostics
Continuous monitoring is key to identifying bottlenecks. Use tools like htop, netdata, Prometheus/Grafana, and Redis-specific commands.
Nginx Diagnostics
Check Nginx error logs (/var/log/nginx/error.log) for common issues like upstream connection failures or timeouts. Use nginx -t to test configuration changes before reloading.
# Test Nginx configuration sudo nginx -t # Reload Nginx gracefully sudo systemctl reload nginx
PHP-FPM/Gunicorn Diagnostics
Monitor PHP-FPM logs (e.g., /var/log/php7.4-fpm.log) for errors and slow script execution. For Gunicorn, check its stdout/stderr logs.
# Example: Check PHP-FPM slow log (if enabled) sudo tail -f /var/log/php7.4-fpm/slow.log
Redis Diagnostics
Use Redis CLI commands to inspect memory usage, cache hit rates, and latency.
# Connect to Redis CLI redis-cli # Check memory usage INFO memory # Check cache hit rate (requires monitoring over time) INFO stats # Monitor latency (run in a separate terminal) redis-cli --latency-history -h your_redis_host -p your_redis_port
For OVH environments, pay close attention to network latency between your application server and Redis if they are on different instances. Consider placing them within the same OVH network zone for reduced latency.