Resolving ‘PHP maximum execution time of 30 seconds exceeded’ in WSL2 Ubuntu
Fix PHP max execution time timeouts in WSL2 Ubuntu. Learn to adjust php.ini, Nginx, and FPM configurations for long-running scripts.
Fix PHP max execution time timeouts in WSL2 Ubuntu. Learn to adjust php.ini, Nginx, and FPM configurations for long-running scripts.
When developing or hosting PHP applications within your Windows Subsystem for Linux 2 (WSL2) Ubuntu environment, you might encounter a frustrating timeout error: "PHP maximum execution time of 30 seconds exceeded." This typically occurs when a PHP script, such as a large data import, complex report generation, or image processing task, takes longer than its default allotted time to complete. Rather than waiting indefinitely, the PHP engine terminates the script, preventing resource exhaustion but often leading to a broken user experience or failed background process.
This guide will walk you through diagnosing and resolving this common issue by adjusting timeout settings across PHP, PHP-FPM, and Nginx in your WSL2 Ubuntu setup, ensuring your long-running scripts execute successfully.
Symptom & Error Signature
Users typically experience a blank page, an HTTP 504 Gateway Timeout error in their browser, or a direct fatal error message if running the script via CLI. Here are the common log entries and browser outputs you might encounter:
Browser Error (Nginx 504 Gateway Timeout):
<html>
<head><title>504 Gateway Time-out</title></head>
<body>
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>
Nginx Error Log (/var/log/nginx/error.log):
2023/10/27 10:30:45 [error] 1234#1234: *123 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 172.20.10.5, server: yourdomain.test, request: "GET /long_process.php", upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:", host: "yourdomain.test"
PHP-FPM Log (/var/log/php/php8.1-fpm.log or similar):
[27-Oct-2023 10:30:45] WARNING: [pool www] child 1234, script '/var/www/html/long_process.php' (request: "GET /long_process.php") execution timed out (30.123 sec), terminating
[27-Oct-2023 10:30:45] WARNING: [pool www] child 1234 exited on signal 9 (SIGKILL) after 30.123 seconds from start
Direct PHP CLI Output:
PHP Fatal error: Maximum execution time of 30 seconds exceeded (tried to allocate 20480 bytes) in /var/www/html/long_process.php on line 15
Root Cause Analysis
The "maximum execution time exceeded" error is a safeguard mechanism implemented across different layers of your web stack to prevent runaway scripts from consuming excessive server resources. Several components contribute to the overall execution time limit:
PHP's
max_execution_time: This is the most direct cause. By default, PHP scripts are allowed 30 seconds to run. This setting is defined inphp.iniand aims to terminate scripts that get stuck in infinite loops or take too long, freeing up PHP workers.PHP-FPM's
request_terminate_timeout: When using PHP-FPM (FastCGI Process Manager), this setting in the FPM pool configuration (www.confor a custom pool file) dictates how long PHP-FPM will wait for a child process to finish processing a request. Ifrequest_terminate_timeoutis set lower than or equal to PHP'smax_execution_time, PHP-FPM might terminate the script even if PHP itself hasn't hit its internal limit. A value of0means 'off', allowing PHP'smax_execution_timeto be the sole governor.Web Server (Nginx)
fastcgi_read_timeout: Nginx acts as a reverse proxy, forwarding requests to PHP-FPM. Thefastcgi_read_timeoutdirective in Nginx determines how long Nginx will wait for a response from the FastCGI server (PHP-FPM). If a PHP script takes longer than this Nginx timeout, Nginx will close the connection and return a 504 Gateway Timeout error, even if the PHP script is still running and hasn't hit itsmax_execution_timeorrequest_terminate_timeout. This is a very common scenario.Resource Exhaustion: While not a direct timeout, scripts that consume excessive CPU or memory can slow down to the point where they are more likely to hit the predefined time limits. Insufficient
memory_limitinphp.inican also cause script termination.
In a WSL2 environment, these layers behave identically to a native Linux server. Diagnosing the exact point of failure often involves checking logs from Nginx and PHP-FPM in conjunction.
Step-by-Step Resolution
To resolve the "maximum execution time exceeded" error, you need to adjust timeout settings in a coordinated manner across PHP, PHP-FPM, and Nginx. Always remember to restart the relevant services after making configuration changes.
Prerequisites:
- Access to your WSL2 Ubuntu terminal.
sudoprivileges.- Knowledge of your PHP version (e.g.,
php8.1). You can check this withphp -v.
1. Adjust PHP's max_execution_time
First, increase the primary PHP execution time limit.
Locate the
php.inifor PHP-FPM: The path typically follows/etc/php/<version>/fpm/php.ini. For example, for PHP 8.1, it would be/etc/php/8.1/fpm/php.ini.sudo nano /etc/php/8.1/fpm/php.iniReplace
8.1with your PHP version if different.Modify
max_execution_time: Find the linemax_execution_time = 30and change30to a higher value, such as180(3 minutes) or300(5 minutes). Choose a value that accommodates your script's needs, but avoid excessively long times without proper justification.max_execution_time = 180Restart PHP-FPM: After saving the
php.inifile, you must restart the PHP-FPM service for the changes to take effect.sudo systemctl restart php8.1-fpmAgain, replace
8.1with your PHP version.
If you also run PHP scripts via the command line (e.g.,
php artisan commands), you might need to adjust themax_execution_timein/etc/php/<version>/cli/php.inias well. For CLI scripts, settingmax_execution_time = 0(meaning no time limit) is common.
2. Configure PHP-FPM's request_terminate_timeout
Next, ensure PHP-FPM doesn't prematurely terminate the request.
Locate the PHP-FPM pool configuration file: The default pool configuration for web requests is usually
/etc/php/<version>/fpm/pool.d/www.conf.sudo nano /etc/php/8.1/fpm/pool.d/www.confAdjust the PHP version as needed.
Modify
request_terminate_timeout: Find the line;request_terminate_timeout = 0. Uncomment it (remove the leading semicolon) and set its value to be equal to or greater than themax_execution_timeyou set inphp.ini. If0, it means no timeout from FPM side, andmax_execution_timetakes precedence. For consistency, it's often set to match.request_terminate_timeout = 180A value of
0means PHP-FPM will not set a timeout and will rely solely on PHP'smax_execution_time. This is often a good option for clarity. However, if your PHP processes hang without hittingmax_execution_time(e.g., a deadlock), FPM's timeout can act as a secondary safety net.Restart PHP-FPM: Even if you only changed
www.conf, a full PHP-FPM service restart is necessary.sudo systemctl restart php8.1-fpm
3. Increase Nginx fastcgi_read_timeout
This is a critical step, as Nginx often times out before PHP or PHP-FPM.
Locate your Nginx site configuration file: Your site's configuration is typically found in
/etc/nginx/sites-available/your_site_name.conf.sudo nano /etc/nginx/sites-available/your_site.confReplace
your_site.confwith the actual name of your Nginx configuration file for the relevant site.Add or modify
fastcgi_read_timeout: Inside thelocation ~ .php$block (or the appropriate location block that handles PHP processing), add or modify thefastcgi_read_timeoutdirective. This value must be equal to or greater than yourmax_execution_timeandrequest_terminate_timeoutvalues to ensure Nginx waits long enough for PHP to respond.location ~ .php$ { include snippets/fastcgi-php.conf; # Common include for PHP setup fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust PHP version and socket path fastcgi_read_timeout 180; # Must be >= PHP's max_execution_time and FPM's request_terminate_timeout # Optional: Increase buffer sizes for large outputs fastcgi_buffers 16 16k; fastcgi_buffer_size 32k; }Test Nginx configuration: Before reloading, always test Nginx's configuration syntax to catch errors.
sudo nginx -tYou should see
test is successful. If there are errors, correct them before proceeding.Reload Nginx: Apply the new Nginx configuration. A reload is usually sufficient.
sudo systemctl reload nginxIf
reloaddoesn't seem to apply changes, arestartmight be necessary, butreloadis generally preferred to avoid dropping active connections.
Ensure that no higher-level Nginx configuration (e.g., in
httporserverblocks) sets afastcgi_read_timeoutto a lower value, as location-specific directives override global ones, but a forgotten global setting could still interfere. If you have a proxy setup (e.g., Nginx proxying to another Nginx or Docker container), you might also need to adjustproxy_read_timeout.
4. (Optional) Address CLI Scripts
If your timeout occurs when running PHP scripts directly from the command line (e.g., php artisan migrate, Composer commands), you need to adjust the php.ini specific to the CLI.
Locate the CLI
php.ini:sudo nano /etc/php/8.1/cli/php.iniModify
max_execution_timeandmemory_limit: For CLI scripts, it's common to setmax_execution_time = 0to disable the time limit, as CLI scripts often run as background jobs without user interaction. You might also want to increasememory_limitfor heavy CLI tasks.max_execution_time = 0 memory_limit = 512M # Or higher, depending on your needsNo service restart is required for CLI
php.inichanges; they take effect immediately on the next CLI execution.
5. Verify Your Changes
To confirm your changes are effective, you can create a simple PHP script designed to exceed the old timeout.
Create a test script (e.g.,
test_timeout.php) in your web root:<?php // It's good practice to log for debugging error_log("Starting long script execution at " . date('Y-m-d H:i:s')); // Try to set time limit to 0 if running in browser and allowed by php.ini // For CLI, php.ini is typically preferred for max_execution_time = 0 set_time_limit(0); $sleep_duration = 120; // Sleep for 2 minutes (120 seconds) echo "Script will sleep for " . $sleep_duration . " seconds...<br>"; flush(); // Try to send output immediately (won't work if output buffering is heavily used) sleep($sleep_duration); echo "Script completed after " . $sleep_duration . " seconds!"; error_log("Finished long script execution at " . date('Y-m-d H:i:s')); ?>Access the script via your browser:
http://yourdomain.test/test_timeout.phpIf configured correctly, the script should complete after 120 seconds, displaying "Script completed after 120 seconds!". If you still get a timeout, check your Nginx and PHP-FPM logs for specific errors.
6. Consider Application-Level Optimizations
While increasing timeouts resolves the immediate error, it's crucial to acknowledge that very long execution times often indicate potential inefficiencies in the application's code.
- Optimize Database Queries: Long-running scripts frequently involve heavy database operations. Profile your queries and ensure appropriate indexing.
- Refactor Long Loops/Processes: Break down large tasks into smaller, manageable chunks.
- Utilize Asynchronous Processing/Queue Systems: For truly long-running operations (e.g., sending bulk emails, generating large reports, processing video), consider offloading them to background jobs using message queues (e.g., Redis Queue, RabbitMQ, Beanstalkd) and dedicated workers. This frees up the web server for immediate requests.
- Batch Processing: Instead of processing thousands of items in one go, process them in smaller batches.
By systematically adjusting these configurations and considering application-level optimizations, you can effectively manage PHP execution timeouts in your WSL2 Ubuntu development and hosting environment.