Jak skonfigurować zastępczą stronę błędów w Nginx?

10

W tej chwili konfiguruję obsługę niektórych stron błędów i innych „domyślnych” plików multimedialnych (takich jak favicon.ico i robots.txt) przez nginx i napotkałem drobny problem z działaniem tak, jak chcę, dla niektórych stron błędów .

Zasadniczo to, co próbuję zrobić, to podać pewne pliki dla serwera w katalogu głównym dla tego serwera, np. /Var/www/someserver.com/robots.txt. Jeśli ten plik nie istnieje, chcę, aby nginx przeszedł do „domyślnej”, tj. /Var/www/default/robots.txt. Oto podstawowa informacja o tym, jak skonfigurowałem (pomyślnie):

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

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

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

To działa świetnie.

Próbuję zrobić to samo dla stron błędów, ale nie jestem w stanie tego zrobić:

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

    error_page 404   /404.html;

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

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

Zauważ, że to „działa” w tym sensie, że jeśli odwiedzasz someserver.com/404.html, najpierw spróbuje załadować /var/www/someserver.com/404.html, a następnie wróci do / var / www / default /404.html, jeśli nie zostanie znaleziony. Jeśli jednak odwiedzisz someserver.com/blahblah, wyświetli stronę 404 tylko wtedy, gdy jest ustawiona w /var/www/someserver.com/. Nie wraca do domyślnego katalogu, jeśli ten plik nie istnieje.

W każdym razie możesz prawdopodobnie to, co próbowałem osiągnąć (dlatego podałem pierwszy działający przykład).

Jakieś pomysły?

Edytować:

Na podstawie odpowiedzi Martina F. skończyłem razem:

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

To działa świetnie. Rzeczywisty blok powyższych stron błędów i lokalizacji znajduje się w pliku server_defaults.conf, który jest dołączany do każdego wirtualnego hosta, dlatego nie zapisałem na stałe ścieżki do każdej lokalizacji i użyłem ścieżki względnej dla wartości domyślnych.

Edycja 2:

Takie podejście ma problem. Jeśli wykonasz test POST pod adresem URL, który zwraca błąd, metoda żądania POST zostanie wysłana przy próbach try_files. To (dla mnie) powoduje błąd 405 niedozwolony, ponieważ nginx zasadniczo próbuje POST np. Do /default/500.html zamiast po prostu pobrać tę stronę.

Edycja 3:

Opublikowałem rozwiązanie, które działa znacznie bliżej mojego oryginalnego pomysłu.

Jim D.
źródło

Odpowiedzi:

10

Skończyło się na czymś znacznie bliższym mojemu pierwotnemu pomysłowi. Kluczem, którego mi brakowało, okazała się dyrektywa recursive_error_pages. Wszystko, co naprawdę musiałem zrobić, to włączyć to i mój oryginalny pomysł zadziałał. Oto jak teraz wygląda odpowiednia część mojego conf:

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

Włączyłem tutaj inne typy błędów, które nie były częścią mojego pierwotnego pytania, ponieważ to właśnie spowodowało mi trudności z podejściem Martina F. log_not_foundDyrektywa zapewnia, że po prostu nie rozumiem błędy 404 w moim dzienniku, gdy strona nie zostanie znaleziony błąd w oryginalnym root.

Jim D.
źródło
Działa to greate (szczególnie w przypadku kombinacji 404 / POST), ale wydaje się, że połyka kod błędu HTTP i wysyła 200 ... Czy zachowujesz się tak samo jak ja?
Paź
2
Zamiast tego możesz chcieć usunąć log_not_found off;i dodać internal;.
Alix Axel,
Problem, który zauważyłeś w wyniku żądania POST skutkującego błędem, to dziwne zachowanie nginx, patrz trac.nginx.org/nginx/ticket/824
Robo
5

Try_files to sposób, aby przejść tutaj. Poniższa konfiguracja powinna działać, ale nie przetestowałem jej pod kątem błędów składniowych.

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
źródło
Tak, właśnie tego potrzebowałem. Próbowałem użyć plików try_files, ale twoja odpowiedź uświadomiła mi, że muszę stworzyć dla niej specjalną wewnętrzną lokalizację. Zmodyfikowałem swoją odpowiedź, aby pokazać konfigurację, która działała dla mnie, która zawiera kilka poprawek do tego, co zasugerowałeś.
Jim D
Zobacz moją edycję 2 powyżej. Z tego, co mogę powiedzieć, ta sugestia nie działa z żądaniami POST. Ponieważ try_files używa metody żądania z pierwotnego żądania, otrzymujesz odpowiedź 405 Niedozwolona.
Jim D
@JimD: Cóż, nie używasz tego podejścia, używasz zmodyfikowanego. To działa dla mnie. Spróbuj zaktualizować swój plik binarny Nginx, jeśli jest starszy niż 0.8.x
Martin Fjordvald
Problem polega na tym, że używam tego przez więcej niż 404 s, i dlatego muszę robić error_page -> lokalizację -> try_files zamiast lokalizacji -> try_files -> lokalizację -> try_files tak jak ty. Jestem jednak na pakiecie binarnym 0.7.x z pakietu, więc spróbuję zbudować go ze źródła i sprawdzić, czy to rozwiąże.
Jim D
2

Niestety spóźniłem się z odpowiedzią kilka lat, ale pomyślałem, że może to pomóc przyszłym poszukiwaczom. Moja zainstalowana wersja Nginx to 1.2.4 i utworzyłem następujący fragment konfiguracji,

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
źródło
1
Dobre wykorzystanie internal.
Clint Pachl