0

This is using nginx 1.6.3 and PHP 7.0.7 via PHP-FPM in CentOS 7.2.

I have run many sites using LAMP and have been trying to switch to LEMP, but a sticking point that keeps coming up is that my page handler keeps showing 404 errors in the status, even though I have set a different status in PHP. It is as if nginx is completely ignoring the headers sent from PHP for the 404 error page.

/etc/nginx/nginx.conf looks like:

user web web; worker_processes auto; error_log /var/web/Logs/WebServer/nginx-error.log; pid /run/nginx.pid; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/web/Logs/WebServer/nginx-access.log main; fastcgi_buffers 8 1024k; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; } 

Each domain's configuration looks like:

server { listen 80; server_name www.something.com; root /var/web/www.something.com/; index index.php index.html; error_page 404 /PageHandler; location / { try_files $uri $uri/ /PageHandler =404; location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } location /PageHandler { try_files /PageHandler.php =500; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; include fastcgi.conf; fastcgi_param REDIRECT_STATUS 404; } } } 

The very simple PHP script is (and yes, I know the headers are redundant, and still it does nothing):

<?php http_response_code(200); header("HTTP/1.1 200 OK"); header("Status: 200", true, 200); ?> Test <?= $_SERVER["REQUEST_URI"] ?>, code <?= $_SERVER["REDIRECT_STATUS"] ?> 

I have searched fruitlessly for hours on how to fix this. I have tried at least a hundred different .conf formats, and none of them work. What I have above at least sets REDIRECT_STATUS to 404, but I have found no way to be able to return a 200 status code if a page was found. I cannot just have nginx always return a 200, because it may actually be a genuine 404 since the actual script tests the current URL in a database.

How do I get nginx to obey PHP's HTTP status header?

3 Answers 3

2

To me these nested location blocks look troublesome, and they are not needed. Try this:

server { listen 80; server_name www.something.com; root /var/web/www.something.com/; index index.php index.html; try_files $uri $uri/ /PageHandler.php =404; location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } } 
5
  • I tried a variation of that. Both that and what you have here causes nginx to send /PageHandler.php with a MIME type of application/octet-stream so then the user downloads it. Commented Aug 2, 2016 at 16:57
  • @MarkOrmston I suspect you are omitting some details which you think aren't important, but actually are. Please review everything and add any missing details. Commented Aug 2, 2016 at 18:57
  • @Michael Hampton♦ The only other configuration I could think to add was nginx.conf which I thought was very standard (aside from fixing the user and changing where the logs go). I have added that to the question if it makes any difference. Commented Aug 2, 2016 at 19:39
  • Did you try exactly my version or one that uses nested location blocks in your question? Since the download behavior could very well be caused by the nested locations.. Commented Aug 2, 2016 at 22:21
  • I tried the exact version you have above. It tried to download /PageHandler.php - It seems to be a behavior issue with try_files. I have finally found a solution that merges data from several sources. Will write that up shortly. Commented Aug 2, 2016 at 22:35
0

The obvious thing to do is to remove this:

 error_page 404 /PageHandler; 

It's completely redundant, since any path that isn't found as a static file will be directed there by your first try_files anyway. It's only necessary or useful to use error_page to serve static error pages.

1
  • If I comment that out, the /PageHandler is ignored and I get nginx's 404 error page instead. Probably because /PageHandler doesn't actually exist so it is skipped with try_files I would assume. I tried creating a blank /PageHandler file and that gets returned as an application/octet-stream so even if I tried to use PHP to handle it, the user would just get the source... Commented Aug 2, 2016 at 17:05
0

By combining the lessons I have learned through many failures, the two other answers I received (thank you Michael Hampton and Tero Kilkanen for pointing me in the right direction), and a hunch to look further into try_files, I found out that the problem was centered around how try_files is working in my installation. There are far more details here: How does try_files work? and here: http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files

The final working server configuration is:

server { listen 80; server_name www.something.com; root /var/web/www.something.com/; index index.php index.html; try_files $uri $uri/ @PageHandler; location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } location @PageHandler { try_files /PageHandler.php =404; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; include fastcgi.conf; fastcgi_param REDIRECT_STATUS 404; } } 

As you can see, I am using a named location of @PageHandler and tying in that. It is using a default HTTP status of 200 instead of 404, but since I can control that from PHP, I set it to 404 explicitly when necessary.

Using any one of the following PHP commands changes the status as seen by my browser (all three are not necessary):

http_response_code(404); header("HTTP/1.1 404 Not Found"); header("Status: 404", true, 404); 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.