PHP Optimization for WordPress with Nginx

Complete Guide to Configuring PHP Performance Settings

Introduction

Optimizing PHP is crucial for WordPress performance when running on Nginx. This comprehensive guide covers essential PHP configuration parameters including upload limits, memory management, OPcache optimization, and resource limits. Proper configuration ensures your WordPress site runs efficiently and can handle the demands of modern themes and plugins.

PHP Resource Limits Overview

PHP Request Processing Flow

Client Request
Nginx
PHP-FPM
WordPress

Each stage has configurable limits that affect performance and security

Directive Purpose Recommended Value
upload_max_filesize Maximum size for individual file uploads 100M
post_max_size Maximum size of POST data (includes files + form data) 125M (slightly higher than upload_max_filesize)
max_input_vars Maximum number of input variables per request 3000 (up to 5000 for complex themes)
memory_limit Maximum memory per PHP script 256M
max_execution_time Maximum script execution time (seconds) 30 (adjust based on plugins)
max_input_time Maximum time for parsing input data (seconds) 60 (adjust based on plugins)

Understanding Key Directives

Upload and POST Size Limits

Important Relationship: The post_max_size must always be larger than upload_max_filesize because POST data includes the file itself plus additional form data and metadata.

upload_max_filesize: This directive specifically controls the maximum size of individual files uploaded through forms. If you need to upload large media files, videos, or high-resolution images, you'll need to increase this value.

post_max_size: This sets the overall limit for the entire POST request payload, which includes all uploaded files plus any additional form fields. Setting this 20-25% higher than upload_max_filesize provides adequate overhead.

; Example configuration upload_max_filesize = 100M post_max_size = 125M

Max Input Variables

The max_input_vars directive limits the number of input variables (GET, POST, and COOKIE) that PHP will accept in a single request. This security measure helps prevent hash collision denial-of-service attacks.

WordPress Consideration: Modern WordPress themes with extensive customization options and page builders can generate forms with thousands of input fields. A value of 3000 is recommended, but complex themes may require up to 5000.

Memory Limit

The memory_limit directive sets the maximum amount of memory a single PHP script can consume. This prevents runaway scripts from exhausting server resources.

Multi-Level Configuration: You can set the memory limit at multiple levels:
  • Server-wide in php.ini or server-override.ini (applies to all sites)
  • Per-site in wp-config.php using define('WP_MEMORY_LIMIT', '256M');
  • Per-pool in PHP-FPM pool configuration

OPcache: The Performance Game Changer

OPcache is a caching engine built into PHP that dramatically improves performance by storing precompiled script bytecode in shared memory. Without OPcache, PHP must compile scripts on every request, leading to severe performance degradation.

PHP Execution: Without vs. With OPcache

❌ Without OPcache

Request Arrives
Load PHP File
Parse Code
Compile to Bytecode
Execute

Repeats on EVERY request!

✅ With OPcache

Request Arrives
Check Cache
Execute Cached Bytecode

Lightning fast execution!

(First request compiles and caches)

OPcache Configuration Directives

Directive Purpose Recommended Value
opcache.memory_consumption Memory allocated for OPcache storage 128 (in MB)
opcache.interned_strings_buffer Memory for string interning optimization 8 (in MB)
opcache.max_accelerated_files Maximum number of PHP files to cache 10000
opcache.validate_timestamps Check for file modifications 0 (production), 1 (development)
opcache.revalidate_freq How often to check for changes (seconds) 2 (only if validate_timestamps=1)
opcache.validate_permission Validate file permissions on cache hits 1 (enabled for security)

Development vs. Production Settings

🔧 Development Server

opcache.validate_timestamps = 1 opcache.revalidate_freq = 2

Behavior: OPcache checks for file modifications every 2 seconds, ensuring code changes are reflected immediately during development.

🚀 Production Server

opcache.validate_timestamps = 0 ; revalidate_freq ignored when timestamps disabled

Behavior: OPcache never checks for modifications, maximizing performance. Requires manual cache clearing after code updates.

Critical Note: When opcache.validate_timestamps is set to 0 (production), the opcache.revalidate_freq directive is completely ignored. You must manually clear the cache after deploying code changes.

Configuration Implementation

Step 1: Edit server-override.ini

