В настоящий момент я настраиваю nginx для обработки некоторых страниц ошибок и других мультимедийных файлов "по умолчанию" (таких как favicon.ico и robots.txt), и у меня возникла небольшая проблема, заставляющая все работать так, как я хочу, для определенных страниц ошибок. .
По сути, то, что я пытаюсь сделать, - это обслуживать определенные файлы для сервера в корневом каталоге этого сервера, например /var/www/someserver.com/robots.txt. Если этот файл не существует, я хочу, чтобы nginx перешел к «умолчанию», то есть /var/www/default/robots.txt. Это основная суть того, как я это (успешно) настроил:
server {
...
root /var/www/someserver.com;
location ~* ^/(robots\.txt)$ {
error_page 404 = @default;
}
location @default {
root /var/www/default;
}
}
Это прекрасно работает.
Я пытаюсь сделать то же самое для страниц с ошибками, но не могу этого сделать:
server {
...
root /var/www/someserver.com;
error_page 404 /404.html;
location ~* ^/(404\.html)$ {
error_page 404 = @default;
}
location @default {
root /var/www/default;
}
}
Обратите внимание, что это «работает» в том смысле, что если вы посетите someserver.com/404.html, он сначала попытается загрузить /var/www/someserver.com/404.html, а затем вернется к / var / www / default. /404.html, если он не найден. Однако, если вы посетите someserver.com/blahblah, он покажет страницу 404, только если она установлена в /var/www/someserver.com/. Если этот файл не существует, он не возвращается в каталог по умолчанию.
Во всяком случае, вы, вероятно, можете то, что я пытался выполнить (поэтому я включил первый рабочий пример).
Любые идеи?
Редактировать:
Основываясь на ответе Мартина Ф, я собрал вот что:
# 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;
}
}
Это прекрасно работает. Фактический блок error_pages и местоположений выше находится в файле server_defaults.conf, который включается в каждый виртуальный хост, поэтому я не жестко закодировал путь к каждому местоположению и использовал относительный путь для значений по умолчанию.
Изменить 2:
У этого подхода есть проблема. Если вы отправляете POST на URL-адрес, который возвращает ошибку, метод запроса POST отправляется с попытками try_files. Это (для меня) приводит к ошибке 405 Not Allowed, потому что nginx, по сути, пытается выполнить POST, например, /default/500.html вместо того, чтобы просто получить эту страницу.
Изменить 3:
Я опубликовал решение, которое намного ближе к моей первоначальной идее.
В итоге я выбрал что-то более близкое к моей первоначальной идее. Ключ, которого мне не хватало, оказался директивой recursive_error_pages
. Все, что мне действительно нужно было сделать, это включить это, и моя первоначальная идея сработала. Вот как теперь выглядит соответствующая часть моей конфигурации:
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;
}
}
Я включил сюда другие типы ошибок, которые не были частью моего первоначального вопроса, потому что это то, что в конечном итоге вызвало у меня трудности с подходом Мартина Ф, который в остальном был превосходным. В log_not_found
Директива просто гарантирует, что я не получу 404 в моем журнале, если страница с ошибкой не найдена в исходном корне.
try_files это путь сюда. Следующая конфигурация должна работать, но я не проверял ее на наличие синтаксических ошибок.
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.
}
}
К сожалению, я опоздал с ответом на пару лет, но подумал, что это может помочь будущим поисковикам. Моя установленная версия Nginx - 1.2.4, и я создал следующий фрагмент конфигурации:
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;
}
}
Я обнаружил, что крайне важно включить "proxy_intercept_errors on;" в любом блоке местоположения, где также была включена error_page.
Без этой настройки блок местоположения будет перехватывать коды ошибок, возвращаемые восходящим потоком.
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors