Is it possible to extend a 504 timeout in nginx on a per location basis
Is it possible to set timeout directives within a location block to prevent nginx returning a 504 from a long running PHP script (PHP-FPM)?
server
{
listen 80;
server_name ubuntu-vm.test-api;
root /home/me/Sites/path/to/site/;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
# Fix for server variables that behave differently under nginx/php-fpm than typically expected
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Include the standard fastcgi_params file included with nginx
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
# Override the SCRIPT_FILENAME variable set by fastcgi_params
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Pass to upstream PHP-FPM; This must match whatever you name your upstream connection
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
location /someurlpath {
try_files $uri $uri/ /index.php?$query_string;
# Fix for server variables that behave differently under nginx/php-fpm than typically expected
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Include the standard fastcgi_params file included with nginx
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
# Override the SCRIPT_FILENAME variable set by fastcgi_params
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Pass to upstream PHP-FPM; This must match whatever you name your upstream connection
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_read_timeout 100000s;
}
error_log /var/log/nginx/my_api_error.log;
access_log /var/log/nginx/my_api_access.log;
}
This has no effect when making a request to example.com/someurlpath
. The timeout occurs after approximately 60 seconds. PHP is configured to allow the script to run until completion (set_time_limit(0))
If I set the fastcgi_read_timeout
in the main ~ /.php {}
block this resolves the issue.
I don't want to set a global timeout for all scripts.
First, take a look at nested locations. The reason why your second
location block isn't taken into account is because when nginx matches a location, it stops. So, http://ubuntu-vm.test-api/someurlpath
, if theres an index.php in the corresponding folder, only matches the location ~ \.php$
!
I've stumbled upon this interesting blog post
To sum this up, you need to:
- Increase the
max_execution_time
configuration variable in your php.ini. - Increase the
request_terminate_timeout
configuration variable of php-fpm. - Set the
fastcgi_read_timeout
in the location you want, in the nginx configuration file.
The trouble is you can't tell php-fpm to use a different configuration file only for that one location.
However, you can set a php.ini configuration variable in your nginx configuration like so:
fastcgi_param PHP_VALUE "max_execution_time=1000";
I ran into the same problem, and while I think you could use the Nginx configuration to set fastcgi_read_timeout
per location as you're trying to do, it ends up being complicated to configure the locations properly that way. And then it may still timeout if you don't also set PHP's max_execution_time
.
I found that a better solution is to set it up so that the Nginx timeouts aren't really used, and let PHP handle the timeouts instead (as it does with other servers like mod-Apache and the command line).
So in your Nginx configuration's location ~ \.php$
section, set request_terminate_timeout
to a very high value (or better yet, set it to 0 to disable the timeout). And also set fastcgi_read_timeout
to the highest number of seconds you could possibly want any script to run.
And then fine-tune it by setting a default value by setting max_execution_time
in your php.ini. Now, when you have script that you want to allow to run for a long time, use the set_time_limit()
PHP command in those scripts.