2014-04-16 21 views
8

Tôi biết điều này đã được hỏi hàng nghìn lần, nhưng tất cả các câu trả lời tôi thấy không hoạt động (đối với tôi hoặc thường là bản gốc) OP của những câu hỏi đó) ... Vì vậy, tôi sẽ cố gắng giải thích vấn đề tốt nhất có thể và hy vọng chúng tôi có thể làm cho nó hoạt động cho tôi và cho những người khác đã hỏi trước đó.Nginx - Chuyển tất cả 404 lỗi về PHP-FPM để xử lý lỗi tùy chỉnh

My Nginx cấu hình (với rất nhiều thứ không liên quan khác bị loại bỏ) là như sau:

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

Tất cả tôi đang cố gắng để làm là có được Nginx để đón tất cả 404s và gửi lại cho PHP-FPM qua location ~ \.php$ để có trang lỗi tùy chỉnh được hiển thị cho người dùng, nhưng tôi luôn nhận được trang lỗi Nginx chuẩn. tất cả

Các url sau đây sẽ hiển thị đầu ra của mydomain.co.uk/error404.php:

  • mydomain.co.uk/someNonExistantFile (không phù hợp với bất kỳ khối địa điểm)
  • mydomain.co.uk/someMissingFile.php (khớp với khối vị trí tệp .php nhưng tệp không tồn tại)

Nhưng chúng thực sự hiển thị trang Nginx 404 chuẩn. Nếu số location ~ \.php$ trả về mã lỗi khác 404 (ví dụ 5xx) thì chúng tôi không muốn tham gia, chỉ cần trả lại nội dung và tiêu đề mà FastCGI trả lại ngay từ đầu.

Tôi hy vọng điều đó có ý nghĩa và ai đó có thể trợ giúp. Cảm ơn bạn trước.

EDIT: Tôi đã cố gắng thêm recursive_error_pages on; vào dòng sau # Custom error pages nhưng điều này thực sự gây ra tất cả Nginx 404 Not Found lỗi để trở thành Nginx 500 Internal Server Error lỗi.

EDIT: Thêm file khác: /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; 

Tôi đoán tôi có lẽ không cần cả hai những thứ này! ;-)

+0

Hãy thử di chuyển root/var/www/xxxx bên ngoài vị trí của bạn ~ php. – CrazySabbath

+0

PHP-FPM và Nginx có trên các máy khác nhau. Làm điều này (một mình) sẽ không giúp Nginx gửi nó trở lại PHP-FPM. –

Trả lời

10

Cuối cùng tôi đã làm việc nhiều nhất. Cảm ơn tất cả mọi người cho lời khuyên của bạn và dành thời gian để viết câu trả lời.

Vấn đề là error404.php chúng tôi được trở về trang lỗi của chúng tôi với một tiêu đề 404 Not Found quá (sử dụng header('HTTP/1.0 404 Not Found');) và Nginx sau đó đã chặn lỗi này như recursive_error_pages tắt (mặc định) và nó đã cho thấy đó là của riêng trang 404. Tắt fastcgi_intercept_errors là giải pháp. Nếu chúng tôi xóa header('HTTP/1.0 404 Not Found'); khỏi tệp lỗi thì chúng tôi sẽ gặp lỗi nhưng với 200 rõ ràng không phải là điều chúng tôi muốn. Tuy nhiên, điều này không giải quyết được vấn đề truy cập một trang bị thiếu kết thúc bằng .php (vì vậy nó khớp với khối vị trí khi chúng tôi đang lấy lại phản hồi PHP-FPM tiêu chuẩn cho các tiêu đề 404 với phần thân File not found..Tôi có thể sử dụng Nate's answer để có được xung quanh này, nhưng tôi không muốn chỉ định tất cả các tên tập tin ở đó.Tôi sẽ tìm một giải pháp cho điều này và đăng nó ở đây khi tôi nhận được một.

EDIT: Một giải pháp đầy đủ hơn:

Bạn cần phải ngăn chặn những sai sót trong khối vị trí php chính của bạn (fastcgi_intercept_errorson) và sau đó có một khối cho các trang báo lỗi của bạn mà bạn không chặn chúng. Xem ví dụ này cấu hình:

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

Điều này sẽ có nghĩa là bất kỳ trang PHP của bạn mà trả về một mã trạng thái HTTP 404 sẽ có nội dung riêng của họ (nếu có) bỏ qua và nội dung của tập tin /http_errors/404.php của bạn sẽ được sử dụng thay .

+1

Wow, đào tạo công việc tốt đẹp - Tôi tò mò muốn thử các chỉ thị nginx mới mà tôi không biết. Thành thật mà nói bạn nên có tiền thưởng của riêng bạn. :) –

