Here’s an interesting bit of behaviour. When a PHP error occurs in a PHP-FPM pool, nginx can still reply with a HTTP 200 status code – indicating everything is OK – if the PHP script returns output.
This is tested running PHP 5.4.36 and nginx 1.6.2.
For instance:
php-fpm-error.log: [error] 24802#0: *7 FastCGI sent in stderr: "PHP message: PHP Parse error: syntax error, unexpected '<' in test.php on line 3" while reading response header from upstream, client: 127.0.0.1, server: , request: "GET /test.php?time=1421685293 HTTP/1.1" nginx-access.log: 127.0.0.1 - - [...] "GET /test.php?time=1421685293 HTTP/1.1" 200 110 "-" "curl"
The actual response seen by the client shows the exact same HTTP 200 OK status code.
$ curl -i localhost/test.php?time=`date +%s` HTTP/1.1 200 OK Server: nginx ... Parse error: syntax error, unexpected '<' in test.php on line 3
Enabling or disabling PHP’s display_errors
option is what makes the difference. This option determines whether errors should be printed to the screen (= On) or hidden (=Off).
If nginx is detecting output from the FastCGI upstream it will consider it as a valid response, even if the upstream (in this case, php-fpm) triggered an error.
Disabling display_errors
in the PHP-FPM pool fixes this.
php_admin_value[display_errors] = Off
It prevents the PHP-script from showing error output to the screen, which in turn causes nginx to correctly throw an HTTP 500 Internal Server Error.
$ curl -i localhost:8080/test.php?time=`date +%s` HTTP/1.1 500 Internal Server Error Server: nginx ... (no output is shown, empty response)
You can still log all errors to a file, with the error_log
directive.
php_admin_value[error_log] = /var/log/php-fpm/error.log php_admin_flag[log_errors] = on
I’ll need to dig deeper into this, because the display_errors
option shouldn’t have this kind of effect on how nginx handles its HTTP response codes. An error from the backend is still an error, regardless of the fact if there’s output or not.
If this isn’t what you’re experiencing, have a look at nginx’s fastcgi_intercept_errors, a config that allows you to catch upstream errors and substitute them with your own error pages.