Nginx - pass all 404 errors to PHP-FPM to handle user errors

I know this has been asked a thousand times, but all the answers that I found simply do not work (for me or usually for the original OP of these questions) ... So, I will try to explain the problem as far as I can, and I hope we can make it work for me and for others who have asked the question before.

My Nginx configuration (with a lot of other unnecessary things removed) looks like this:

http { # Config from here removed server { listen 80; listen 443 ssl; server_name mydomain.co.uk; ssl_certificate /xxxxxxx.crt; ssl_certificate_key /xxxxxxx.key; # Custom error pages root /var/www/viovet_frontend; error_page 404 = /error404.php; # Any simple .php page location ~ \.php$ { root /var/www/xxxxxx; #index index.php index.html; include /etc/nginx/fastcgi.conf; fastcgi_pass phpfastcgiservers; include fastcgi_params; fastcgi_intercept_errors on; } # Lots more config and re-write rules here removed } upstream phpfastcgiservers { server xxxxx1:9001; server xxxxx2:9001; server xxxxx3:9001; fair; } } 

All I'm trying to do is get Nginx to catch all 404s and send them back to PHP-FPM via location ~ \.php$ so that the user error page shows up to the user, but I always get the standard Nginx error page.

The following URLs should display the output of mydomain.co.uk/error404.php :

  • mydomain.co.uk/someNonExistantFile (does not match any location blocks)
  • mydomain.co.uk/someMissingFile.php (corresponds to the location block of the .php file, but the file does not exist)

But they actually show the standard Nginx 404 page. If location ~ \.php$ returns another error code in 404 (for example, 5xx), then we donโ€™t want to interfere, we just return the contents and headers that FastCGI returned first.

I hope this makes sense and that someone can help. Thank you in advance.

EDIT: I tried adding recursive_error_pages on; to the line after # Custom error pages , but this actually leads to the fact that all Nginx 404 Not Found errors become Nginx 500 Internal Server Error errors.

EDIT: Adding Other Files: /etc/nginx/fastcgi.conf

 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; 

fastcgi_params

 fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; 

I guess I probably don't need both of them !; -)

+8
source share
5 answers

I finally worked on it. Thank you all for your advice and take the time to write an answer.

The problem is that our error404.php returned our error page with a 404 Not Found header('HTTP/1.0 404 Not Found'); too (using header('HTTP/1.0 404 Not Found'); ), and Nginx then caught this error because recursive_error_pages disabled (by default) , and he displayed his own 404 pages. Turning off fastcgi_intercept_errors is the solution. If we remove header('HTTP/1.0 404 Not Found'); from the error file, we get an error, but with 200 , which, obviously, is not what we want.

This, however, does not solve the problem of accessing the missing page that ends in .php (therefore, it corresponds to the location block, since now we are returning the standard PHP-FPM response in response to the 404 header with body File not found. . I could use Nate answer to get around this, but I donโ€™t need to provide all the file names there, Iโ€™ll look for another solution for this and post it here when I receive it.

EDIT: more complete solution:

You need to catch errors in your main php location block ( fastcgi_intercept_errors is on ), and then add another block for error pages where you don't catch them. See this configuration example:

  server { listen 80; listen 443 ssl; server_name mydomain.co.uk; ssl_certificate /xxxxxxx.crt; ssl_certificate_key /xxxxxxx.key; # Custom error pages recursive_error_pages off; error_page 404 = /http_errors/404.php; # error_page 500 501 502 503 504 = /error5xx.php; # Not sure about this yet! # Any simple .php page location ~ \.php$ { root /var/www/xxxxx; include /etc/nginx/fastcgi.conf; fastcgi_pass phpfastcgiservers; include fastcgi_params; fastcgi_intercept_errors on; } # Handling error pages location ^~ /http_errors/ { internal; root /var/www/xxxxx; include /etc/nginx/fastcgi.conf; fastcgi_pass phpfastcgiservers; include fastcgi_params; fastcgi_intercept_errors off; } } 

This will mean that any of your PHP pages returning an HTTP 404 status code will have its own content (if any) that will be ignored, and the contents of your /http_errors/404.php file will be used /http_errors/404.php .

+10
source share

I believe that what you ask for is not possible using nginx alone - unless you manually configure each known .php file. If you can list known .php files, you can discover the expected 404 based on this information. Instead of writing all .php files with a regular expression, you specify known php files:

Replace location ~ \.php$ {} with something like:

location ~ ^ / (index | foo | bar | admin / index) .php $ {}

However, this will not lead to a 404 failure generated by your machine php-fpm if a request for a supposedly known php file such as index.php returns 404 even if you told nginx that it should exist.

The complete solution will most likely require an additional server in front of your nginx server, which detects a 404 response from php-fpm / nginx, which then proxies another request back and forth to your server for the error404.php file. You will still encounter the problem of your error404.php file, which also returns 404 itself. I looked at Varnish to find out if the detected 404 can generate a second request to the source server for the error page, but unfortunately vcl_backend_error can only serve 404 or retry the request. Varnish - or something similar - may have some way to accomplish what you want, but it will not be easy.

All I can say is one of the reasons why most people do not configure nginx and php-fpm on different machines - it causes such headaches. If possible, you should consider keeping nginx and php-fpm on the same computer and downloading the balancing of these servers. No matter what benefit you think you get from sharing them, there are probably no additional problems.

+1
source share

The location ~ \.php$ block requires verification of try_files. If it does not exist, return 404 and your 404.php error will take it.

 http { # Config from here removed server { listen 80; listen 443 ssl; server_name mydomain.co.uk; ssl_certificate /xxxxxxx.crt; ssl_certificate_key /xxxxxxx.key; root /var/www/xxxxxx; # Custom error pages error_page 404 = /error404.php; # Any simple .php page location ~ \.php$ { try_files $uri =404; include /etc/nginx/fastcgi.conf; fastcgi_pass phpfastcgiservers; include fastcgi_params; fastcgi_intercept_errors on; } # Lots more config and re-write rules here removed } upstream phpfastcgiservers { server xxxxx1:9001; server xxxxx2:9001; server xxxxx3:9001; fair; } } 
0
source share

"root / var / www / xxxxxx;" must be outside the block "location ~ .php $" and before "error_page 404 = / error404.php;"

If you still canโ€™t get the desired 404 page with error404.php, I suggest you start debugging using a standard copy of the nginx.conf file, and then submit your error_page because we offered a job. I used the same configurations for my own server.

If it still does not work, it should be an upstream problem.

You also want to check

enable / etc / nginx / fastcgi.conf; enable fastcgi_params;

to see if there are any outcasts. There may be some duplicate variables.

General rule for debugging. Reduce the variables. Start with a simple configuration and complete your order to customize it.

0
source share

The right way

error_page 404 /path/to/404.php;

I know this works because I recently created an application and it was a setting for error handling. note that I use URL rewriting to remove index.php from requests for each directory. This way you can configure your script error to write information to your database, which can be useful for complex ajax debugging errors, among other things:

  error_page 500 /error/?t=500; error_page 501 /error/?t=501; error_page 502 /error/?t=502; error_page 503 /error/?t=503; error_page 400 /error/?t=400; error_page 401 /error/?t=401; error_page 403 /error/?t=403; error_page 404 /error/?t=404; error_page 405 /error/?t=405; error_page 406 /error/?t=406; error_page 413 /error/?t=413; error_page 414 /error/?t=414; error_page 418 /error/?t=418; # i'm a teapot 
0
source share

All Articles