+0

Mục đích của '/ http_errors /' là gì? Có một khối vị trí khớp với '404.php' hoạt động. –

0

Khối location ~ \.php$ yêu cầu try_files để kiểm tra sự tồn tại của tệp. Nếu không tồn tại, trả về 404, và error404.php của bạn sẽ lấy nó.

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

Cảm ơn, nhưng PHP-FPM là trên các máy khác nhau để Nginx, và các máy Nginx không có các tập tin PHP. Làm thế nào sẽ try_files biết họ tồn tại/không tồn tại? Ngoài ra, cách này sẽ giải quyết các url như 'mydomain.co.uk/someNonExistantFile' không khớp với bất kỳ khối vị trí nào? –

0

"root/var/www/xxxxxx;" của bạn phải là bên ngoài của khối "vị trí ~ .php $" và trước "error_page 404 = /error404.php;"

Nếu bạn vẫn không thể nhận được trang 404 mong muốn từ error404.php, tôi đề nghị bạn bắt đầu gỡ lỗi bằng cách sử dụng một bản sao chuẩn của nginx.conf và sau đó tùy chỉnh error_page của bạn từ đó vì những gì chúng tôi đề xuất hoạt động. Tôi đã sử dụng cùng một cấu hình cho máy chủ của riêng mình.

Nếu nó vẫn không hoạt động, nó phải là một vấn đề ngược dòng.

Bạn cũng muốn kiểm tra

bao gồm /etc/nginx/fastcgi.conf; bao gồm fastcgi_params;

để xem có bất kỳ biến số giả mạo nào không. Có thể có một số biến trùng lặp ở đó.

Quy tắc chung về cách gỡ lỗi. Giảm các biến của bạn. Bắt đầu với một cấu hình đơn giản và làm việc theo cách của bạn để tùy chỉnh nó.

+0

Xin chào, cảm ơn vì đề xuất này, nhưng điều này không hiệu quả. Tôi đã thêm dòng ngay trước 'error_page 404 = /error404.php;' và nó không tạo ra sự khác biệt. Chúng tôi cũng có các khối vị trí khác không được bao gồm trong đoạn mã trên là các tệp tĩnh, hình ảnh, css, v.v. tải trực tiếp từ máy Nginx. Các cá thể PHP-FPM nằm trên các máy khác. Các máy Nginx không có các tập tin php trên chúng mà tôi nghĩ là tại sao nó không nghĩ rằng nó có thể tìm thấy nó. Tôi sẽ thêm fastcgi_params và fastcgi.conf của tôi vào câu hỏi chính nhưng tôi nghĩ rằng họ là ok như mọi thứ khác hoạt động –

+0

Tôi là một chút bối rối bởi bình luận của bạn dưới đây cho Tân. "Máy Nginx không có tệp PHP." Tôi chắc chắn rằng proxy_pass đến thượng nguồn sẽ phục vụ các tệp php được chỉ định trong thư mục gốc/var/www/xxxxxx; Bạn đã đặt proxy_pass http: // phpfastcgiservers; ? – RyanYJL

1

Tôi tin rằng những gì bạn đang yêu cầu là không thể với nginx một mình - trừ khi bạn cấu hình mỗi và mọi tệp .php đã biết theo cách thủ công. Nếu bạn có thể liệt kê các tệp .php đã biết, bạn có thể phát hiện 404 dự kiến ​​dựa trên thông tin này. Thay vì chụp tất cả các file .php với một biểu thức chính quy, bạn chỉ định file php biết:

