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

The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and PostgreSQL on OVH for Magento 2

Nginx Configuration Tuning for Magento 2

Optimizing Nginx is paramount for serving high-traffic Magento 2 instances. We’ll focus on key directives that directly impact performance and resource utilization, particularly within the context of an OVH VPS or dedicated server environment where direct control over the webserver is expected.

Worker Processes and Connections

The worker_processes directive determines how many worker processes Nginx will spawn. A common recommendation is to set this to the number of CPU cores available. For worker_connections, this defines the maximum number of simultaneous connections that each worker process can handle. The total number of connections is worker_processes * worker_connections. Ensure your system’s file descriptor limits are high enough to accommodate this.

Edit your main Nginx configuration file, typically located at /etc/nginx/nginx.conf:

user www-data;
worker_processes auto; # Or set to the number of CPU cores, e.g., worker_processes 4;

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

After modifying nginx.conf, test the configuration and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

Keepalive Timeout and Buffers

keepalive_timeout controls how long an idle HTTP connection will remain open. A lower value can free up resources faster, but too low can increase overhead for clients making frequent requests. client_body_buffer_size and client_header_buffer_size are crucial for handling large requests. Magento 2 can generate substantial POST requests, especially during checkout.

http {
    # ... other http directives ...

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 65; # Default is 65, consider reducing slightly if needed
    keepalive_requests 1000; # Maximum requests per keep-alive connection

    client_body_buffer_size 128k; # Default is 8k, increase for large POSTs
    client_header_buffer_size 128k; # Default is 1k, increase for large headers
    large_client_header_buffers 4 128k; # For very large headers

    # ... other http directives ...
}

Gzip Compression

Enabling Gzip compression significantly reduces the size of transferred data, leading to faster page load times. Ensure it’s configured appropriately for static assets and dynamic content.

http {
    # ...

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6; # Compression level (1-9)
    gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
    gzip_min_length 1000; # Minimum response length to compress

    # ...
}

Caching Strategies

Leverage Nginx’s ability to cache static assets. This offloads requests from your application server and database.

location ~* ^/(media|static)/ {
    expires 30d; # Cache for 30 days
    add_header Cache-Control "public, immutable";
    access_log off;
    log_not_found off;
}

For dynamic content, consider using Nginx’s FastCGI cache or proxy_cache if you’re not relying solely on Varnish or Redis for page caching. This is a more advanced topic and requires careful configuration to avoid cache invalidation issues with Magento 2.

Gunicorn/PHP-FPM Tuning

The choice between Gunicorn (for Python-based applications, though Magento 2 is PHP) and PHP-FPM depends on your specific setup. Assuming a standard PHP deployment for Magento 2, we’ll focus on PHP-FPM.

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 production, dynamic or static are generally preferred.

Edit your PHP-FPM pool configuration file, typically found in /etc/php/[version]/fpm/pool.d/www.conf (replace [version] with your PHP version, e.g., 8.1).

; Choose one of: static, dynamic, ondemand
pm = dynamic

; If dynamic, these settings are used:
pm.max_children = 50       ; Max number of children serving requests. Adjust based on RAM.
pm.start_servers = 5       ; Number of children created at start.
pm.min_spare_servers = 5   ; Number of children when idle.
pm.max_spare_servers = 10  ; Number of children when idle.
pm.max_requests = 500      ; Max requests per child process before respawning.

; If static, these settings are used:
; pm = static
; pm.max_children = 50     ; Fixed number of children.

; If ondemand, these settings are used:
; pm = ondemand
; pm.max_children = 50
; pm.min_spare_servers = 1
; pm.max_spare_servers = 3
; pm.process_idle_timeout = 10s
; pm.max_requests = 0

Tuning Considerations:

  • pm.max_children: This is the most critical setting. Too high, and you’ll run out of RAM. Too low, and requests will queue up. A good starting point is to monitor your server’s RAM usage under load and set this to a value that keeps RAM usage below 80-90%. Each PHP-FPM worker can consume 20-50MB of RAM or more, depending on Magento’s complexity and loaded extensions.
  • pm.max_requests: Setting this to a reasonable number helps prevent memory leaks from accumulating over time.

After changes, test and reload PHP-FPM:

sudo systemctl restart php[version]-fpm

PHP.ini Optimizations

Several PHP.ini settings directly impact Magento 2 performance.

; In your php.ini file (e.g., /etc/php/[version]/fpm/php.ini)

memory_limit = 512M       ; Increase for Magento's memory needs
max_execution_time = 180  ; Allow longer execution for complex tasks
upload_max_filesize = 64M ; Adjust as needed for media uploads
post_max_size = 64M       ; Must be >= upload_max_filesize
max_input_vars = 3000     ; Crucial for Magento's form processing
opcache.enable = 1
opcache.memory_consumption = 128 ; MB, adjust based on your code size
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60 ; Check for file updates every 60 seconds
opcache.validate_timestamps = 1 ; Set to 0 in production for max performance, but requires manual cache clearing on deploy.
opcache.enable_cli = 1

