Nginx-передать все 404 ошибки обратно в PHP-FPM для обработки пользовательских страниц ошибок

Я знаю, что это было задано тысячу раз, но все ответы, которые я нашел, просто не работают (для меня или обычно оригинального OP этих вопросов)... Поэтому я постараюсь объяснить проблему как можно лучше, и надеюсь, что мы сможем заставить ее работать на меня и на других, кто спрашивал раньше.

моя конфигурация Nginx (с большим количеством других ненужных вещей удалена) выглядит следующим образом:

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;
    }
}

все, что я пытаюсь сделать, это заставить Nginx поймать все 404s и отправить их обратно в PHP-FPM через location ~ .php$ для отображения пользовательской страницы ошибок, но я всегда получаю стандартную страницу ошибок Nginx.

следующие URL-адреса должны показывать выходные данные mydomain.co.uk/error404.php:

  • мидомен.co.uk / someNonExistantFile (не соответствует блокам местоположения)
  • mydomain.co.uk/someMissingFile.php (соответствует .php файл расположение блока, но файл не существует)

но они на самом деле показывают стандартный Nginx 404 страница. Если location ~ .php$ возвращает другой код ошибки 404 (e.g 5xx) тогда мы не хотим участвовать, просто верните контент и заголовки, которые FastCGI вернул в первую очередь.

Я надеюсь, что имеет смысл и что кто-то может помочь. Заранее спасибо.

EDIT: я пробовал добавлять recursive_error_pages on; в строке после # Custom error pages но это на самом деле вызывает все Nginx 404 Not Found ошибки, чтобы стать Nginx 500 Internal Server Error ошибки.

EDIT: добавление других файлов: /и т. д./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;

Я думаю, что мне, вероятно, не нужны оба из них в любом случае! ;-)

5 ответов


я, наконец, понял большую часть этого. Спасибо всем за Ваши советы и время, чтобы написать ответ.

проблема в том, что наши error404.php возвращал нашу страницу с ошибкой 404 не найден заголовок тоже (используя header('HTTP/1.0 404 Not Found');) и Nginx затем перехватывал эту ошибку как recursive_error_pages выключен (по умолчанию), и он показывал свою собственную страницу 404. Выключение fastcgi_intercept_errors это решение. Если убрать header('HTTP/1.0 404 Not Found'); из файла ошибки, тогда мы получим ошибку, но с 200 что явно не то, чего мы хотим.

это, однако, не решит проблему доступа к отсутствующей странице, которая заканчивается .php (таким образом, он соответствует блоку местоположения, поскольку мы теперь возвращаем стандартный ответ PHP-FPM на заголовок 404 с телом File not found.. Я мог бы использовать ответ Нейта чтобы обойти это, но я бы предпочел не указывать все имена файлов там. Я буду искать другое решение для этого и опубликовать его здесь, когда я получу один.

EDIT: более полное решение:

вам нужно перехватить ошибки в вашем основном блоке местоположения php (fastcgi_intercept_errors is on), а затем еще один блок для ваших страниц ошибок, где вы их не перехватываете. См. этот пример конфигурации:

    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;
            }
}

это будет означать, что любая из ваших PHP-страниц, которые возвращают код состояния HTTP 404, будет иметь свой собственный контент (если таковой имеется) и содержимое вашего /http_errors/404.php файл будет использоваться вместо.


Я считаю, что то, что вы просите, невозможно только с nginx - если вы не настроите все известные .php-файл вручную. Если вы можете перечислить известные .php файлы, вы можете обнаружить ожидаемый 404 на основе этой информации. Вместо того, чтобы захватить все .php файлы с регулярным выражением, вы указываете известные php файлы:

заменить location ~ \.php$ {} примерно так:

местоположение ~ ^ / (index|foo|bar/admin / index).php$ {}

Это однако не захватите 404, сгенерированный вашим вне машины php-fpm, если запрос на предположительно известный php-файл, такой как .в PHP возвращает 404, хотя вы сказали nginx, что он должен существовать.

полное решение, вероятно, потребует дополнительного сервера перед ваш сервер nginx, который обнаруживает ответ 404 от php-fpm / nginx, который затем будет прокси другой запрос туда и обратно на ваш сервер для error404.в PHP. Вы все еще столкнетесь с проблемой вашего error404.в PHP файл также возвращает сам 404. Я заглянул в лак чтобы узнать, может ли обнаруженный 404 генерировать второй запрос на исходный сервер для страницы ошибки, но, к сожалению,vcl_backend_error может служить только 404 или повторить запрос. Лак - или что - то подобное-может иметь какой-то способ выполнить то, что вы хотите, но это будет нелегко.

все что я могу сказать, это одна из причин, почему большинство людей не настраивают nginx и php-fpm на разных машинах - это вызывает такие головные боли. Если возможно, вы действительно должны рассмотреть возможность сохранения nginx и php-fpm на одном компьютере и балансировки нагрузки на этих серверах. Какую бы пользу вы ни получали от их разделения, она, вероятно, не стоит дополнительных проблем.


на location ~ \.php$ блок требует try_files для проверки существования файла. Если не существует, верните 404 и ваш error404.php возьмет его.

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;
    }
}

ваш "root / var / www / xxxxxx;" должен быть за пределами "местонахождения ~ .php$ " блок и до "ошибки 404 = /error404.php;"

Если вы все еще не можете получить нужную страницу 404 из error404.php, я предлагаю вам начать отладку, используя стандартную копию nginx.conf, а затем настройте свой error_page оттуда, потому что то, что мы предложили, работает. Я использовал те же конфигурации для собственного сервера.

Если он все еще не работает, он должен проблема апстрима.

вы также хотите проверить свой

включить /и т. д./nginx/FastCGI-сервера.conf; включают fastcgi_params;

чтобы узнать, есть ли какие-либо переменные-изгои. Там могут быть дубликаты переменных.

общее эмпирическое правило при отладке. Снизить переменные. Начните с простой конфигурации и работать свой путь до пользовательских его.


правильно

error_page 404 /path/to/404.php;

Я знаю, что это работает, потому что я недавно создал приложение, и это была настройка для обработки ошибок. пожалуйста, обратите внимание, что я использую url rewriting to remove index.php запросов для каждого каталога. Таким образом, вы можете настроить свой сценарий ошибок для регистрации информации в базе данных, что может быть полезно для сложной отладки ошибок ajax, среди прочего:

    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