• 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 Linode for WooCommerce

The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and PostgreSQL on Linode for WooCommerce

Nginx Configuration for WooCommerce High Traffic

Optimizing Nginx is paramount for serving static assets, handling SSL termination, and acting as a reverse proxy for your PHP application server. For a WooCommerce site, efficient static file serving and robust connection management are key.

We’ll focus on tuning worker_processes, worker_connections, and enabling Gzip compression. For a Linode instance, setting worker_processes to the number of CPU cores is a good starting point. worker_connections dictates how many simultaneous connections each worker process can handle; a value of 1024 or higher is typical for production.

Core Nginx Tuning Directives

Edit your nginx.conf file, typically located at /etc/nginx/nginx.conf or within /etc/nginx/conf.d/. Ensure these directives are set within the http block.

# Determine the number of CPU cores available
# For example, if you have 4 cores, set worker_processes to 4
worker_processes 4;

events {
    # Maximum number of simultaneous connections per worker process
    worker_connections 4096;
    # Use epoll for Linux, kqueue for BSD/macOS
    use epoll;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    # Enable Gzip compression for text-based assets
    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;

    # Keepalive timeout for persistent connections
    keepalive_timeout 65;

    # Enable sendfile for efficient file transfer
    sendfile on;
    # Adjust tcp_nopush and tcp_nodelay for performance
    tcp_nopush on;
    tcp_nodelay on;

    # Buffering settings
    client_body_buffer_size 10K;
    client_max_body_size 20m; # Adjust based on WooCommerce upload needs
    client_header_buffer_size 1K;
    large_client_header_buffers 4 8K;

    # Timeout settings
    client_header_timeout 10;
    client_body_timeout 10;
    send_timeout 10;
    lingering_close off;
    lingering_time 30;

    # Server block for your WooCommerce site
    server {
        listen 80;
        server_name your_domain.com www.your_domain.com;
        # Redirect HTTP to HTTPS
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name your_domain.com www.your_domain.com;

        # SSL Configuration (replace with your actual cert paths)
        ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
        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;
        ssl_session_timeout 10m;
        ssl_session_tickets off;

        # Static file caching
        location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
            expires 30d;
            add_header Cache-Control "public, no-transform";
            access_log off;
        }

        # Proxy to your PHP application server (Gunicorn/FPM)
        location / {
            proxy_pass http://unix:/var/run/php/php7.4-fpm.sock; # Or your Gunicorn socket
            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 timeout for potentially long WooCommerce requests
            proxy_connect_timeout 75s;
        }

        # Deny access to hidden files
        location ~ /\. {
            deny all;
        }
    }
}

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

sudo nginx -t
sudo systemctl reload nginx

Gunicorn/PHP-FPM Tuning for WooCommerce

The choice between Gunicorn (for Python/Django/Flask) and PHP-FPM (for PHP/WordPress/WooCommerce) dictates the tuning strategy. We’ll cover both.

PHP-FPM Tuning (for WordPress/WooCommerce)

PHP-FPM’s performance is heavily influenced by its process manager settings. The pm (process manager) can be set to dynamic, static, or ondemand. For a busy WooCommerce site, dynamic or static are generally preferred.

Edit your PHP-FPM pool configuration file, typically found at /etc/php/X.Y/fpm/pool.d/www.conf (replace X.Y with your PHP version, e.g., 7.4).

; Example for pm = dynamic
pm = dynamic
pm.max_children = 100       ; Max number of children serving requests
pm.start_servers = 10       ; Number of children when pool starts
pm.min_spare_servers = 5    ; Min number of idle resp. to keep
pm.max_spare_servers = 20   ; Max number of idle resp. to keep
pm.process_idle_timeout = 10s ; Timeout for idle processes

; Example for pm = static
; pm = static
; pm.max_children = 150     ; Fixed number of children

; Adjust request_terminate_timeout for long-running WooCommerce tasks
request_terminate_timeout = 300s

; Adjust listen socket (ensure it matches Nginx config)
listen = /var/run/php/php7.4-fpm.sock
; listen.owner = www-data
; listen.group = www-data
; listen.mode = 0660

; Adjust memory limit if necessary for heavy plugins/themes
; memory_limit = 256M

After changes, reload PHP-FPM:

sudo systemctl reload php7.4-fpm

Gunicorn Tuning (for Python Apps)

Gunicorn’s worker count and type are critical. For CPU-bound tasks, use sync workers. For I/O-bound tasks, gevent or event workers are more efficient. A common starting point for workers is (2 * number_of_cores) + 1.

You can configure Gunicorn via command-line arguments or a configuration file.

# Example command-line invocation
gunicorn --workers 5 \
         --worker-class gevent \
         --bind unix:/path/to/your/app.sock \
         --timeout 300 \
         your_app.wsgi:application

Or, create a gunicorn.conf.py file:

import multiprocessing

bind = "unix:/path/to/your/app.sock"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "gevent" # or "sync", "event"
timeout = 300
loglevel = "info"
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"

Ensure your Nginx proxy_pass directive points to the correct Gunicorn socket path.

PostgreSQL Performance Tuning for WooCommerce

