Nginx sets HTTP 200 OK on PHP-FPM parse errors

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, January 19, 2015

Follow me on Twitter as @mattiasgeniar

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.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.