Thay location ~ \.php$ {} với một cái gì đó như:

vị trí ~ ^/(index | foo | thanh | admin/index). php $ {}

này sẽ tuy nhiên không phải chụp một 404 được tạo ra bởi máy off-php-fpm của bạn nếu một yêu cầu cho một tập tin php được cho là nổi tiếng như index.php trả 404 mặc dù bạn đã nói nginx nó nên tồn tại.

Một giải pháp đầy đủ có thể sẽ yêu cầu một máy chủ bổ sung trước máy chủ nginx bạn phát hiện một phản ứng 404 từ php-fpm/nginx, mà sẽ sau đó proxy khác yêu cầu khứ hồi để hỗ trợ của bạn cho error404. php tệp. Bạn vẫn gặp phải sự cố về tệp error404.php của bạn cũng trả về bản thân 404. Tôi đã xem xét Varnish để xem liệu 404 được phát hiện có thể tạo yêu cầu thứ hai tới máy chủ gốc cho trang lỗi hay không, nhưng tiếc là vcl_backend_error chỉ có thể phục vụ 404 hoặc thử lại yêu cầu. Varnish - hoặc một cái gì đó tương tự - có thể có một số cách để thực hiện những gì bạn muốn, nhưng nó sẽ không dễ dàng.

Tất cả những gì tôi có thể nói là đây là một lý do tại sao hầu hết mọi người không thiết lập nginx và php-fpm trên các máy khác nhau - nó gây đau đầu như thế này. Nếu có thể, bạn thực sự nên xem xét việc giữ nginx và php-fpm trên cùng một máy và cân bằng tải những máy chủ đó. Dù lợi ích bạn tin rằng bạn đang nhận được từ tách chúng có lẽ không có giá trị các vấn đề thêm.

+0

Cảm ơn @Nate, có lẽ sẽ dễ dàng hơn để có được Nginx trên ba máy PHP-FPM và trao đổi hai máy Nginx hiện tại trước mặt chúng sử dụng HAProxy để cân bằng tải. Tôi nghĩ rằng phải có nhiều hơn để giải quyết phần 1 (tập tin không phù hợp với bất kỳ khối địa điểm) như hiện tại nếu tôi truy cập mydomain.co.uk/NoMatchingLocationBlock Tôi vẫn không nhận được trang 404 chính xác và không phù hợp với bất kỳ khối nào. Điều đó có ý nghĩa? –

+0

Cảm ơn Nate, tôi đã trao cho bạn tiền thưởng như câu trả lời của bạn không hoàn toàn giải quyết tất cả các vấn đề, nó là gần nhất. Tôi đã đăng một câu trả lời dưới đây mà khi kết hợp với bạn sẽ giải quyết tất cả các vấn đề, nhưng tôi không muốn chỉ định tất cả các tên tập tin php nếu tôi có thể nhận được ngay với nó. –

0

Cách đúng

error_page 404 /path/to/404.php;

Tôi biết nó hoạt động, vì tôi đã xây dựng một ứng dụng gần đây và đây là thiết lập để xử lý lỗi. xin lưu ý tôi sử dụng url viết lại để loại bỏ index.php từ yêu cầu cho mỗi thư mục. Bằng cách này bạn có thể thiết lập kịch bản lỗi của bạn để đăng nhập thông tin cho cơ sở dữ liệu của bạn, mà có thể hữu ích cho rất khó để lỗi debug ajax, trong số những thứ khác:

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

Tôi lấy nó mà bạn không đọc câu hỏi? Nó phức tạp hơn rất nhiều so với PHP và Nginx trên các máy riêng biệt theo thiết lập của chúng tôi ở trên, bạn muốn các tiêu đề chính xác và cũng có 404 bị ném vì các tệp không tồn tại và được ném trong mã php cho một tệp không tồn tại. –

+0

@LukeCousins ​​lỗi của tôi && lời xin lỗi – r3wt

Các vấn đề liên quan