When working with Apache2's mod_proxy_fcgi to handle PHP requests through PHP-FPM, many developers encounter an unexpected 30-second timeout barrier, even when explicit timeout values are configured much higher. The error typically appears in logs as:
[proxy_fcgi:error] (70007)The timeout specified has expired: AH01075: Error dispatching request
Apache's proxy architecture actually implements several independent timeout mechanisms:
- Core Apache Timeout directive
- mod_proxy's ProxyTimeout
- mod_proxy_fcgi's internal timeout
- PHP-FPM's request_terminate_timeout
The 30-second default comes from PHP-FPM's configuration, not Apache's directives.
Here's the full set of configurations needed across all layers:
# In Apache configuration (httpd.conf or virtual host)
Timeout 600
ProxyTimeout 600
<IfModule proxy_module>
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9001/var/www/$1 timeout=600 retry=0
</IfModule>
# In PHP-FPM pool configuration (www.conf)
request_terminate_timeout = 600
request_slowlog_timeout = 300
When troubleshooting, check these critical points:
- Verify which PHP-FPM pool is being used with
ps aux | grep php-fpm
- Confirm the loaded Apache modules with
apachectl -M | grep proxy
- Test with a simple sleep script to isolate the issue:
<?php
// test-timeout.php
sleep(35); // Should work with proper configuration
echo "Completed after 35 seconds";
?>
For high-traffic systems, you'll need to adjust keepalive settings:
# In Apache configuration
KeepAlive On
KeepAliveTimeout 15
MaxKeepAliveRequests 100
# In PHP-FPM pool
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
Here's a working configuration from a production Laravel application handling long-running reports:
# Virtual Host Configuration
<VirtualHost *:443>
Timeout 1800
ProxyTimeout 1800
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9002"
ProxySet connectiontimeout=1800 timeout=1800
</FilesMatch>
# Additional directives...
</VirtualHost>
# Corresponding PHP-FPM pool
[reports]
listen = 127.0.0.1:9002
request_terminate_timeout = 1800
pm = static
pm.max_children = 4
Many developers encounter this frustrating scenario: your PHP script works perfectly when it completes within 30 seconds, but anything longer triggers a 503 Service Unavailable
error. The Apache error log shows:
[proxy_fcgi:error] (70007)The timeout specified has expired: AH01075: Error dispatching request
You've probably already tried these standard timeout settings in your VirtualHost configuration:
Timeout 600
<IfModule proxy_module>
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9001/path/to/scripts/$1 timeout=600
ProxyTimeout 600
</IfModule>
Yet the 30-second timeout persists, suggesting there's another layer to this problem.
While Apache's timeout settings appear correct, PHP-FPM has its own execution time limit that overrides these settings. Check your PHP-FPM pool configuration (typically in /etc/php-fpm.d/www.conf
):
; Default timeout for worker processes
request_terminate_timeout = 30s
This is likely set to 30 seconds by default. Change it to match your Apache timeout:
request_terminate_timeout = 600s
For long-running scripts, you need to configure timeouts at multiple levels:
- Apache Core:
Timeout 600
- mod_proxy:
ProxyTimeout 600
- PHP-FPM:
request_terminate_timeout = 600s
- PHP Script (optional):
set_time_limit(600);
Create a simple test script to verify your changes:
<?php
// test-timeout.php
$start = time();
$duration = 120; // 2 minutes
while (time() - $start < $duration) {
echo "Running for " . (time() - $start) . " seconds\n";
flush();
sleep(5);
}
echo "Script completed successfully after $duration seconds";
?>
If all configurations are correct, this script should run to completion without timing out.
For production environments, consider these best practices:
- Implement proper error handling in long-running scripts
- Use background processing for extremely long operations
- Monitor resource usage during extended execution
- Consider implementing progress tracking for user feedback