title: NginX issues HTTP 499 error after 60 seconds despite config. (PHP and AWS)
body: <p>At the end of last week I noticed a problem on one of my medium AWS instances where Nginx always returns a HTTP 499 response if a request takes more than 60 seconds.  The page being requested is a PHP script</p>
  
  <p>I've spent several days trying to find answers and have tried everything that I can find on the internet including several entries here on Stack Overflow, nothing works.</p>
  
  <p>I've tried modifying the PHP settings, PHP-FPM settings and Nginx settings. You can see a question I raised on the NginX forums on Friday (<a href="http://forum.nginx.org/read.php?9,237692" rel="noreferrer">http://forum.nginx.org/read.php?9,237692</a>) though that has received no response so I am hoping that I might be able to find an answer here before I am forced to moved back to Apache which I know just works.</p>
  
  <p>This <strong>is not</strong> the same problem as the HTTP 500 errors reported in other entries.</p>
  
  <p>I've been able to replicate the problem with a fresh micro AWS instance of NginX using PHP 5.4.11.</p>
  
  <p>To help anyone who wishes to see the problem in action I'm going to take you through the set-up I ran for the latest Micro test server.</p>
  
  <p>You'll need to launch a new AWS Micro instance (so it's free) using the AMI ami-c1aaabb5</p>
  
  <p>This PasteBin entry has the complete set-up to run to mirror my test environment. You'll just need to change <em>example.com</em> within the NginX config at the end</p>
  
  <p><a href="http://pastebin.com/WQX4AqEU" rel="noreferrer">http://pastebin.com/WQX4AqEU</a></p>
  
  <p>Once that's set-up you just need to create the sample PHP file which I am testing with which is</p>
  
  <pre><code>&lt;?php
  sleep(70);
  die( 'Hello World' );
  ?&gt;
  </code></pre>
  
  <p>Save that into the webroot and then test.  If you run the script from the command line using php or php-cgi, it will work.  If you access the script via a webpage and tail the access log <em>/var/log/nginx/example.access.log</em>, you will notice that you receive the HTTP 1.1 499 response after 60 seconds.</p>
  
  <p>Now that you can see the timeout, I'll go through some of the config changes I've made to both PHP and NginX to try to get around this.  For PHP I'll create several config files so that they can be easily disabled</p>
  
  <p><strong>Update the PHP FPM Config to include external config files</strong></p>
  
  <pre><code>sudo echo '
  include=/usr/local/php/php-fpm.d/*.conf
  ' &gt;&gt; /usr/local/php/etc/php-fpm.conf
  </code></pre>
  
  <p><strong>Create  a new PHP-FPM config to override the request timeout</strong></p>
  
  <pre><code>sudo echo '[www]
  request_terminate_timeout = 120s
  request_slowlog_timeout = 60s
  slowlog = /var/log/php-fpm-slow.log ' &gt;
  /usr/local/php/php-fpm.d/timeouts.conf
  </code></pre>
  
  <p><strong>Change some of the global settings to ensure the emergency restart interval is 2 minutes</strong></p>
  
  <pre><code># Create a global tweaks
  sudo echo '[global]
  error_log = /var/log/php-fpm.log
  emergency_restart_threshold = 10
  emergency_restart_interval = 2m
  process_control_timeout = 10s
  ' &gt; /usr/local/php/php-fpm.d/global-tweaks.conf
  </code></pre>
  
  <p>Next, we will change some of the PHP.INI settings, again using separate files</p>
  
  <pre><code># Log PHP Errors
  sudo echo '[PHP]
  log_errors = on
  error_log = /var/log/php.log
  ' &gt; /usr/local/php/conf.d/errors.ini
  
  sudo echo '[PHP]
  post_max_size=32M
  upload_max_filesize=32M
  max_execution_time = 360
  default_socket_timeout = 360
  mysql.connect_timeout = 360
  max_input_time = 360
  ' &gt; /usr/local/php/conf.d/filesize.ini
  </code></pre>
  
  <p>As you can see, this is increasing the socket timeout to 3 minutes and will help log errors.</p>
  
  <p>Finally, I'll edit some of the NginX settings to increase the timeout's that side</p>
  
  <p>First I edit the file <em>/etc/nginx/nginx.conf</em> and add this to the http directive
      fastcgi_read_timeout 300;</p>
  
  <p>Next, I edit the file <em>/etc/nginx/sites-enabled/example</em> which we created earlier (See the pastebin entry) and add the following settings into the <strong>server</strong> directive</p>
  
  <pre><code>client_max_body_size    200;
  client_header_timeout   360;
  client_body_timeout     360;
  fastcgi_read_timeout    360;
  keepalive_timeout       360;
  proxy_ignore_client_abort on;
  send_timeout            360;
  lingering_timeout       360;
  </code></pre>
  
  <p>Finally I add the following into the <em>location ~ .php$</em> section of the server dir</p>
  
  <pre><code>fastcgi_read_timeout 360;
  fastcgi_send_timeout 360;
  fastcgi_connect_timeout 1200;
  </code></pre>
  
  <p>Before retrying the script, start both nginx and php-fpm to ensure that the new settings have been picked up. I then try accessing the page and still receive the HTTP/1.1 499 entry within the NginX example.error.log.</p>
  
  <p>So, where am I going wrong?  This just works on apache when I set PHP's max execution time to 2 minutes.</p>
  
  <p>I can see that the PHP settings have been picked up by running <strong>phpinfo()</strong> from a web-accessible page.  I just don't get, I actually think that too much has been increased as it should just need PHP's <em>max_execution_time</em>, <em>default_socket_timeout</em> changed as well as NginX's <em>fastcgi_read_timeout</em> within just the server->location directive.</p>
  
  <h2>Update 1</h2>
  
  <p>Having performed some further test to show that the problem is not that the client is dying I have modified the test file to be</p>
  
  <pre><code>&lt;?php
  file_put_contents('/www/log.log', 'My first data');
  sleep(70);
  file_put_contents('/www/log.log','The sleep has passed');
  die('Hello World after sleep');
  ?&gt;
  </code></pre>
  
  <p>If I run the script from a web page then I can see the content of the file be set to the first string. 60 seconds later the error appears in the NginX log. 10 seconds later the  contents of the file changes to the 2nd string, proving that PHP is completing the process.</p>
  
  <h2>Update 2</h2>
  
  <p>Setting <strong>fastcgi_ignore_client_abort on;</strong> does change the response from a HTTP 499 to a HTTP 200 though nothing is still returned to the end client.</p>
  
  <h2>Update 3</h2>
  
  <p>Having installed Apache and PHP (5.3.10) onto the box straight (using apt) and then increasing the execution time the problem does appear to also happen on Apache as well.  The symptoms are the same as NginX now, a HTTP200 response but the actual client connection times out before hand.</p>
  
  <p>I've also started to notice, in the NginX logs, that if I test using Firefox, it makes a double request (like this <a href="https://stackoverflow.com/questions/13261327/php-script-executes-twice-when-longer-than-60-seconds">PHP script executes twice when longer than 60 seconds</a>). Though that does appear to be the client requesting upon the script failing</p>