Remember to restart PHP-FPM after modifying php.ini.

PostgreSQL Tuning for Magento 2

PostgreSQL is the default database for Magento 2. Optimizing its configuration is critical for database-intensive operations common in e-commerce.

Shared Buffers and WAL Settings

shared_buffers is the most important parameter, determining how much memory PostgreSQL uses for caching data. A common recommendation is 25% of your total system RAM, but this can be adjusted based on your server’s RAM and workload.

Write-Ahead Logging (WAL) settings are crucial for data integrity and performance. Tuning wal_buffers and checkpoint_segments (or max_wal_size in newer versions) can improve write performance.

Edit your postgresql.conf file (location varies by OS and version, e.g., /etc/postgresql/[version]/main/postgresql.conf).

# Example for a server with 16GB RAM
shared_buffers = 4GB       ; 25% of 16GB
effective_cache_size = 12GB ; ~75% of RAM, helps query planner

# WAL settings
wal_buffers = 16MB         ; Default is 3MB, increase for busy systems
wal_writer_delay = 200ms   ; Default is 200ms, can be tuned
max_wal_size = 4GB         ; For PostgreSQL 9.5+, replaces checkpoint_segments
checkpoint_timeout = 15min ; For PostgreSQL 9.5+, default is 5min
checkpoint_completion_target = 0.9 ; Default is 0.5, helps spread I/O

# Other important settings
work_mem = 32MB            ; Memory for internal sort operations and hash tables
maintenance_work_mem = 256MB ; Memory for VACUUM, CREATE INDEX, etc.
random_page_cost = 1.1     ; Default is 4.0, tune for SSDs
seq_page_cost = 1.0        ; Default is 1.0
effective_io_concurrency = 200 ; For SSDs, tune based on IOPS
default_statistics_target = 100 ; For better query planning

After modifying postgresql.conf, restart the PostgreSQL service:

sudo systemctl restart postgresql

Connection Pooling

Magento 2 can open many database connections. Using a connection pooler like PgBouncer can significantly reduce overhead and improve performance by managing a pool of persistent connections to PostgreSQL.

Install PgBouncer (e.g., sudo apt install pgbouncer) and configure its pgbouncer.ini file (typically in /etc/pgbouncer/).

[databases]
pgbouncer = host=127.0.0.1 port=5432 dbname=your_magento_db

[pgbouncer]
; Connection pooling mode: session, transaction, or statement
; 'transaction' is generally recommended for Magento 2
pool_mode = transaction

; Maximum number of clients that can connect to pgbouncer
max_client_conn = 1000

; Maximum number of server connections per database
default_pool_size = 20

; Minimum number of server connections per database
min_pool_size = 5

; Maximum number of server connections per database when pool_mode is 'transaction'
; This is crucial for Magento 2. A common recommendation is 10-20 per worker process.
; If you have 50 PHP-FPM workers, and each can potentially open a connection,
; you might set this to 500 or more, depending on your database server's capacity.
; For a default setup with 50 max_children, start with default_pool_size = 50, max_db_connections = 100
max_db_connections = 500

; Authentication method (e.g., md5, scram-sha-256)
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt

; Log settings
logfile = /var/log/pgbouncer/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid

Create the userlist.txt file with your database credentials:

"your_magento_db" "your_db_user" "md5your_db_password_hash"

Start and enable PgBouncer:

sudo systemctl start pgbouncer
sudo systemctl enable pgbouncer

Ensure your Magento 2 app/etc/env.php is configured to connect to PgBouncer instead of directly to PostgreSQL:

return [
    // ... other config ...
    'db' => [
        'connection' => [
            'host' => '127.0.0.1', // Connect to PgBouncer
            'dbname' => 'your_magento_db',
            'username' => 'your_db_user',
            'password' => 'your_db_password',
            'model' => 'mysqlImproved', // Or appropriate model
            'port' => 6432, // PgBouncer's default port
            'initStatements' => 'SET NAMES utf8;',
            'driver_options' => [
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
            ]
        ],
        // ... other db config ...
    ],
    // ... other config ...
];

Monitoring and Iteration

Performance tuning is an iterative process. Continuously monitor your server’s resource utilization (CPU, RAM, I/O, network) using tools like htop, vmstat, iostat, and PostgreSQL’s pg_stat_activity. Use Magento’s built-in profiling tools and external APM solutions to identify bottlenecks. Adjust these configurations based on observed performance metrics and load testing. Remember to clear Magento’s cache (bin/magento cache:clean and bin/magento cache:flush) after significant configuration changes.

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