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

The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and MySQL on DigitalOcean for WordPress

Nginx as a High-Performance Frontend for WordPress

For WordPress deployments, Nginx excels as a reverse proxy and static file server. Its event-driven architecture handles high concurrency with minimal resource overhead. We’ll focus on tuning Nginx for optimal WordPress performance, particularly concerning caching and connection management.

Nginx Configuration for WordPress

The core of our Nginx tuning lies within its main configuration file (typically /etc/nginx/nginx.conf) and site-specific configurations (e.g., /etc/nginx/sites-available/your-wordpress-site). We’ll optimize worker processes, connection limits, and enable gzip compression.

Worker Processes and Connections

The worker_processes directive should ideally be set to the number of CPU cores available on your server. 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 server load and RAM.

Example nginx.conf Snippet
# /etc/nginx/nginx.conf

user www-data;
worker_processes auto; # Or set to the number of CPU cores
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 4096; # Increased from default 1024
    multi_accept on;
}

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

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

    # 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;

    # SSL Configuration (if applicable)
    # ssl_protocols TLSv1.2 TLSv1.3;
    # ssl_prefer_server_ciphers on;
    # ssl_session_cache shared:SSL:10m;
    # ssl_session_timeout 10m;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

WordPress-Specific Nginx Configuration

This section focuses on caching static assets, preventing hotlinking, and correctly proxying requests to your PHP processor (Gunicorn/FPM).

Example WordPress Site Configuration
# /etc/nginx/sites-available/your-wordpress-site

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com www.your-domain.com;

    # Redirect HTTP to HTTPS (if SSL is configured)
    # return 301 https://$host$request_uri;

    # Root directory and index files
    root /var/www/your-wordpress-site/public_html;
    index index.php index.html index.htm;

    # Caching for static assets
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp)$ {
        expires 365d;
        add_header Cache-Control "public, no-transform";
        access_log off;
        log_not_found off;
    }

    # Prevent access to sensitive files
    location ~ /\.ht {
        deny all;
    }

    # PHP processing (using FastCGI for FPM)
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # With php-fpm (or other FastCGI processors)
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust PHP version and socket path
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # Deny access to wp-config.php
    location ~ wp-config\.php$ {
        deny all;
    }

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

    # Optional: Security headers
    # add_header X-Frame-Options "SAMEORIGIN";
    # add_header X-Content-Type-Options "nosniff";
    # add_header Referrer-Policy "strict-origin-when-cross-origin";
    # add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
}

Applying Nginx Changes

After modifying Nginx configuration files, always test the configuration for syntax errors before reloading the service. This prevents downtime.

Testing and Reloading Nginx
sudo nginx -t
# If syntax is OK, reload Nginx
sudo systemctl reload nginx

Gunicorn/PHP-FPM: The Application Backend

For WordPress, PHP-FPM (FastCGI Process Manager) is the standard for handling PHP requests. If you’re using a framework like Laravel or Django with WordPress, you might integrate Gunicorn. This section focuses on PHP-FPM tuning.

PHP-FPM Configuration Tuning

PHP-FPM’s performance is heavily influenced by its process management. The key directives are found in /etc/php/8.1/fpm/pool.d/www.conf (adjust PHP version and pool name as needed).

Process Manager Settings

The pm directive can be set to static, dynamic, or ondemand. For WordPress, dynamic or static are generally preferred for consistent performance.

Tuning Directives for dynamic PM
; /etc/php/8.1/fpm/pool.d/www.conf

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

pm = dynamic
pm.max_children = 50       ; Max number of children at any one time
pm.start_servers = 5       ; Number of children created at startup
pm.min_spare_servers = 5   ; Min number of idle/spare children
pm.max_spare_servers = 10  ; Max number of idle/spare children
pm.process_idle_timeout = 10s ; How long to keep idle processes
pm.max_requests = 500      ; Max requests per child process before respawning

Explanation:

  • pm.max_children: This is the most critical setting. It should be high enough to handle peak concurrent requests but not so high that it exhausts server memory. A common formula is (Total RAM - RAM for OS/DB/Nginx) / Average PHP Process Size. Monitor memory usage and adjust.
  • pm.start_servers: The number of processes spawned when PHP-FPM starts.
  • pm.min_spare_servers and pm.max_spare_servers: PHP-FPM will try to maintain this number of idle processes.
  • pm.max_requests: Setting this to a reasonable number helps prevent memory leaks in long-running processes.
Tuning Directives for static PM
; /etc/php/8.1/fpm/pool.d/www.conf

[www]
user = www-data
group = www-data
listen = /var/run/php/php8.1-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = static
pm.max_children = 50       ; Fixed number of children
pm.max_requests = 500      ; Max requests per child process before respawning

Explanation:

  • pm.max_children: With static, this is the *fixed* number of processes that will always be running. This offers more predictable performance but can be less efficient if traffic is highly variable.

Applying PHP-FPM Changes

Similar to Nginx, test and reload PHP-FPM after making configuration changes.

Testing and Reloading PHP-FPM
sudo php-fpm8.1 -t # Adjust PHP version
# If syntax is OK, reload PHP-FPM
sudo systemctl reload php8.1-fpm # Adjust PHP version

MySQL/MariaDB Optimization for WordPress

