Что это такое? #
Прям такого режима в Nginx нет, я просто хочу так называть возможность вручную включить выдачу определенной страницы вместо всей остальной выдачи.
Сейчас мы умеем раздавать определенную html-страничку вместо стандартной страницы ошибки.
Например вместо дефолтной 504 ошибки мы можем отдавать красивую страницу с логотипом компании и вежливой понятной фразой вроде “Сейчас сервис недоступен, мы уже знаем о проблеме, попробуйте через минутку”.
error_page 500 501 503 502 504 /static/errors/5xx.html
А что если мы знаем, что сегодня с 20 вечера будут проводиться работы, которые повлекут даунтайм сервиса. Включим maintenance-режим с информацией о проводимых работах, сроке завершения.
Вторая ситуация: сервис жестко упал, инженеры решают инцедент, а клиенты в это время видят то 500-ки, то 503, то 504-ки, то таймауты. Включим maintenance-режим и всем будет спокойнее.
Неудачная попытка #
Первое что нашлось в интернете на эту тему: через if проверяйте наличие файла на сервере (например /etc/nginx/maintenance.flag), если файл есть - отдаем страницу, если нет - идем по стандартному nginx-конфигу. Что-то типа такого:
server {
....
error_page 503 /maintenance.html;
location = /maintenance.html {
root /etc/nginx/maintenance/;
internal;
}
location / {
if (-f /etc/nginx/maintenance.flag) {
return 503;
}
proxy_pass http://127.0.0.1:3000;
}
}
Это вполне рабочий вариант, но здесь наличие файла проверяется на КАЖДЫЙ запрос. Это может быть ресурсозатратным. На dev-стенде всё прошло хорошо, а на проде начало вызывать тормоза.
Почему return 503? #
Почему нужно возвращать клиенту 503 код ответа, несмотря на то, что мы отдаем живую работающую html-страницу?
503 код обычно означает, что сервис временно недоступен, там проводятся работы или он перегружен. Подробнее.
503 код ответа не индексируется поисковиками. Представь, если робот гугла в момент даунтайма спарсит страницу твоего проекта и запишет у себя “Under maintenance”.
Так же клиентским браузерам надо запрещать кэшировать такие страницы, чтобы после завершения даунтайма пользователь не ходил на maintenance-страничку из кэша.
Как можно сделать через include конфигурации? #
Общая логика такая:
- у нас есть файл
maintenance_on.confв котором одна строка:return 503; - по необходимости исклюдим этот файл в нужные locations череш
include maintenance_on.conf - мягко рестартим Nginx (через reload)
Теперь подробности реализации:
- Создаем директорию, чтобы не было мусора:
mkdir /etc/nginx/maintenance - В нее кладем нашу
maintenance.htmlстраничку. Навайбкодьте… - Создаем конфиг-файл
maintenance_on.conf:
return 503;
- Создаем пустой конфиг-файл
maintenance_off.conf - Создаем симлинк
maintenance_current.conf
ln -sfn /etc/nginx/maintenance/maintenance_off.conf /etc/nginx/maintenance/maintenance_current.conf
Нужно добавить немного строк в nginx-конфиг в блок server:
server {
...
error_page 503 /maintenance.html;
location = /maintenance.html {
internal;
root /etc/nginx/maintenance/maintenance.html;
add_header Cache-Control "no-store" always;
add_header Retry-After "3600" always;
}
location / {
include /etc/nginx/maintenance/maintenance_current.conf;
...
}
}
Что здесь происходит:
- Мы говорим, чтобы Nginx редиректил на
/maintenance.htmlпри 503 ошибке - Настраиваем локейшен
/maintenance.html, который отвечает за раздачу нашей сервисной странички.internalнужен, чтобы клиент не мог вообще никак запросить/maintenance_on.confили любой другой файл. - Добавляем заголовки, чтобы клиентский браузер не кэшировал страничку, а также Retry-After.
- В основной location (или в любой другой) добавляем
includeнашего симлинка.
Таким образом, чтобы включить maintenance-режим нам нужно только поменять симлинк и мягко перезапустить Nginx:
ln -sfn /etc/nginx/maintenance/maintenance_on.conf /etc/nginx/maintenance/maintenance_current.conf
nginx -t && systemctl reload nginx
Для выключения создаем линк на _off-файл и опять перезапускаем Nginx.
Как автоматизировать - сами придумайте.