Вопрос или проблема
Я пытаюсь настроить nginx так, чтобы он возвращал 503, если существует определенный файл (возможно, что-то вроде “upgrading”). Я пытаюсь использовать директиву try_files
, но когда она находит файл /upgrading.html
, она обслуживает его, а не следует директиве. Почему так происходит?
location / {
try_files /upgrading.html @keepgoing;
}
location = /upgrading.html {
return 503;
}
location @keepgoing {
#здесь выполняются обычные действия...
}
В журнале, когда включено отладочное логирование, я вижу следующее:
3388 2010/07/01 19:44:21 [debug] 76327#0: *8 test location: "https://serverfault.com/"
3389 2010/07/01 19:44:21 [debug] 76327#0: *8 using configuration "https://serverfault.com/"
3390 2010/07/01 19:44:21 [debug] 76327#0: *8 http cl:-1 max:52428800
3391 2010/07/01 19:44:21 [debug] 76327#0: *8 generic phase: 2
3392 2010/07/01 19:44:21 [debug] 76327#0: *8 post rewrite phase: 3
3393 2010/07/01 19:44:21 [debug] 76327#0: *8 generic phase: 4
3394 2010/07/01 19:44:21 [debug] 76327#0: *8 generic phase: 5
3395 2010/07/01 19:44:21 [debug] 76327#0: *8 access phase: 6
3396 2010/07/01 19:44:21 [debug] 76327#0: *8 access phase: 7
3397 2010/07/01 19:44:21 [debug] 76327#0: *8 post access phase: 8
3398 2010/07/01 19:44:21 [debug] 76327#0: *8 try files phase: 9
3399 2010/07/01 19:44:21 [debug] 76327#0: *8 try to use file: "/upgrading.html" "/usr/local/nginx/html/upgrading.html"
3400 2010/07/01 19:44:21 [debug] 76327#0: *8 try file uri: "/upgrading.html"
3401 2010/07/01 19:44:21 [debug] 76327#0: *8 content phase: 10
3402 2010/07/01 19:44:21 [debug] 76327#0: *8 content phase: 11
3403 2010/07/01 19:44:21 [debug] 76327#0: *8 content phase: 12
3404 2010/07/01 19:44:21 [debug] 76327#0: *8 http filename: "/usr/local/nginx/html/upgrading.html"
Кажется, он не может найти директиву, но она там есть, так что я не уверен, что делаю неправильно.
Также, в более общем плане, является ли это приемлемым подходом для решения этой проблемы? Другие способы сделать это?
С этой страницы: https://calomel.org/nginx.html
## Техническое обслуживание системы (услуга недоступна)
if (-f $document_root/system_maintenance.html ) {
error_page 503 /system_maintenance.html;
return 503;
}
Важной частью является ‘-f’, я полагаю – она проверяет, существует ли файл.
Я предлагаю не использовать try_files
здесь, а вместо этого искать файл и возвращать код ошибки, если он существует. Затем можно отдельно обрабатывать код ошибки. Посмотрите пример ниже.
# Если файл maintenance.html существует, вернуть статус 503
if (-f $document_root/maintenance.html) {
return 503;
}
# Затем при статусе 503 использовать локацию @maintenance
error_page 503 @maintenance;
# В локации @maintenance отображать maintenance.html
location @maintenance {
rewrite ^(.*)$ /maintenance.html break;
}
Если вы планируете делать это регулярно и хотите использовать один и тот же maintenance.html
каждый раз, вы также можете изменить первую часть, чтобы она выглядела как-то так. Тогда maintenance.html
всегда будет на месте, и просто добавьте пустой файл .maintenance
, когда это необходимо.
if (-f $document_root/.maintenance) {
return 503;
}
Вот что сработало для меня к версии nginx 1.18.0 (Ubuntu)
Сначала настройте дополнительный включаемый белый список с IP-адресами администраторов:
nano /etc/nginx/includes/whitelist.conf
# Отключить режим обслуживания для IP-адресов из белого списка
if ($remote_addr = "111.11.11.111") {
set $maintenance off;
}
Затем добавьте проверку файла на уровне сервера:
server {
# Проверка флага обслуживания для каждого сервиса
set $maintenance off;
if (-f /srv/static/live/public/maintenance/service.flag) {
set $maintenance on;
}
# Включить проверку белого списка
include /etc/nginx/includes/whitelist.conf;
...
}
На уровне блоков location добавьте проверку на включение $maintenance:
location / {
....
if ($maintenance = on) {
return 503;
}
# перенаправление на страницу ошибки
error_page 503 @maintenance;
# в противном случае обслуживать
root /srv/static/live/public/site;
}
Добавьте локацию 503:
location @maintenance {
root /srv/static/live/public/;
rewrite ^(.*)$ /503.html break;
}
.. и 503.html по адресу /srv/static/live/public/503.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!-- блокировка любого внедренного скрипта -->
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description"
content="Ваше имя/организация">
<meta name="theme-color" content="#fdb300">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="Ваше имя">
<meta name="apple-mobile-web-app-title" content="Mobile rules">
<meta name="apple-mobile-web-app-status-bar-style" content="red">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<title>503</title>
<style>
*{
transition: all 0.6s;
}
html {
height: 100%;
}
body{
font-family: 'Lato', sans-serif;
color: #888;
margin: 0;
}
#main{
display: table;
width: 100%;
height: 100vh;
text-align: center;
}
.fof{
display: table-cell;
vertical-align: middle;
}
.fof h1{
font-size: 50px;
display: inline-block;
padding-right: 12px;
animation: type .5s alternate infinite;
}
@keyframes type{
from{box-shadow: inset -3px 0px 0px #888;}
to{box-shadow: inset -3px 0px 0px transparent;}
}
</style>
</head>
<body>
<div id="main">
<div class="fof">
<h1>503: Service down for maintenance</h1>
<h2>Updates can be found at ...</h2>
</div>
</div>
</body>
</html>
Ответ или решение
Для конфигурации nginx, чтобы возвращать код ошибки 503, если существует определенный файл, подход, который описан вами, может быть улучшен использованием директивы if
для проверки наличия файла, а не try_files
. Давайте подробно разберем это решение, приводя теоретическое объяснение, практический пример и применение на практике в контексте реальной конфигурации.
Теория
Концепция здесь заключается в использовании директивы if
в конфигурации nginx. Директива if
позволяет проверять условие: если условие истинно, выполняется действие, которое вы задаете. В случае, когда существует файл upgrading.html
, мы хотим вернуть код 503, который обозначает "Service Unavailable". Дополнительным компонентом может быть использование директивы error_page
, чтобы переопределить местоположение страницы, отображаемой пользователю при ошибке 503.
Почему try_files
не подходит? Ваша первоначальная идея использования try_files
для возврата 503 при существовании файла не сработала из-за механики этой директивы. try_files
пытается найти файл и, если он существует, возвращает его. Это полезно, когда необходимо с минимальными накладными расходами проверить наличие файла и вернуть его, но в нашем случае задача стоит в проверке и возврате кода, а сам файл нам отдавать не нужно.
Пример
Посмотрим, как может выглядеть простая конфигурация nginx для решения поставленной задачи:
server {
listen 80;
server_name example.com;
# Переменная для отслеживания режима обслуживания
set $maintenance off;
# Если файл 'upgrading.html' существует, устанавливаем флаг обслуживания
if (-f $document_root/upgrading.html) {
set $maintenance on;
}
# Проверяем флаг обслуживания и возвращаем 503, если он включен
if ($maintenance = on) {
return 503;
}
# Настройка страницы ошибки для кода 503
error_page 503 @maintenance;
# Параметры для стандартных запросов
location / {
proxy_pass http://backend;
}
# Обработка страницы обслуживания
location @maintenance {
root /var/www/html;
rewrite ^(.*)$ /503.html break;
}
}
Применение
-
Проверка переменной состояния обслуживания: Переменная
$maintenance
изначально установлена в состояниеoff
. При наличии файлаupgrading.html
в корне документа переменная изменяется наon
, что сигнализирует о текущем режиме обслуживания. -
Произведение необходимых действий при режиме обслуживания: Если переменная
$maintenance
настроена наon
, возвращается код состояния 503, что сигнализирует пользователям о временной недоступности сайта. -
Переопределение страницы ошибки: Используя директиву
error_page
, мы переопределяем стандартную страницу ошибки сервиса, указывая nginx использовать вместо неё специальную страницу503.html
, расположенную, скажем, в/var/www/html
. -
Интеграция в текущие сервера: Эта настройка легко интегрируется в существующую конфигурацию серверов nginx, позволяя администраторам сети быстро переключать сайт в режим обслуживания простым созданием или удалением определенного файла.
Таким образом, предложенное решение учитывает все аспекты управления состоянием сайта в nginx, включая настройки обслуживания и реагирование на изменение состояния. Это позволяет администраторам гибко управлять доступностью ресурса, обеспечивая пользователей соответствующей информацией и поддерживая непрерывность работы систем.
Этот подход особенно полезен в сценариях, когда необходимо регулярно проводить профилактические работы или обновления, минимально вмешиваясь в основную конфигурацию nginx и обеспечивая поддержку скалируемых и повторяемых процессов обслуживания. На практике все изменения легко реализовать с помощью простейших файловых операций, что значительно упрощает внедрение и управление решениями на основе nginx в продакшн-средах.