1 Navigate to the PHP configuration directory:
cd /etc/php/8.3/fpm/conf.d/
2 Open server-override.ini with nano:
sudo nano server-override.ini
3 Add the following configuration:
; ========================================== ; OPTIMIZE PHP ; ========================================== ; File Upload Settings upload_max_filesize = 100M post_max_size = 125M ; Security & Performance max_input_vars = 3000 ; Memory Management memory_limit = 256M ; Execution Time Limits (adjust based on your plugins) ; max_execution_time = 30 ; max_input_time = 60 ; Error Logging (configured per-pool later) display_errors = Off log_errors = On
Note: The max_execution_time and max_input_time directives are commented out by default. Uncomment and adjust these values only if required by your specific themes or plugins.

Step 2: Configure PHP-FPM Process Limits

1 Navigate to PHP-FPM configuration directory:
cd /etc/php/8.3/fpm/
2 Create a backup of php-fpm.conf:
sudo cp php-fpm.conf php-fpm.conf.backup
3 Edit php-fpm.conf:
sudo nano php-fpm.conf
4 Search for and modify these directives (Ctrl+W to search):
; Original (commented): ;rlimit_files = 1024 ; Change to: rlimit_files = 32768 ; Original (commented): ;rlimit_core = 0 ; Change to: rlimit_core = unlimited
What these directives do:
  • rlimit_files: Sets the maximum number of file descriptors (open files) PHP-FPM can use. Increasing from 1024 to 32768 prevents "too many open files" errors.
  • rlimit_core: Setting to "unlimited" allows PHP-FPM to generate core dump files when crashes occur, which is invaluable for debugging.

Step 3: Apply Changes

1 Reload Nginx:
sudo systemctl reload nginx # Or using alias: nr
2 Reload PHP-FPM:
sudo systemctl reload php8.3-fpm # Or using alias: fpmr

Verifying Configuration Changes

Checking Open File Limits

1 Find the PHP-FPM master process ID:
ps ax | grep php-fpm
Example output:
24832 ? Ss 0:00 php-fpm: master process (/etc/php/8.3/fpm/php-fpm.conf)
54734 ? S 0:00 php-fpm: pool www
54735 ? S 0:00 php-fpm: pool www
2 Check the limits for the master process (replace 24832 with your PID):
cat /proc/24832/limits
3 Verify the Max open files line shows:
Max open files 32768 32768 files
4 Check pool worker processes as well:
cat /proc/54734/limits cat /proc/54735/limits
Expected result: All processes (master and workers) should show the new limit of 32768 for both soft and hard limits.

Clearing OPcache

When running in production mode with opcache.validate_timestamps = 0, you must manually clear the cache after code updates. There are several methods:

Method 1: Command Line (Recommended)

# Reload PHP-FPM to clear OPcache sudo systemctl reload php8.3-fpm # Or using alias: fpmr

Method 2: WordPress Plugin

Plugin Options:
  • Search the WordPress repository for "OPcache" plugins
  • Choose actively maintained plugins with recent updates
  • Most plugins provide cache clearing buttons and detailed statistics
  • Useful for viewing cache hit rates and memory usage
Important: Only install OPcache plugins from reputable sources that are regularly updated and provide support. Always verify the plugin is compatible with your PHP version.

Per-Site PHP Pools

For optimal security and performance, each WordPress site should run in its own PHP-FPM pool. This provides:

Coming Later: PHP pool configuration for individual sites will be covered in detail later in the course when we set up file and directory management for WordPress installations.

Troubleshooting Common Issues

Issue: "Too Many Open Files" Error

Solution: If you still receive this error after setting rlimit_files to 32768, you may need to increase the system-wide limits in /etc/security/limits.conf and raise the rlimit_files value even higher.

Issue: Theme Options Disappearing

Solution: Increase max_input_vars from 3000 to 5000. Some complex themes and page builders require higher values.

Issue: Upload Fails for Large Files

Solution: Check that post_max_size is larger than upload_max_filesize. Also verify nginx client_max_body_size is set appropriately in your nginx configuration.

Issue: OPcache Not Clearing After Code Updates

Solution: On production servers with validate_timestamps=0, you must manually reload PHP-FPM. Consider using a deployment script that automatically reloads PHP-FPM after code updates.

Summary and Next Steps

Configuration Complete! ✅

You have successfully:

  • Configured PHP resource limits (upload sizes, memory, input variables)
  • Optimized OPcache for dramatic performance improvements
  • Set appropriate process limits for PHP-FPM
  • Prepared for per-site PHP pool configuration

What's Next?

In the next section of the course, we will cover:

Current Status: You have now installed, hardened, and optimized Nginx, MariaDB, and PHP 8.3. Your server is ready for WordPress site deployment.