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:

  1. Increase the max_execution_time configuration variable in your php.ini.
  2. Increase the request_terminate_timeout configuration variable of php-fpm.
  3. 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.