Comment configurer une page d'erreur de secours dans Nginx?

10

Je suis en train de configurer la gestion par nginx de certaines pages d'erreur et d'autres fichiers multimédias "par défaut" (tels que favicon.ico et robots.txt) en ce moment et j'ai rencontré un problème mineur pour que les choses fonctionnent comme je le souhaite pour certaines pages d'erreur .

Fondamentalement, ce que j'essaie de faire est de servir certains fichiers pour un serveur sous la racine de ce serveur, par exemple /var/www/someserver.com/robots.txt. Si ce fichier n'existe pas, je veux que nginx passe au "défaut", c'est-à-dire /var/www/default/robots.txt. C'est l'essentiel de la façon dont j'ai configuré (avec succès):

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

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

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

Cela fonctionne très bien.

J'essaie de faire la même chose pour les pages d'erreur, et je ne suis pas en mesure de le faire cependant:

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

    error_page 404   /404.html;

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

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

Notez que cela "fonctionne" dans le sens où si vous visitez someserver.com/404.html, il essaiera d'abord de charger /var/www/someserver.com/404.html puis retombera dans / var / www / default /404.html si ce n'est pas trouvé. Cependant, si vous visitez someserver.com/blahblah, il n'affiche la page 404 que si elle est définie dans /var/www/someserver.com/. Il ne revient pas au répertoire par défaut si ce fichier n'existe pas.

Quoi qu'il en soit, vous pouvez probablement ce que j'essayais d'accomplir (c'est pourquoi j'ai inclus le premier exemple de travail).

Des idées?

Éditer:

Sur la base de la réponse de Martin F, voici ce que j'ai fini par rassembler:

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

Cela fonctionne très bien. Le bloc réel de error_pages et d'emplacements ci-dessus se trouve dans un fichier server_defaults.conf qui est inclus avec chaque hôte virtuel, c'est pourquoi je n'ai pas codé en dur le chemin d'accès à chaque emplacement et utilisé un chemin d'accès relatif pour les valeurs par défaut.

Modifier 2:

Cette approche a un problème. Si vous POSTEZ sur une URL qui renvoie une erreur, la méthode de demande POST est envoyée avec les tentatives try_files. Cela (pour moi) entraîne une erreur 405 non autorisée, car nginx essaie essentiellement de POSTER par exemple /default/500.html au lieu d'obtenir simplement cette page.

Modifier 3:

J'ai posté une solution qui fonctionne beaucoup plus proche de mon idée d'origine.

Jim D
la source

Réponses:

10

J'ai fini par aller avec quelque chose de beaucoup plus proche de mon idée originale. La clé qui me manquait s'est avérée être la directive recursive_error_pages. Tout ce que j'avais vraiment à faire était d'activer cette fonction et mon idée originale a fonctionné. Voici à quoi ressemble la partie pertinente de ma conf maintenant:

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

J'ai inclus ici d'autres types d'erreurs qui ne faisaient pas partie de ma question d'origine, car c'est ce qui a fini par me poser des problèmes avec l'approche de Martin F, qui était par ailleurs excellente. La log_not_founddirective garantit simplement que je n'obtiens pas de 404 dans mon journal lorsque la page d'erreur n'est pas trouvée dans la racine d'origine.

Jim D
la source
Cela fonctionne bien (en particulier concernant la combinaison 404 / POST) mais il semble avaler le code d'erreur HTTP et envoie 200 ... Avez-vous le même comportement que moi?
octobre
2
Vous souhaiterez peut-être supprimer log_not_found off;et ajouter à la internal;place.
Alix Axel
Le problème que vous avez remarqué avec une requête POST entraînant une erreur est un comportement étrange de nginx, voir trac.nginx.org/nginx/ticket/824
Robo
5

try_files est le chemin à parcourir ici. La configuration suivante devrait fonctionner, mais je ne l'ai pas testée pour les erreurs de syntaxe.

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
la source
Oui, c'est exactement ce dont j'avais besoin. J'avais essayé d'utiliser try_files mais votre réponse m'a amené à réaliser que je devais lui créer un emplacement interne spécial. J'ai édité ma réponse pour montrer la configuration qui a fonctionné pour moi, qui a quelques ajustements à ce que vous avez suggéré.
Jim D
Voir mon montage 2 ci-dessus. D'après ce que je peux dire, cette suggestion ne fonctionne pas avec les requêtes POST. Étant donné que try_files utilise la méthode de demande de la demande d'origine, vous vous retrouvez avec une réponse 405 non autorisée.
Jim D
@ JimD: Eh bien, vous n'utilisez pas exactement cette approche, vous en utilisez une modifiée. Cela fonctionne pour moi. Essayez de mettre à jour votre binaire Nginx s'il est plus ancien que 0.8.x
Martin Fjordvald
Eh bien, le problème est que j'utilise cela pour plus que 404, c'est pourquoi je dois faire error_page -> location -> try_files au lieu de location -> try_files -> location -> try_files comme vous êtes. Je suis cependant sur un binaire 0.7.x à partir d'un package, donc je vais essayer de le construire à partir des sources et de voir si cela le résout.
Jim D
2

Malheureusement, j'ai quelques années de retard avec ma réponse, mais j'ai pensé que cela pourrait aider les futurs chercheurs. Ma version Nginx installée est 1.2.4, et j'ai créé l'extrait de configuration suivant,

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
la source
1
Bon usage de internal.
Clint Pachl