The database is often the bottleneck for dynamic WordPress sites. Optimizing MySQL/MariaDB involves tuning its buffer pools, connection handling, and query cache (though query cache is deprecated in newer MySQL versions and often less effective than other caching mechanisms).

MySQL/MariaDB Configuration Tuning

The primary configuration file is typically /etc/mysql/my.cnf or /etc/mysql/mariadb.conf.d/50-server.cnf. We’ll focus on key InnoDB settings and connection parameters.

InnoDB Buffer Pool

The innodb_buffer_pool_size is arguably the most important setting. It caches data and indexes for InnoDB tables. A common recommendation is 50-75% of available RAM on a dedicated database server, or a smaller percentage (e.g., 25-50%) on a shared server.

Connection Handling

Query Cache (MySQL < 8.0)

For older MySQL versions, the query cache can sometimes help, but it’s known to have scalability issues with frequent writes. If you’re on MySQL 8.0+, this is disabled by default and removed in later versions. Consider application-level or object caching (e.g., Redis, Memcached) instead.

Example MySQL/MariaDB Configuration Snippet
# /etc/mysql/mariadb.conf.d/50-server.cnf (or equivalent)

[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_US
skip-external-locking

# InnoDB Settings
innodb_buffer_pool_size = 1G  ; Adjust based on server RAM (e.g., 1G for 4GB RAM server)
innodb_log_file_size    = 256M ; Larger log files can improve write performance
innodb_flush_log_at_trx_commit = 1 ; For ACID compliance (0 or 2 for higher performance at risk)
innodb_flush_method     = O_DIRECT ; Recommended for Linux
innodb_file_per_table   = 1    ; Recommended for better management

# Connection Settings
max_connections         = 150  ; Adjust based on expected concurrent connections
thread_cache_size       = 16   ; Cache threads for reuse
table_open_cache        = 2000 ; Cache open table file descriptors
table_definition_cache  = 1000 ; Cache table definitions

# Query Cache (MySQL < 8.0, generally not recommended for high-write loads)
# query_cache_type        = 1
# query_cache_size        = 64M
# query_cache_limit       = 1M

# Other optimizations
sort_buffer_size        = 2M
join_buffer_size        = 2M
read_rnd_buffer_size    = 1M
read_buffer_size        = 1M
tmp_table_size          = 64M
max_heap_table_size     = 64M
key_buffer_size         = 16M  ; For MyISAM, if used (less common for WP)

Note: The exact values for innodb_buffer_pool_size, max_connections, and other memory-related settings depend heavily on your server’s RAM and the specific workload. Always monitor your server’s performance and resource utilization after making changes.

Applying MySQL/MariaDB Changes

After modifying the MySQL/MariaDB configuration, restart the service.

Restarting MySQL/MariaDB
sudo systemctl restart mysql # Or mariadb

Monitoring and Iterative Tuning

Tuning is not a one-time event. Continuous monitoring is crucial to identify bottlenecks and validate the effectiveness of your changes. Use tools like:

Key Monitoring Tools and Metrics

  • Nginx: ngx_http_stub_status_module (for active connections, requests per second), Nginx access/error logs, htop/top for CPU/memory.
  • PHP-FPM: PHP-FPM status page (if enabled), htop/top, PHP error logs.
  • MySQL/MariaDB: SHOW GLOBAL STATUS;, SHOW ENGINE INNODB STATUS;, mysqltuner.pl script, pt-query-digest for slow query analysis, htop/top.
  • System-wide: htop, iotop, vmstat, Prometheus/Grafana for long-term trend analysis.

Start with conservative settings and gradually increase them while observing resource utilization. If you encounter issues like high CPU usage, excessive swapping, or slow response times, revisit your configurations. For WordPress, consider implementing object caching (Redis/Memcached) and a robust CDN to further offload your server.

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

  • Orchestrating Serverless PHP 9 with AWS Lambda and API Gateway: A Deep Dive into Performance and Cost Optimization
  • Leveraging PHP 8.3 JIT and Vectorization for Extreme Performance in Laravel Applications
  • Leveraging PHP 9’s JIT Compiler and Concurrent Execution for High-Performance Laravel Microservices
  • Leveraging PHP 8.3 JIT and Vectorization for High-Throughput Microservices in a Laravel Ecosystem
  • Leveraging Laravel Octane and Docker Swarm for High-Performance, Scalable WordPress Headless Deployments

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (664)
  • Desktop Applications (14)
  • DevOps (11)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (6)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • PHP (19)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (10)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (650)
  • SEO & Growth (492)
  • Server (118)
  • Softwares (1)
  • Ubuntu (9)
  • Uncategorized (24)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (26)
  • WordPress Plugin Development (728)
  • WordPress Theme Development (357)

Recent Posts

  • Orchestrating Serverless PHP 9 with AWS Lambda and API Gateway: A Deep Dive into Performance and Cost Optimization
  • Leveraging PHP 8.3 JIT and Vectorization for Extreme Performance in Laravel Applications
  • Leveraging PHP 9's JIT Compiler and Concurrent Execution for High-Performance Laravel Microservices

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (728)
  • Debugging & Troubleshooting (664)
  • Security & Compliance (650)
  • SEO & Growth (492)

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