Тестирование конфигурации Nginx: обеспечение плавных развертываний с помощью ключевых команд

Используйте nginx -t, nginx -T и безопасные привычки перезагрузки, чтобы выявить ошибки конфигурации Nginx до того, как они повлияют на трафик.

Тестирование конфигурации Nginx: обеспечение плавных развертываний с помощью ключевых команд

Тестирование конфигурации Nginx — это одна из тех привычек, которые кажутся слишком незначительными, пока не спасут вас от сломанной перезагрузки. Пропущенная точка с запятой, неправильный путь include или директива из модуля, которого у вас нет, могут помешать Nginx принять новую конфигурацию. На рабочем обратном прокси это не мелкая ошибка.

Основная команда проста:

sudo nginx -t

Запускайте её перед каждой перезагрузкой. Запускайте после редактирования server block. Запускайте в CI, если ваша команда хранит конфигурацию Nginx в Git. Команда анализирует конфигурацию и сообщает, корректен ли синтаксис. Она не доказывает, что ваша логика маршрутизации верна, ваш TLS-сертификат действителен для каждого имени хоста или ваше вышестоящее приложение здорово. Она выявляет класс ошибок, которые Nginx может обнаружить до применения конфигурации.

Что проверяет nginx -t

nginx -t указывает Nginx протестировать конфигурацию. Он читает основной конфигурационный файл, обрабатывает директивы include, анализирует директивы и блоки, а также проверяет многие проблемы с файлами/путями. Успешный запуск обычно выглядит так:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Неудачный запуск указывает на файл и номер строки:

nginx: [emerg] unexpected "}" in /etc/nginx/conf.d/api.conf:18
nginx: configuration file /etc/nginx/nginx.conf test failed

Номер строки — это место, где парсер заметил проблему, а не всегда то, где вы допустили ошибку. Если Nginx сообщает о неожиданной } на строке 18, проверьте строки выше на наличие пропущенной точки с запятой или незакрытого блока.

Используйте sudo, когда конфигурационные файлы, файлы сертификатов или включенные сниппеты доступны для чтения только root:

sudo nginx -t

Без правильных разрешений ваш тест может завершиться неудачей, даже если синтаксис в порядке.

Используйте nginx -T, когда include-файлы усложняют просмотр конфигурации

