I know this has been asked a thousand times, but all of the answers I'm found simply don't work (for me or usually the original OP of those questions)... So, I'll try to explain the problem as best as I possibly can and hopefully we can get it working for me and for others who have asked before.
My Nginx config (with lots of other irrelevant stuff removed) is as follows:
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$
to have a custom error page shown to the user, but I always get the standard Nginx error page.
The following urls should all show the output of mydomain.co.uk/error404.php
:
But they actually show the standard Nginx 404 page. If the location ~ \.php$
returns a different error code to 404 (e.g 5xx) then we don't want to get involved, just return the content and headers that FastCGI returned in the first place.
I hope that makes sense and that someone can help. Thank you in advance.
EDIT: I have tried adding recursive_error_pages on;
to the line after # Custom error pages
but this actually causes all Nginx 404 Not Found
errors to 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 these anyway! ;-)
I've finally worked most of it out. Thanks everyone for your tips and putting the time in to write answer.
The issue is that our error404.php
was returning our error page with an 404 Not Found header too (using header('HTTP/1.0 404 Not Found');
) and Nginx was then intercepting this error as recursive_error_pages
is off (default) and it was showing its own 404 page. Switching off fastcgi_intercept_errors
is the solution. If we remove the header('HTTP/1.0 404 Not Found');
from the error file then we'd get the error but with a 200
which is obviously not what we want.
This does not, however, solve the problem of accessing a missing page which ends with .php
(so it matches the location block as we are now getting back the standard PHP-FPM response to those of a 404 header with the body File not found.
. I could use Nate's answer to get around this, but I'd rather not need to specify all the file names there. I'll look for another solution for this and post it here when I get one.
EDIT: A more full solution:
You need to intercept errors in your main php location block (fastcgi_intercept_errors
is on
) and then have another block for your error pages where you don't intercept them. See this config 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 which return an HTTP status code of 404 will have their own content (if any) ignored and the content of your /http_errors/404.php
file will be used instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With