PostgreSQL is the backbone of WooCommerce data. Optimizing its configuration, particularly memory allocation and query planning, can yield significant performance gains.

Key PostgreSQL Configuration Parameters

The primary configuration file is postgresql.conf, usually located in /etc/postgresql/X.Y/main/. Always back up this file before making changes.

# Shared Memory Buffers
# Aim for 15-25% of total system RAM. For a 4GB Linode, start with 1GB.
shared_buffers = 1GB

# Write-Ahead Log (WAL) Buffers
# Typically 1/4 of shared_buffers, but not excessively large.
wal_buffers = 16MB

# Effective Cache Size
# Estimate of how much memory is available for disk caching by the OS and PostgreSQL.
# Set to 50-75% of total RAM.
effective_cache_size = 3GB

# Maintenance Work Memory
# Used for VACUUM, CREATE INDEX, ALTER TABLE. Larger values speed up maintenance.
maintenance_work_mem = 256MB

# Work Memory
# Used for sorting and hashing operations. Adjust based on query complexity.
# Start with a moderate value and monitor.
work_mem = 16MB

# Checkpointing
# Controls how often WAL is flushed to disk. More frequent checkpoints reduce recovery time but increase I/O.
max_wal_size = 1GB
min_wal_size = 128MB
checkpoint_completion_target = 0.9

# Connection Pooling (if using pgBouncer or similar)
# max_connections = 100 # Adjust based on your application's needs and server resources

# Autovacuum settings (crucial for preventing table bloat)
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 15s
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
autovacuum_vacuum_scale_factor = 0.1
autovacuum_analyze_scale_factor = 0.05

# Logging (essential for diagnostics)
log_destination = 'stderr'
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_min_duration_statement = 1000 # Log statements longer than 1 second
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 0 # Log temp files larger than 0 bytes
log_autovacuum_min_duration = 0 # Log all autovacuum actions

After modifying postgresql.conf, restart the PostgreSQL service:

sudo systemctl restart postgresql

Query Optimization and Indexing

Regularly analyze slow queries using PostgreSQL’s logging. WooCommerce can generate complex queries, especially around product searches, order processing, and reporting.

Use EXPLAIN ANALYZE to understand query execution plans. Identify missing indexes or inefficient joins.

-- Example: Analyze a slow query
EXPLAIN ANALYZE SELECT * FROM wp_posts WHERE post_type = 'product' AND post_status = 'publish';

-- Example: Add an index to speed up product queries
CREATE INDEX idx_posts_type_status ON wp_posts (post_type, post_status);

-- Example: Analyze order status queries
EXPLAIN ANALYZE SELECT * FROM wp_posts WHERE post_type = 'shop_order' AND post_status = 'wc-processing';

-- Consider indexing custom fields or meta data if frequently queried
-- CREATE INDEX idx_postmeta_key_value ON wp_postmeta (meta_key, meta_value); -- Use with caution, can be large

For WooCommerce, specific tables like wp_posts, wp_postmeta, wp_options, and order-related tables are critical. Monitor their growth and fragmentation.

System-Level Monitoring and Diagnostics

Effective monitoring is crucial for identifying bottlenecks and validating tuning efforts. Use tools like htop, iotop, netstat, and PostgreSQL’s built-in statistics.

Key Monitoring Commands

  • CPU Usage: htop or top. Look for consistently high CPU usage on Nginx workers, PHP-FPM processes, or PostgreSQL.
  • Memory Usage: htop or free -h. Monitor for swapping, which indicates insufficient RAM.
  • Disk I/O: iotop (requires root). Identify processes heavily utilizing disk, often PostgreSQL or Nginx if caching is misconfigured.
  • Network Connections: netstat -tulnp. Check listening ports and active connections.
  • Nginx Status: Enable the stub_status module in Nginx to monitor active connections, requests, and read/write rates.
# Add to your Nginx http block or a specific server block
location /nginx_status {
    stub_status;
    allow 127.0.0.1; # Restrict access
    deny all;
}

Access this status page via http://your_domain.com/nginx_status (if allowed). You’ll see metrics like Active connections, accepts, handled, and requests.

PostgreSQL Statistics:

-- Check active queries
SELECT pid, age(clock_timestamp(), query_start), usename, query
FROM pg_stat_activity
WHERE state != 'idle' AND query NOT LIKE '%pg_stat_activity%'
ORDER BY query_start;

-- Check database cache hit ratio
SELECT
    datname,
    pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(datname)) AS size,
    blks_read,
    blks_hit,
    CASE WHEN blks_hit + blks_read = 0 THEN 0 ELSE round(cr.blks_hit / (cr.blks_hit + cr.blks_read) * 100.0) END AS hit_ratio
FROM pg_catalog.pg_database d
JOIN (
    SELECT
        refname,
        sum(blks_read) as blks_read,
        sum(blks_hit) as blks_hit
    FROM pg_statio_user_tables
    GROUP BY refname
) cr ON d.datname = cr.refname
ORDER BY hit_ratio DESC;

A cache hit ratio below 95% for your WooCommerce database might indicate insufficient shared_buffers or effective caching strategies.

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