• 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 » The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MySQL on OVH for Ruby

The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MySQL on OVH for Ruby

OVH Infrastructure Deep Dive: Nginx, Gunicorn/FPM, and MySQL Tuning for Ruby Applications

This playbook focuses on optimizing a typical Ruby web application stack deployed on OVH infrastructure. We’ll cover granular tuning of Nginx, the chosen application server (Gunicorn for Python-based apps or PHP-FPM for PHP), and MySQL, emphasizing production-ready configurations and diagnostic techniques.

Nginx Configuration for High Throughput and Low Latency

Nginx acts as the front-line web server and reverse proxy. Optimizing its worker processes, connection handling, and caching is crucial. We’ll assume a typical OVH VPS or dedicated server with multiple CPU cores.

Worker Processes and Connections

The `worker_processes` directive should generally be set to the number of CPU cores available. `worker_connections` 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 observed load and system limits.

Tuning `ulimit`

Before adjusting Nginx, ensure the operating system’s file descriptor limits are sufficient. Edit `/etc/security/limits.conf` or create a file in `/etc/security/limits.d/`.

Example `limits.conf` Snippet

# /etc/security/limits.d/99-nginx.conf
* soft nofile 65536
* hard nofile 65536
root soft nofile 65536
root hard nofile 65536
nginx soft nofile 65536
nginx hard nofile 65536

After modifying limits, you’ll need to restart the Nginx service or, for systemd, reload the daemon and restart Nginx.

Nginx `nginx.conf` Snippet

# /etc/nginx/nginx.conf

user www-data; # Or the user Nginx runs as
worker_processes auto; # Or set to the number of CPU cores, e.g., 4
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 4096; # Increased from default 1024
    multi_accept on;
    use epoll; # Linux specific, highly recommended
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    server_tokens off; # Hide Nginx version for security

    # Gzip compression for static assets and API responses
    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;

    # Buffers and timeouts
    client_body_buffer_size 10K;
    client_header_buffer_size 1K;
    large_client_header_buffers 2 4K;
    client_max_body_size 100M; # Adjust as needed for uploads
    send_timeout 300s;
    read_timeout 300s;
    proxy_connect_timeout 75s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    proxy_buffer_size 16k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;

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

Optimizing for Ruby Applications (via Gunicorn/Puma or PHP-FPM)

When proxying to application servers like Gunicorn (for Python/Ruby frameworks like Flask/Rails if using WSGI) or Puma (common for Ruby), tune the upstream connection settings. For PHP applications using PHP-FPM, Nginx configuration is more about passing requests efficiently.

Nginx Proxy Configuration Snippet

# Inside your server block for the Ruby app

