Wie richte ich eine Fallback-Fehlerseite in Nginx ein?

10

Ich konfiguriere derzeit die Behandlung einiger Fehlerseiten und anderer "Standard" -Datendateien (wie favicon.ico und robots.txt) durch nginx und habe ein kleines Problem damit, dass die Dinge für bestimmte Fehlerseiten so funktionieren, wie ich es möchte .

Grundsätzlich versuche ich, bestimmte Dateien für einen Server unter dem Stammverzeichnis für diesen Server bereitzustellen, z. B. /var/www/someserver.com/robots.txt. Wenn diese Datei nicht vorhanden ist, möchte ich, dass nginx zum "Standard" wechselt, dh /var/www/default/robots.txt. Dies ist der Grundgedanke, wie ich das (erfolgreich) konfiguriert habe:

server {
    ...
    root /var/www/someserver.com;

    location ~* ^/(robots\.txt)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

Das funktioniert super.

Ich versuche, dasselbe für Fehlerseiten zu tun, und ich kann dies jedoch nicht erreichen:

server {
    ...
    root /var/www/someserver.com;

    error_page 404   /404.html;

    location ~* ^/(404\.html)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

Beachten Sie, dass dies in dem Sinne "funktioniert", dass beim Besuch von someserver.com/404.html zunächst versucht wird, /var/www/someserver.com/404.html zu laden, und dann auf / var / www / default zurückgegriffen wird /404.html wenn das nicht gefunden wird. Wenn Sie jedoch someserver.com/blahblah besuchen, wird die 404-Seite nur angezeigt, wenn sie in /var/www/someserver.com/ festgelegt ist. Es wird nicht auf das Standardverzeichnis zurückgegriffen, wenn diese Datei nicht vorhanden ist.

Wie auch immer, Sie können wahrscheinlich das erreichen, was ich erreichen wollte (deshalb habe ich das erste Arbeitsbeispiel beigefügt).

Irgendwelche Ideen?

Bearbeiten:

Basierend auf der Antwort von Martin F habe ich Folgendes zusammengestellt:

# Doesn't work when error page is returned on a POST request
server {
    ...
    root /var/www/someserver.com;

    error_page  404         = @notfound;
    error_page  500 502 504 = @server_error;
    error_page  503         = @maintenance;

    location @notfound {
        try_files /404.html /../default/404.html =404;
    }

    location @server_error {
        try_files /500.html /../default/500.html =500;
    }

    location @maintenance {
        try_files /503.html /../default/503.html =503;
    }
}

Das funktioniert super. Der eigentliche Block der oben genannten error_pages und Speicherorte befindet sich in einer server_defaults.conf-Datei, die in jedem virtuellen Host enthalten ist. Aus diesem Grund habe ich den Pfad nicht fest in jeden Speicherort codiert und einen relativen Pfad für die Standardwerte verwendet.

Bearbeiten 2:

Dieser Ansatz hat ein Problem. Wenn Sie an eine URL POSTEN, die einen Fehler zurückgibt, wird die POST-Anforderungsmethode mit den Versuchen try_files gesendet. Dies führt (für mich) zu einem 405 Not Allowed-Fehler, da nginx im Wesentlichen versucht, POST an z. B. /default/500.html zu senden, anstatt nur diese Seite abzurufen.

Edit 3:

Ich habe eine Lösung veröffentlicht, die meiner ursprünglichen Idee viel näher kommt.

Jim D.
quelle

Antworten:

10

Am Ende hatte ich etwas, das meiner ursprünglichen Idee viel näher kam. Der Schlüssel, den ich vermisste, stellte sich als Direktive heraus recursive_error_pages. Alles was ich wirklich tun musste war dieses "Einschalten" und meine ursprüngliche Idee funktionierte. So sieht der relevante Teil meiner Conf jetzt aus:

server {
    ...

    root /var/www/someserver.com/;

    error_page 400 404      /404.html;
    error_page 500 502 504  /500.html;
    error_page 503          /503.html;

    recursive_error_pages   on;

    location ~* ^/(404\.html|500\.html|503\.html)$ {
        log_not_found off;
        error_page 404 = @default;
    }

    location @default {
        log_not_found on;
        root /var/www/default;
    }
}

Ich habe hier andere Fehlertypen aufgenommen, die nicht Teil meiner ursprünglichen Frage waren, da dies zu Schwierigkeiten mit dem ansonsten hervorragenden Ansatz von Martin F führte. Die log_not_foundDirektive stellt nur sicher, dass ich keine 404s in meinem Protokoll habe, wenn die Fehlerseite nicht im ursprünglichen Stammverzeichnis gefunden wird.

Jim D.
quelle
Dies funktioniert gut (insbesondere in Bezug auf die 404 / POST-Kombination), aber es scheint den HTTP-Fehlercode zu verschlucken und sendet 200 ... Haben Sie das gleiche Verhalten wie ich?
Oktober
2
Möglicherweise möchten log_not_found off;Sie internal;stattdessen entfernen und hinzufügen .
Alix Axel
Das Problem, das Sie bei einer POST-Anfrage festgestellt haben, die zu einem Fehler geführt hat, ist das seltsame Verhalten von nginx, siehe trac.nginx.org/nginx/ticket/824
Robo
5

try_files ist der richtige Weg hierher. Die folgende Konfiguration sollte funktionieren, aber ich habe sie nicht auf Syntaxfehler getestet.

server {
    ...
    root /var/www;

    location / {
        try_files /someserver.com$uri /default$uri /someserver.com$uri/ /default$uri/ @notfound;
    }

    location @notfound {
       try_files /someserver/404.html /default/404.html =404; # =404 should make it use the nginx-default 404 page.
    }
}
Martin Fjordvald
quelle
Ja, genau das brauchte ich. Ich hatte versucht, try_files zu verwenden, aber Ihre Antwort führte mich zu der Erkenntnis, dass ich einen speziellen internen Speicherort dafür erstellen musste. Ich habe meine Antwort bearbeitet, um die für mich funktionierende Konfiguration anzuzeigen, die einige Änderungen an Ihren Vorschlägen enthält.
Jim D
Siehe meine Bearbeitung 2 oben. Soweit ich weiß, funktioniert dieser Vorschlag nicht mit POST-Anfragen. Da try_files die Anforderungsmethode der ursprünglichen Anforderung verwendet, erhalten Sie die Antwort 405 Not Allowed.
Jim D
@ JimD: Nun, Sie verwenden diesen Ansatz nicht genau, Sie verwenden einen modifizierten. Das funktioniert bei mir. Versuchen Sie, Ihre Nginx-Binärdatei zu aktualisieren, wenn sie älter als 0.8.x ist
Martin Fjordvald
Nun, das Problem ist, dass ich dies für mehr als nur 404s benutze, weshalb ich error_page -> location -> try_files anstelle von location -> try_files -> location -> try_files so machen muss, wie Sie sind. Ich bin jedoch auf einer 0.7.x-Binärdatei aus einem Paket, also werde ich versuchen, sie aus dem Quellcode zu erstellen und zu prüfen, ob dies das Problem löst.
Jim D
2

Leider bin ich ein paar Jahre zu spät mit meiner Antwort, aber ich dachte, es könnte den zukünftigen Suchenden helfen. Meine installierte Nginx-Version ist 1.2.4 und ich habe das folgende Konfigurations-Snippet erstellt:

server {

server_name www.example.com
root /var/www/example


## Errors -> Locations
error_page   400 /400.html;
error_page   403 /403.html;
error_page   404 /404.html;
error_page   500 502 503 504 /50x.html;

## Locations -> Fallback
location = /400.html {
    try_files /400.html @error;
    internal;
}
location = /403.html {
    try_files /403.html @error;
    internal;
}
location = /404.html {
    try_files /404.html @error;
    internal;
}
location = /50x.html {
    try_files /50x.html @error;
    internal;
}

## Fallback Directory
location @error {
    root /var/www/error;
}

}
JM Becker
quelle
1
Gute Verwendung von internal.
Clint Pachl