The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MongoDB on OVH for Shopify
Nginx Configuration for High-Traffic Shopify Stores on OVH
Optimizing Nginx is paramount for handling the spiky traffic patterns typical of e-commerce platforms like Shopify, especially when hosted on OVH’s robust infrastructure. Our focus here is on tuning for maximum throughput and minimal latency, leveraging OVH’s network capabilities.
Worker Processes and Connections
The worker_processes directive should ideally be set to the number of CPU cores available on your OVH instance. This allows Nginx to utilize all available processing power for handling requests. The worker_connections directive dictates the maximum number of simultaneous connections a worker process can handle. A common starting point is 1024, but this can be increased based on your server’s RAM and expected load.
Tuning for Performance
Enable keepalive_timeout to reduce the overhead of establishing new TCP connections for subsequent requests from the same client. A value between 60 and 120 seconds is generally suitable. tcp_nodelay on is crucial for reducing latency by disabling the Nagle algorithm, ensuring small packets are sent immediately.
Gzip Compression and Caching
Enabling Gzip compression significantly reduces bandwidth usage and speeds up content delivery. Configure it to compress text-based assets like HTML, CSS, and JavaScript. Browser caching is also essential; set appropriate expires headers for static assets to allow clients to cache them effectively.
Example Nginx Configuration Snippet
Here’s a sample Nginx configuration block tailored for a high-traffic Shopify store on OVH. Remember to adjust worker_processes based on your specific OVH instance’s CPU count.
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto; # Set to the number of CPU cores on your OVH instance
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 4096; # Adjust based on RAM and load
multi_accept on;
use epoll; # Linux-specific, highly efficient event notification mechanism
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75; # Seconds
types_hash_max_size 2048;
# 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 image/svg+xml;
# Browser Caching for Static Assets
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 365d;
add_header Cache-Control "public";
}
# Proxy to Gunicorn/FPM
location / {
proxy_pass http://unix:/path/to/your/gunicorn.sock; # Or your FPM socket/host
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;
proxy_read_timeout 300s; # Increase for long-running requests
proxy_connect_timeout 75s;
}
# ... other http configurations ...
}
Gunicorn Tuning for Python Applications on OVH
When deploying Python web applications (like those powering Shopify customizations or backend services) on OVH, Gunicorn is a popular choice. Tuning its worker count and type is critical for performance and stability.
Worker Processes and Threads
Gunicorn’s --workers setting is the most impactful. A common recommendation is (2 * CPU_CORES) + 1. For example, on a 4-core OVH instance, you might start with 9 workers. The --threads option allows for multi-threading within each worker process. If your application is I/O bound (e.g., making many external API calls or database queries), using threads can improve concurrency. However, for CPU-bound tasks, threads might not offer significant benefits due to Python’s Global Interpreter Lock (GIL).
Worker Types
Gunicorn supports several worker types:
sync: The default, synchronous worker. Simple but can block under heavy load.eventletandgevent: Asynchronous workers that use green threads. Excellent for I/O-bound applications, allowing a single worker to handle many concurrent connections efficiently.tornado: Another asynchronous worker, suitable for high-concurrency I/O-bound applications.
For most modern web applications, especially those interacting with external services or databases, gevent or eventlet are often preferred for their ability to handle many concurrent requests without blocking.
Timeout and Graceful Shutdown
The --timeout setting defines how long Gunicorn will wait for a worker to respond before considering it dead. For long-running tasks, this needs to be increased. --graceful-timeout is used during reloads to allow existing requests to complete.
Example Gunicorn Command Line
This command launches Gunicorn with 9 workers (for a hypothetical 4-core instance), using the gevent worker type, and sets appropriate timeouts. It binds to a Unix socket, which Nginx will proxy to.
gunicorn --workers 9 \
--worker-class gevent \
--bind unix:/path/to/your/gunicorn.sock \
--timeout 120 \
--graceful-timeout 120 \
--log-level info \
your_project.wsgi:application
PHP-FPM Tuning for PHP Applications on OVH
If your Shopify store utilizes PHP for backend logic or custom modules, tuning PHP-FPM (FastCGI Process Manager) is essential. OVH instances running PHP will benefit from these optimizations.
Process Management Strategies
PHP-FPM offers three primary process management strategies:
static: Pre-spawns a fixed number of child processes. Good for predictable loads.dynamic: Spawns processes as needed, up to a defined maximum. Offers flexibility but can have overhead.ondemand: Spawns processes only when a request arrives. Minimal resource usage when idle, but can introduce latency on the first request.
For high-traffic sites, dynamic is often a good balance. You’ll configure pm.max_children (maximum number of active processes), pm.start_servers (number of processes started on boot), pm.min_spare_servers (minimum number of idle processes), and pm.max_spare_servers (maximum number of idle processes).
Tuning Dynamic Settings
A common starting point for dynamic mode on a multi-core OVH server:
pm.max_children: This is the most critical. Calculate based on available RAM. Each PHP-FPM process consumes memory. A rough estimate is (Total RAM - RAM for OS/Nginx/DB) / Average Process Memory Usage. Start conservatively and monitor.
pm.start_servers: Typically set to pm.min_spare_servers + (pm.max_spare_servers - pm.min_spare_servers) / 2.
pm.min_spare_servers: 5
pm.max_spare_servers: 10
pm.max_requests: Set to a value like 500 or 1000. This tells FPM to respawn a child process after it has handled a certain number of requests, helping to prevent memory leaks.
Example PHP-FPM Pool Configuration
This configuration is for a pool file, typically located at /etc/php/X.Y/fpm/pool.d/www.conf (replace X.Y with your PHP version). Adjust values based on your OVH instance’s resources and observed performance.
; /etc/php/X.Y/fpm/pool.d/www.conf [www] user = www-data group = www-data listen = /run/php/phpX.Y-fpm.sock ; Or a TCP/IP socket like 127.0.0.1:9000 listen.owner = www-data listen.group = www-data listen.mode = 0660 pm = dynamic pm.max_children = 150 ; Adjust based on RAM and typical process size pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 20 pm.max_requests = 1000 ; Respawn after this many requests request_terminate_timeout = 120s ; Match Nginx proxy_read_timeout if needed ; request_slowlog_timeout = 10s ; Uncomment to log slow requests ; slowlog = /var/log/php/phpX.Y-fpm-slow.log ; Other useful settings: ; pm.process_idle_timeout = 10s ; For 'ondemand' ; pm.max_children_reached_notify_method = notify ; For 'dynamic'
MongoDB Performance Tuning on OVH
MongoDB is a common choice for storing application data. Optimizing its performance on OVH involves careful configuration of memory usage, journaling, and indexing.
WiredTiger Storage Engine
Modern MongoDB versions use the WiredTiger storage engine. Its performance is heavily influenced by the storage.wiredTiger.engineConfig.cacheSizeGB setting. This should be set to a significant portion of your available RAM, typically 50-75%, leaving enough for the OS and other services.
Journaling and Durability
Journaling (storage.journal.enabled: true) is enabled by default and crucial for data durability. While it adds some write overhead, it’s essential for preventing data loss in case of crashes. For extremely high write throughput scenarios where some risk is acceptable, it *could* be disabled, but this is rarely recommended for production Shopify stores.
Indexing Strategy
The most significant performance gains in MongoDB often come from proper indexing. Analyze your application’s query patterns and create indexes accordingly. Use db.collection.explain("executionStats").find({...}) to understand query performance and identify missing indexes. Avoid over-indexing, as indexes consume memory and slow down writes.
Connection Pooling
Ensure your application is using connection pooling to MongoDB. Re-establishing connections is expensive. Libraries like Mongoose (Node.js) or PyMongo (Python) handle this automatically, but verify the pool size is adequate for your expected concurrency.
Example MongoDB Configuration Snippet
This snippet shows key settings in MongoDB’s mongod.conf file. Adjust cacheSizeGB based on your OVH instance’s RAM.
# /etc/mongod.conf
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 4 # Example: For an 8GB RAM instance, leaving 4GB for OS/other services
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1 # Or the specific IP(s) your application connects from
# logging:
# path: /var/log/mongodb/mongod.log
# systemLogRoll:
# sizeThresholdMB: 256
# timeThresholdMin: 60
# processManagement:
# fork: true
# pidFilePath: /var/run/mongodb/mongod.pid
# timeZoneInfo: Etc/UTC
Monitoring and Iterative Tuning
Performance tuning is not a one-time task. Continuously monitor your OVH infrastructure using tools like Prometheus, Grafana, Datadog, or even basic system utilities (top, htop, iostat, vmstat). Pay close attention to:
- CPU Utilization
- Memory Usage (especially swap usage)
- Network I/O
- Disk I/O
- Application Response Times
- Database Query Latency
- Nginx/PHP-FPM/Gunicorn worker status
Make incremental changes, monitor the impact, and iterate. Understanding your specific traffic patterns and application bottlenecks is key to achieving optimal performance on OVH for your Shopify deployment.