Многие настройки Nginx разделяют конфигурацию между /etc/nginx/nginx.conf, conf.d/*.conf, sites-enabled/* и общими сниппетами. Это хорошо для поддерживаемости, но может затруднить отладку.

nginx -T тестирует конфигурацию и выводит полную разобранную конфигурацию в stdout:

sudo nginx -T

Это полезно, когда вам нужно ответить на такие вопросы:

  • Какой файл на самом деле определяет этот server block?
  • Подхватил ли мой шаблон include резервный файл?
  • Устанавливается ли эта директива на уровне http, server или location?
  • Какой дублирующийся блок server_name побеждает?

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

Тестирование нестандартного конфигурационного файла с помощью -c

Если вы создаете конфигурацию в промежуточном пути, используйте -c:

sudo nginx -t -c /home/deploy/nginx-staging/nginx.conf

Это указывает Nginx, какой основной конфигурационный файл тестировать. Относительные пути внутри этой конфигурации могут вести себя по-разному в зависимости от настроек префикса, поэтому по возможности держите промежуточные тесты близко к рабочей структуре.

Вы также можете просмотреть пути времени компиляции и модули с помощью:

nginx -V

Вывод идет в stderr во многих системах, что удивляет людей при перенаправлении вывода. Он показывает версию Nginx и параметры сборки, включая поддержку модулей и пути по умолчанию. Это важно, когда конфигурация использует директивы из модулей, таких как http_v2, realip, stub_status или потоковое проксирование.

Перезагружайте, а не перезапускайте без необходимости

Как только тест пройден, перезагрузите Nginx:

sudo systemctl reload nginx

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

Перезапуск останавливает и запускает службу:

sudo systemctl restart nginx

Используйте перезапуск, когда он действительно нужен, например, после изменений пакетов или проблемы с состоянием службы. Для обычных правок конфигурации перезагрузка менее разрушительна.

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

Родная команда сигнала Nginx также распространена:

sudo nginx -s reload

На серверах, управляемых systemd, я обычно предпочитаю systemctl reload nginx, потому что это сохраняет состояние службы и журналы в одном слое управления.

Безопасный рабочий процесс редактирования

Для обычного изменения server block используйте такой ритм:

sudo cp /etc/nginx/conf.d/api.conf /etc/nginx/conf.d/api.conf.bak.$(date +%Y%m%d%H%M%S)
sudoedit /etc/nginx/conf.d/api.conf
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status nginx --no-pager

Если ваша конфигурация находится в Git, зафиксируйте изменение вместо того, чтобы хранить случайные резервные файлы вечно. Команда резервного копирования выше полезна для небольших неуправляемых серверов, но не заменяет систему контроля версий.

После перезагрузки протестируйте фактический маршрут:

curl -I https://example.com/api/health
curl -I -H 'Host: example.com' http://127.0.0.1/

nginx -t может сказать вам, что конфигурация разбирается. curl говорит вам, ведет ли себя сайт так, как вы задумали.

Частые сообщения об ошибках и что они обычно означают

Пропущенная точка с запятой часто выглядит так:

nginx: [emerg] invalid number of arguments in "proxy_set_header" directive in /etc/nginx/conf.d/app.conf:22

Проверьте директиву в этой строке и строке перед ней. Директивы Nginx обычно заканчиваются на ;, а блоки заканчиваются на { ... }.

Неправильный путь include выглядит так:

nginx: [emerg] open() "/etc/nginx/snippets/security-headers.conf" failed (2: No such file or directory)

Либо путь к файлу неверен, сниппет не был развернут, либо шаблон include зависит от окружения.

Проблема с разрешениями может выглядеть так:

nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": BIO_new_file() failed

Файл может отсутствовать, символическая ссылка может быть сломана, или пользователь, запускающий тест, не может его прочитать. Скрипты обновления и развертывания сертификатов — частые места, где это происходит.

Неизвестная директива означает одно из трех: опечатка, неправильный контекст или отсутствующий модуль.

nginx: [emerg] unknown directive "proxy_cache_purge"

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

Дублирующееся или конфликтующее имя сервера может появиться как предупреждение, а не как жесткая ошибка:

nginx: [warn] conflicting server name "example.com" on 0.0.0.0:80, ignored

Не игнорируйте предупреждения только потому, что последняя строка говорит, что тест прошел успешно. Предупреждение может означать, что Nginx не будет использовать тот server block, который вы думаете.

Тестирование в CI

Если конфигурация Nginx хранится в репозитории, тестируйте ее перед развертыванием. Простая проверка на основе контейнера может смонтировать конфигурацию в образ Nginx и запустить:

nginx -t -c /etc/nginx/nginx.conf

Сложная часть — сопоставление рабочих путей. Если ваша конфигурация ссылается на /etc/letsencrypt, локальным тестам нужны файлы-заполнители или конфигурация, специфичная для теста. Если она ссылается на имена вышестоящих хостов, синтаксический тест не требует, чтобы вышестоящий сервер был жив, но включенные файлы и файлы сертификатов должны существовать.

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

Что тестирование конфигурации не может выявить

nginx -t не скажет вам, что ваш новый блок location затеняется другим блоком с регулярным выражением. Он не узнает, что ваше вышестоящее приложение возвращает 500. Он не докажет, что цепочка перенаправлений разумна или что правило кэширования безопасно.

Для этого добавьте проверки поведения:

curl -I https://example.com/
curl -I https://example.com/old-path
curl -sS https://example.com/api/health

Для изменений TLS проверьте сертификат с точки зрения клиента:

openssl s_client -connect example.com:443 -servername example.com </dev/null

Для изменений обратного прокси следите за журналами во время и после перезагрузки:

sudo tail -f /var/log/nginx/error.log /var/log/nginx/access.log

Тестирование конфигурации Nginx — это не полная стратегия развертывания, но это шлюз, который должна включать каждая стратегия. Используйте nginx -t для синтаксиса, nginx -T для отладки отрисованной конфигурации, nginx -V для деталей сборки и systemctl reload nginx для обычных изменений. Затем проверяйте поведение с помощью реальных запросов.