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

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

Nginx Configuration for High-Traffic WooCommerce

Optimizing Nginx is paramount for serving static assets efficiently and acting as a robust reverse proxy for your WooCommerce application. For high-traffic scenarios, we’ll focus on connection handling, caching, and security headers.

Tuning Worker Processes and Connections

The worker_processes directive should ideally be set to the number of CPU cores available on your server. This allows Nginx to effectively utilize all available processing power. 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.

Example nginx.conf Snippet

worker_processes auto; # Set to the number of CPU cores or 'auto'
events {
    worker_connections 4096; # Adjust based on RAM and load
    multi_accept on;
    use epoll; # For Linux systems
}

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

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

    # Gzip compression for dynamic and static content
    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 ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # ... other http configurations ...
}

Reverse Proxy Configuration for Gunicorn/FPM

When Nginx acts as a reverse proxy, it forwards requests to your application server (e.g., Gunicorn for Python/Django/Flask, or PHP-FPM for PHP). Proper proxy settings are crucial for performance and error handling.

Example Server Block (for Gunicorn/Python)

server {
    listen 80;
    server_name your_domain.com www.your_domain.com;

    location /static/ {
        alias /path/to/your/project/static/;
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    location /media/ {
        alias /path/to/your/project/media/;
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    location / {
        proxy_pass http://unix:/path/to/your/gunicorn.sock; # Or http://127.0.0.1:8000;
        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_connect_timeout 75s;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }

    # Optional: SSL configuration
    # listen 443 ssl http2;
    # ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    # ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
    # include /etc/letsencrypt/options-ssl-nginx.conf;
    # ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

Example Server Block (for PHP-FPM/WooCommerce)

server {
    listen 80;
    server_name your_domain.com www.your_domain.com;
    root /var/www/html/your_woocommerce_directory; # Path to your WooCommerce installation
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # Use the correct PHP-FPM socket or IP:Port
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust PHP version as needed
        # fastcgi_pass 127.0.0.1:9000; # Alternative if using TCP/IP
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_read_timeout 300; # Increase timeout for long-running PHP scripts
    }

    # Deny access to sensitive files
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }

    location ~ /\.ht {
        deny all;
    }

    # Caching for static assets (if not handled by PHP)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # Optional: SSL configuration
    # listen 443 ssl http2;
    # ... SSL directives as above ...
}

Gunicorn/PHP-FPM Tuning for Performance

The application server is where your actual PHP or Python code executes. Tuning Gunicorn (for Python) or PHP-FPM (for PHP) directly impacts response times and resource utilization.

Gunicorn Configuration (Python)

Gunicorn’s performance is heavily influenced by the number of worker processes and the worker type. For CPU-bound tasks, a synchronous worker (like sync or gevent with monkey patching) is often suitable. For I/O-bound tasks, asynchronous workers (like asyncio or gevent without monkey patching) can be more efficient. The number of workers is typically set to (2 * number_of_cores) + 1.

Example Gunicorn Command Line

gunicorn --workers 5 \
         --worker-class gevent \
         --bind unix:/path/to/your/gunicorn.sock \
         --timeout 300 \
         --log-level info \
         your_project.wsgi:application

Explanation:

  • --workers 5: Adjust based on your server’s CPU cores. A common formula is (2 * CPU_CORES) + 1.
  • --worker-class gevent: Choose an appropriate worker class. gevent is good for I/O-bound tasks.
  • --bind unix:/path/to/your/gunicorn.sock: Binding to a Unix socket is generally faster than TCP/IP for local communication.
  • --timeout 300: Increase timeout for potentially long-running WooCommerce operations (e.g., order processing, complex queries).
  • your_project.wsgi:application: Points to your Django/Flask application’s WSGI entry point.

PHP-FPM Configuration (PHP)

PHP-FPM has several pool configuration options that significantly affect performance. The key settings are related to process management (static, dynamic, ondemand) and the number of child processes.

Example php-fpm.conf (or pool configuration file)

[www]
user = www-data
group = www-data
listen = /var/run/php/php8.1-fpm.sock # Match this with your Nginx config
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 50      ; Max number of child processes at any time
pm.start_servers = 5      ; Number of processes started on boot
pm.min_spare_servers = 2  ; Min number of idle processes
pm.max_spare_servers = 10 ; Max number of idle processes
pm.process_idle_timeout = 10s ; How long an idle process stays alive

request_terminate_timeout = 120s ; Timeout for individual PHP scripts
request_slowlog_timeout = 30s    ; Log scripts exceeding this time
slowlog = /var/log/php/php-fpm/slow.log

; For high-traffic, consider tuning these further
; pm.max_requests = 500 ; Restart child processes after this many requests

Tuning Considerations:

  • pm: dynamic is a good balance. ondemand can save resources but might introduce latency on first requests. static is best for predictable, high-load environments but can waste resources if not sized correctly.
  • pm.max_children: This is the most critical setting. It should be high enough to handle peak load but not so high that it exhausts server RAM. Monitor memory usage closely. A common starting point is (total_RAM - Nginx_RAM - OS_RAM) / average_PHP_process_size.
  • pm.start_servers, pm.min_spare_servers, pm.max_spare_servers: These control how PHP-FPM scales dynamically. Adjust based on traffic patterns.
  • request_terminate_timeout: Crucial for preventing runaway scripts, but ensure it’s long enough for legitimate, complex WooCommerce operations.

PostgreSQL Tuning for WooCommerce

PostgreSQL is the backbone of WooCommerce data. Optimizing its configuration, particularly memory usage and query performance, is vital. We’ll focus on key parameters in postgresql.conf.

Key Configuration Parameters

These parameters are typically found in /etc/postgresql/[version]/main/postgresql.conf on Debian/Ubuntu systems.

Example postgresql.conf Snippets

# Memory settings
shared_buffers = 1GB             ; Typically 25% of total RAM, but can be up to 40% for dedicated DB servers.
                                 ; For a 4GB RAM server, start with 1GB.
work_mem = 32MB                  ; Memory for sorting and hash operations per query.
                                 ; Adjust based on complex queries. Can be higher if RAM allows.
maintenance_work_mem = 256MB     ; Memory for VACUUM, CREATE INDEX, etc.
                                 ; Higher values speed up maintenance tasks.

# Connection settings
max_connections = 100            ; Number of concurrent connections. Adjust based on application needs and server resources.
                                 ; Each connection consumes RAM.
                                 ; WooCommerce might open many connections.

# WAL (Write-Ahead Logging) settings for durability and performance
wal_level = replica              ; 'minimal' for single-node, 'replica' for replication.
wal_buffers = 16MB               ; Memory for WAL data before writing to disk.
min_wal_size = 1GB               ; Minimum size of WAL files.
max_wal_size = 4GB               ; Maximum size of WAL files. Adjust based on write load.
checkpoint_completion_time = 30s ; Spread checkpoints over time to reduce I/O spikes.

# Autovacuum tuning (essential for PostgreSQL performance)
autovacuum = on
autovacuum_max_workers = 3       ; Number of concurrent autovacuum workers.
autovacuum_naptime = 15s         ; How often to check for tasks.
autovacuum_vacuum_threshold = 50 ; Min number of row updates/deletes before vacuum.
autovacuum_analyze_threshold = 50; Min number of row inserts/updates/deletes before analyze.
vacuum_cost_delay = 10ms         ; Delay between cost-based vacuum operations.
                                 ; Lower values increase vacuum speed but also I/O.
                                 ; Consider tuning based on I/O capacity.

# Query planner settings
effective_cache_size = 2GB       ; Estimate of total memory available for caching by OS and PostgreSQL.
                                 ; Typically 50-75% of total RAM.
random_page_cost = 1.1           ; Lower value favors sequential scans, higher favors random.
                                 ; Default is 4.0. Adjust based on storage type (SSD vs HDD).
seq_page_cost = 1.0              ; Cost of sequential page fetch.

# Logging (for debugging and performance analysis)
log_destination = 'stderr'
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_statement = 'ddl'            ; Log Data Definition Language statements.
                                 ; Consider 'all' or 'mod' for debugging specific performance issues.
log_min_duration_statement = 250ms ; Log queries longer than this. Crucial for identifying slow queries.
log_autovacuum_min_duration = 10s  ; Log autovacuum actions longer than this.

Tuning Strategy:

  • Memory Allocation: Start with shared_buffers at 25% of RAM. Monitor usage and adjust. work_mem is per-operation, so be cautious with high values if max_connections is also high.
  • Autovacuum: This is critical. Ensure it’s enabled and tuned. WooCommerce generates a lot of data changes, so autovacuum needs to keep up to prevent table bloat and slow queries. Adjust thresholds and costs based on your workload.
  • Query Performance: Use log_min_duration_statement to identify slow queries. Analyze them with EXPLAIN ANALYZE. Ensure appropriate indexes are in place for WooCommerce tables (e.g., wp_posts, wp_postmeta, wp_wc_order_stats).
  • WAL: Tune max_wal_size and checkpoint_completion_time to balance write performance and I/O impact.

Indexing for WooCommerce Performance

Default WooCommerce installations might not have optimal indexes for all query patterns, especially under heavy load. Regularly analyze slow queries and add necessary indexes. Common areas include:

  • wp_posts and wp_postmeta: For product lookups, order retrieval, and general content queries.
  • wp_wc_order_stats: For order reporting and analytics.
  • wp_options: While often problematic, ensure critical options are cached.

Example SQL for Indexing

-- Example: Indexing for faster product searches by SKU
CREATE INDEX IF NOT EXISTS idx_posts_sku ON wp_posts (post_name) WHERE post_type = 'product';

-- Example: Indexing for faster order status lookups
CREATE INDEX IF NOT EXISTS idx_posts_order_status ON wp_posts (post_status) WHERE post_type = 'shop_order';

-- Example: Indexing for faster order meta lookups (e.g., customer ID)
CREATE INDEX IF NOT EXISTS idx_postmeta_customer_id ON wp_postmeta (meta_key, meta_value) WHERE meta_key = '_customer_user';

-- Analyze query performance and add indexes as needed
-- SELECT * FROM pg_stat_user_tables ORDER BY n_live_tup DESC LIMIT 10; -- Identify tables with high activity
-- SELECT * FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10; -- Identify slow queries

Monitoring and Iterative Tuning

Performance tuning is not a one-time task. Continuous monitoring and iterative adjustments are essential. Implement robust monitoring for:

  • Server Resources: CPU, RAM, Disk I/O, Network (e.g., using htop, iotop, Prometheus Node Exporter).
  • Nginx: Active connections, request rates, error logs (e.g., Nginx Amplify, Prometheus exporter).
  • Application Server (Gunicorn/PHP-FPM): Worker status, request latency, error rates.
  • Database: Query performance, connection counts, buffer cache hit ratio, vacuum activity, disk I/O (e.g., pg_stat_statements, Prometheus PostgreSQL exporter).
  • Application-Specific Metrics: WooCommerce order processing times, add-to-cart times, checkout success rates.

Use tools like Datadog, New Relic, Prometheus/Grafana, or DigitalOcean’s built-in monitoring to gain visibility. Regularly review logs and performance metrics to identify bottlenecks and make informed tuning decisions. Remember to test changes in a staging environment before deploying to production.

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

  • Step-by-Step: Diagnosing thread pools deadlock during concurrent ActiveRecord transaction processing on Linode Servers
  • Securing Your E-commerce APIs: Preventing SQL Injection (SQLi) in customized checkout queries in WooCommerce Implementations
  • Disaster Recovery 101: Architecting Auto-Failovers for MySQL and Ruby Deployments on Linode
  • High-Throughput Caching Strategies: Scaling MySQL for Perl Application APIs
  • Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and Laravel Deployments on DigitalOcean

Copyright © 2026 · Vinay Vengala