Настройте nginx для возврата 503, если файл существует.

Вопрос или проблема

Я пытаюсь настроить 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;
    }
}

Применение

  1. Проверка переменной состояния обслуживания: Переменная $maintenance изначально установлена в состояние off. При наличии файла upgrading.html в корне документа переменная изменяется на on, что сигнализирует о текущем режиме обслуживания.

  2. Произведение необходимых действий при режиме обслуживания: Если переменная $maintenance настроена на on, возвращается код состояния 503, что сигнализирует пользователям о временной недоступности сайта.

  3. Переопределение страницы ошибки: Используя директиву error_page, мы переопределяем стандартную страницу ошибки сервиса, указывая nginx использовать вместо неё специальную страницу 503.html, расположенную, скажем, в /var/www/html.

  4. Интеграция в текущие сервера: Эта настройка легко интегрируется в существующую конфигурацию серверов nginx, позволяя администраторам сети быстро переключать сайт в режим обслуживания простым созданием или удалением определенного файла.

Таким образом, предложенное решение учитывает все аспекты управления состоянием сайта в nginx, включая настройки обслуживания и реагирование на изменение состояния. Это позволяет администраторам гибко управлять доступностью ресурса, обеспечивая пользователей соответствующей информацией и поддерживая непрерывность работы систем.

Этот подход особенно полезен в сценариях, когда необходимо регулярно проводить профилактические работы или обновления, минимально вмешиваясь в основную конфигурацию nginx и обеспечивая поддержку скалируемых и повторяемых процессов обслуживания. На практике все изменения легко реализовать с помощью простейших файловых операций, что значительно упрощает внедрение и управление решениями на основе nginx в продакшн-средах.

Оцените материал
Добавить комментарий

Капча загружается...