location / {
    proxy_pass http://your_app_backend; # e.g., http://127.0.0.1:8000 for Gunicorn
    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;

    # For long-running requests or WebSocket support
    proxy_read_timeout 300s;
    proxy_connect_timeout 75s;
    proxy_send_timeout 300s;

    # For WebSocket support (if applicable)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

# For static files served directly by Nginx
location ~ ^/(assets|images|javascripts|css|fonts)/ {
    root /path/to/your/public/directory; # e.g., /var/www/your_app/public
    expires 30d;
    add_header Cache-Control "public";
    access_log off;
}

Caching Strategies

Leverage Nginx’s caching capabilities for static assets and even dynamic content if appropriate. For dynamic content, consider using `proxy_cache` with appropriate keys and expiration times.

Example `proxy_cache` Configuration

# In http block of nginx.conf
proxy_cache_path /var/cache/nginx/my_app levels=1:2 keys_zone=my_app_cache:10m inactive=60m max_size=1g;

# Inside your server block
location / {
    proxy_pass http://your_app_backend;
    # ... other proxy settings ...

    proxy_cache my_app_cache;
    proxy_cache_valid 200 302 10m; # Cache 200 and 302 responses for 10 minutes
    proxy_cache_valid 404 1m;      # Cache 404 responses for 1 minute
    proxy_cache_key "$scheme$request_method$host$request_uri";
    add_header X-Cache-Status $upstream_cache_status; # Useful for debugging
}

Application Server Tuning: Gunicorn (for Python/Ruby) or PHP-FPM

The application server is where your Ruby code executes. Tuning its worker processes, threads, and memory usage is critical for handling concurrent requests efficiently.

Gunicorn Tuning (Common for WSGI/ASGI Apps)

Gunicorn is often used for Python applications but can also serve Ruby applications via WSGI interfaces. The key is balancing worker processes and threads.

Gunicorn Command Line/Configuration

# Example command line for Gunicorn
# Assuming a Ruby app served via a WSGI interface (e.g., Rack)
# For a typical Rails app, you'd use Puma or Unicorn directly, not Gunicorn.
# This example is more illustrative for Python/WSGI apps.

# For a Python app (e.g., Flask, Django)
gunicorn --workers 3 --threads 2 --bind 127.0.0.1:8000 myapp.wsgi:application

# --workers: Number of worker processes. A common starting point is (2 * num_cores) + 1.
# --threads: Number of threads per worker. Useful for I/O bound tasks.
# --bind: Address and port to bind to.
# --timeout: Request timeout in seconds.
# --worker-connections: For event-driven workers (like gevent/asyncio).

# Using a Gunicorn configuration file (e.g., gunicorn_config.py)
# workers = 3
# threads = 2
# bind = "127.0.0.1:8000"
# timeout = 120
# worker_class = "sync" # or "gevent", "eventlet", "asyncio"

Note: For Ruby on Rails, Puma or Unicorn are the standard application servers. The tuning principles (workers, threads, memory) remain similar, but the specific directives will differ.

PHP-FPM Tuning (for PHP Applications)

PHP-FPM (FastCGI Process Manager) is the de facto standard for serving PHP. Tuning its process management is crucial.

PHP-FPM Configuration (`php-fpm.conf` or pool configuration files)

; /etc/php/X.Y/fpm/pool.d/www.conf (Replace X.Y with your PHP version)

; Process Manager Settings
; pm = dynamic | static | ondemand
pm = dynamic

; If pm = dynamic:
pm.max_children = 50       ; Max number of children at any one time.
pm.start_servers = 5       ; Number of servers started when FPM starts.
pm.min_spare_servers = 2   ; Number of servers to maintain in low-speed environment.
pm.max_spare_servers = 10  ; Number of servers to maintain in high-speed environment.
pm.max_requests = 500      ; Max number of requests each child process should serve.

; If pm = static:
; pm.static.max_children = 50 ; Fixed number of children.

; If pm = ondemand:
; pm.max_children = 50
; pm.start_time = '00:00:00' ; Time to start workers
; pm.min_spare_starts = 1
; pm.max_spare_starts = 3

; Other important settings
request_terminate_timeout = 120s ; Timeout for script execution
; listen.owner = www-data
; listen.group = www-data
; listen.mode = 0660
; listen = /run/php/phpX.Y-fpm.sock ; For Unix socket (recommended for performance)
; listen = 127.0.0.1:9000 ; For TCP socket

Tuning `pm.max_children`: This is the most critical setting. It should be calculated based on available RAM. A rough estimate: `max_children = (Total RAM – RAM for OS/Nginx/MySQL) / Average RAM per PHP process`. Monitor memory usage and adjust.

MySQL Performance Tuning on OVH

Database performance is often the bottleneck. Tuning MySQL’s configuration file (`my.cnf` or `mysqld.cnf`) is essential. OVH often provides managed MySQL instances; if so, some parameters might be managed by OVH, but understanding them is still vital.

Key `my.cnf` Parameters

# /etc/mysql/my.cnf or /etc/mysql/mysql.conf.d/mysqld.cnf

[mysqld]
# General Settings
user                    = mysql
pid-file                = /var/run/mysqld/mysqld.pid
socket                  = /var/run/mysqld/mysqld.sock
port                    = 3306
basedir                 = /usr
datadir                 = /var/lib/mysql
tmpdir                  = /tmp
lc_messages_dir         = /usr/share/mysql
lc_messages             = en
skip-external-locking

# Performance Tuning
# InnoDB is the default and recommended engine
default_storage_engine  = InnoDB

# Buffer Pool Size: Crucial for InnoDB performance. Aim for 50-75% of available RAM on a dedicated DB server.
innodb_buffer_pool_size = 4G  # Example: For a server with 8GB RAM

# Log File Size: Affects recovery time and performance.
innodb_log_file_size    = 512M # Adjust based on write load. Larger can improve write performance but increase recovery time.
innodb_log_buffer_size  = 16M

# I/O and Threading
innodb_flush_log_at_trx_commit = 1 # ACID compliant, but can be slower. 2 offers better performance with minimal risk. 0 is fastest but risky.
innodb_flush_method     = O_DIRECT # Recommended for Linux with hardware RAID or SSDs.
innodb_io_capacity      = 2000 # For SSDs, can be higher. Adjust based on disk speed.
innodb_thread_concurrency = 0 # 0 means unlimited, let MySQL decide. Can be set to number of cores.

# Query Cache (Deprecated in MySQL 5.7, removed in 8.0. Use application-level caching instead.)
# query_cache_type        = 0
# query_cache_size        = 0

# Connection Handling
max_connections         = 200  # Adjust based on application needs and server resources.
max_user_connections    = 150  # Limit per user if needed.
wait_timeout            = 600  # Close idle connections after 10 minutes.
interactive_timeout     = 600

# Temporary Tables
tmp_table_size          = 64M
max_heap_table_size     = 64M

# Sort Buffers
sort_buffer_size        = 2M
read_rnd_buffer_size    = 2M
read_buffer_size        = 1M
join_buffer_size        = 2M

# Table Cache
table_open_cache        = 2000
table_definition_cache  = 1000

# Other
thread_cache_size       = 16
key_buffer_size         = 16M # Primarily for MyISAM, less critical if using InnoDB exclusively.

Important Considerations for OVH:

  • RAM Allocation: The `innodb_buffer_pool_size` is paramount. Ensure you leave enough RAM for the OS, Nginx, and application servers. Monitor RAM usage closely using `htop` or `free -m`.
  • Disk I/O: OVH offers various storage options (SATA, SSD, NVMe). Tune `innodb_io_capacity` and `innodb_flush_method` accordingly. SSDs generally benefit from `O_DIRECT` and higher `innodb_io_capacity`.
  • Managed Databases: If using OVH’s managed MySQL, consult their documentation. Some parameters may be pre-configured or inaccessible. Focus on application-level query optimization and connection pooling.
  • Replication/Clustering: For high availability, ensure replication is configured correctly and monitor replication lag.

Monitoring and Diagnostics

Regular monitoring is key to identifying performance bottlenecks. Use a combination of system tools and database-specific commands.

System Monitoring

  • `htop` / `top`: Monitor CPU, memory, and process usage. Identify runaway processes.
  • `iotop`: Monitor disk I/O per process.
  • `vmstat`: Provides system-wide statistics on processes, memory, paging, block I/O, traps, and CPU activity.
  • `netstat -tulnp`: Check listening ports and active connections.
  • Nginx `access.log` and `error.log`: Analyze request times, status codes, and errors.
  • PHP-FPM logs: Check for errors or slow script execution.

MySQL Monitoring

Connect to your MySQL server and run these commands:

-- Show current status variables
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_running';
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_wait_free'; -- Indicates buffer pool contention
SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_waits'; -- Indicates row lock contention

-- Show running queries
SHOW FULL PROCESSLIST;

-- Check for table locks (especially if not using InnoDB or for specific operations)
SHOW OPEN TABLES WHERE In_use > 0;

-- Analyze slow query log (if enabled in my.cnf)
-- The slow query log file is specified by 'slow_query_log_file' in my.cnf
-- Use tools like pt-query-digest (from Percona Toolkit) for detailed analysis.

Enabling the Slow Query Log:

# In my.cnf
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2  # Log queries taking longer than 2 seconds
log_queries_not_using_indexes = 1 # Optional: Log queries that don't use indexes

Conclusion

Tuning Nginx, your application server (Gunicorn/PHP-FPM), and MySQL is an iterative process. Start with these baseline configurations, monitor your application’s performance under load, and adjust parameters based on observed bottlenecks. Always test changes in a staging environment before deploying to production. For Ruby applications specifically, ensure you’re using the appropriate Ruby-native servers like Puma or Unicorn and tune them according to their documentation, applying similar principles of worker/thread management and memory allocation.

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

  • Go Goroutines vs. Node.js Event Loop: Scaling I/O-Bound Microservices Under High Load
  • Elixir Phoenix vs. Go Gin: Concurrency Models and Fault Tolerance Under Peak Request Volume
  • Python Celery vs. Go Channels: Distributed Task Queue Overhead and Memory Reliability
  • Scala Pekko vs. Go Goroutines: Actor Model vs. CSP for Event-Driven Reactive Systems
  • Java Loom Virtual Threads vs. Go Goroutines: Under-the-Hood Scheduler and Thread Overhead Comparison

Categories

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

Recent Posts

  • Go Goroutines vs. Node.js Event Loop: Scaling I/O-Bound Microservices Under High Load
  • Elixir Phoenix vs. Go Gin: Concurrency Models and Fault Tolerance Under Peak Request Volume
  • Python Celery vs. Go Channels: Distributed Task Queue Overhead and Memory Reliability

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (806)
  • Debugging & Troubleshooting (584)
  • Security & Compliance (543)
  • SEO & Growth (491)
  • Business & Monetization (390)

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