Come impostare una pagina di errore di fallback in nginx?


10

Al momento sto configurando la gestione da parte di nginx di alcune pagine di errore e altri file multimediali "predefiniti" (come favicon.ico e robots.txt) al momento e ho riscontrato un piccolo problema nel far funzionare le cose come voglio per determinate pagine di errore .

Fondamentalmente, quello che sto cercando di fare è servire determinati file per un server nella root per quel server, ad esempio /var/www/someserver.com/robots.txt. Se quel file non esiste, voglio che nginx vada al "default", cioè /var/www/default/robots.txt. Questa è la sintesi di come ho configurato (con successo):

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

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

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

Funziona benissimo.

Sto cercando di fare lo stesso per le pagine di errore e non sono in grado di farlo accadere però:

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

    error_page 404   /404.html;

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

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

Nota che questo "funziona" nel senso che se visiti someserver.com/404.html, proverà prima a caricare /var/www/someserver.com/404.html e poi tornerà a / var / www / default /404.html se non trovato. Tuttavia, se visiti someserver.com/blahblah, mostra la pagina 404 solo se è impostata in /var/www/someserver.com/. Non torna alla directory predefinita se quel file non esiste.

Ad ogni modo, puoi probabilmente quello che stavo cercando di realizzare (ecco perché ho incluso il primo esempio funzionante).

Qualche idea?

Modificare:

Basato sulla risposta di Martin F, questo è quello che ho finito per mettere insieme:

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

Funziona benissimo. Il blocco effettivo di pagine_errore e posizioni sopra si trova in un file server_defaults.conf che viene incluso in ogni host virtuale, motivo per cui non ho programmato a fondo il percorso in ogni posizione e utilizzato un percorso relativo per i valori predefiniti.

Modifica 2:

Questo approccio ha un problema. Se si POST a un URL che restituisce un errore, il metodo di richiesta POST viene inviato con i tentativi try_files. Questo (per me) provoca un errore 405 non consentito, perché nginx sta essenzialmente tentando di POST ad es. /Default/500.html invece di ottenere solo quella pagina.

Modifica 3:

Ho pubblicato una soluzione che funziona molto più vicino alla mia idea originale.

Risposte:


10

Ho finito per andare con qualcosa di molto più vicino alla mia idea originale. La chiave che mi mancava si rivelò essere la direttiva recursive_error_pages. Tutto quello che dovevo davvero fare era attivare questo "e la mia idea originale ha funzionato. Ecco come appare ora la parte rilevante della mia 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;
    }
}

Ho incluso altri tipi di errore che non facevano parte della mia domanda originale qui perché questo è ciò che alla fine mi ha causato difficoltà con l'approccio di Martin F, che altrimenti era eccellente. La log_not_founddirettiva assicura solo che non riesco a visualizzare 404s nel mio registro quando la pagina di errore non viene trovata nella radice originale.


Funziona alla grande (specialmente con la combinazione 404 / POST) ma sembra ingoiare il codice di errore HTTP e invia 200 ... Hai lo stesso comportamento di me?
ottobre

2
Potresti voler rimuovere log_not_found off;e aggiungere internal;invece.
Alix Axel,

Il problema che hai riscontrato con una richiesta POST che ha provocato un errore è un comportamento strano di nginx, vedi trac.nginx.org/nginx/ticket/824
Robo

5

try_files è la strada da percorrere qui. La seguente configurazione dovrebbe funzionare, ma non l'ho testata per errori di sintassi.

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

Sì, è esattamente quello di cui avevo bisogno. Avevo provato a usare try_files ma la tua risposta mi ha portato a rendermi conto che dovevo creare una posizione interna speciale per questo. Ho modificato la mia risposta per mostrare la configurazione che ha funzionato per me, che presenta alcune modifiche a ciò che mi hai suggerito.
Jim D,

Vedi la mia modifica 2 sopra. Da quello che posso dire, questo suggerimento non funziona con le richieste POST. Poiché try_files utilizza il metodo di richiesta della richiesta originale, si ottiene una risposta 405 non consentita.
Jim D,

@JimD: Beh, non usi esattamente questo approccio, ne usi uno modificato. Questo funziona per me. Prova ad aggiornare il tuo binario Nginx se è più vecchio di 0.8.x
Martin Fjordvald

Bene, il problema è che sto usando questo per più di soli 404s, motivo per cui devo fare error_page -> location -> try_files invece di location -> try_files -> location -> try_files come sei. Sono comunque su un binario 0.7.x da un pacchetto, quindi proverò a costruirlo dal sorgente e vedere se questo lo risolve.
Jim D,

2

Purtroppo sono in ritardo di un paio di anni con la mia risposta, ma ho pensato che potesse aiutare i futuri ricercatori. La mia versione di Nginx installata è 1.2.4 e ho creato il seguente frammento di configurazione,

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

}

1
Buon uso di internal.
Clint Pachl,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.