Введение:

При разработке сложной системы часто приходится сталкиваться с необходимостью использования nginx в качестве reverse proxy. Один из частых сценариев использования это роутинг, список правил, регулирующих путь запроса во внутренние системы или путь между внутренними подсистемами.

Зачастую быстро развивающиеся сервисы обрастают правилами, назначение которых не очевидно или имеет недокументированные особенности. Крупные системы по своей природе склонны иметь разветвленную логику, в том числе утекающую в правила nginx. Иногда это результат осознанного наращивания техдолга за счет "быстрых решений", иногда вынужденный ход в условиях спешки. Много объективных и не очень причин почему так случилось, но в какой то момент это все приходится приводить в порядок.

Проверенный способ рефакторинга систем с недокументированным поведением:
зафиксировать и вылечить упростить. Фиксировать будем тестами.

Как же проверить корректность вашей конфигурации Nginx'а. Какие есть для этого варианты, их плюсы, минусы, практическая применимость и как эти проверки встроить в CI пайплайн ? Постараюсь ответить на эти вопросы. Будет полезно, погнали.

Совсем кратко о себе: разрабатываю высоконагруженные сервисы, веду канал о разработке в стартапах, где делюсь своим опытом. Буду рад видеть каждого! Заходите!

Способы тестирования конфигурации Nginx:

1) Ручное тестирование
Безусловно сложно не сказать про ручной вариант. Правки конфигурации, запуск, несколько cUrl и так по кругу насколько хватит терпения и трудолюбия. Иногда вполне практичный выбор, но разовый, увлекаться не стоит.

Полезных опции:

  • команда nginx -t - проверяет синтаксис конфигурационных файлов Nginx, не запуская и не перезапуская сам сервер.

  • директива rewrite_log on; - включает подробное логирование работы rewrite-правил в Nginx.

2) Проект "nginx-location-match-finder" на python
Утилита определяет, какой именно директивой location будет обрабатываться заданный URI. Скорее его можно назвать вспомогательной утилитой для дебага конфигурации, нежели полноценным способом тестирования.
Из явных минусов отсутствие поддержки свежих версий nginx, последняя указанная работоспособная это nginx 1.18.0.

3) Test::Nginx
Это Perl-библиотека для тестирования конфигов nginx и поведения location, rewrite, proxy_pass и т.д

Она позволяет:

  • в тесте описать мини-конфиг nginx;

  • поднять nginx на заданном порту;

  • отправить HTTP-запросы;

  • проверить статус/заголовки/тело ответа/логи.

Общая структура выглядит следующим образом:

use Test::Nginx::Socket -Base;

plan tests => 1;

run_tests();

__DATA__

=== TEST <Название теста>
--- http_config
    Содержимое попадает в секцию http { ... } в тестовом nginx.conf.

--- config
    Содержимое попадает внутрь server { ... } тестового nginx.
    То есть здесь — тестируемый location, rewrite, proxy_pass и т.п.
    Это именно тот участок конфига, который мы проверяем.

--- request
    HTTP-запрос, который Test::Nginx отправит к запущенному nginx.
--- more_headers
    Дополнительные заголовки HTTP-запроса.
--- error_code: 
    Ожидаемый HTTP-код ответа.
--- response_body_like
    Регулярное выражение, которое должно совпасть с телом ответа.

Пример теста на Test::Nginx можно посмотреть тут или тут

Минусы:
а) Test::Nginx для запуска требует установленного в системе perl и nginx
б) Test::Nginx имеет свой dsl, но все таки придется освоить основы perl, +1 к зоопарку технологий в проекте.
в) при запуске таких тестов локально и в CI нужно будет либо иметь в окружении perl и nginx либо запускать их в docker(с perl и nginx) например как тут. Во втором варианте придется дорабатывать ci скрипты и\или Dockerfile, для корректного возврата результата и списка упавших тестов в ci джобу.

Плюсы:
а) Готовый dsl для тестирования nginx
б) Test::Nginx это нативный тестовый фреймворк для nginx, что несет много плюсов само по себе.

4) Nginx_в _Docker + эхо_сервер + TestContainers + тесты на любом ЯП

Для данного способа потребуется несколько шагов:
4.1) Упаковать nginx вместе с вашей конфигурацией в docker. Во многих сервисах такой способ поставки уже используется, поэтому данный шаг может быть уже фактически выполнен, как вот тут.
Для примера он может содержать вот такое правило:

set $myserver ${MY_SERVER};

location /api/v1/old-query {
  rewrite ^/api/v1/old-query/(.*)$ /api/v2/$1 break;
  proxy_set_header Host $host;
  proxy_set_header X-Orig-Request-URI $request_uri;
  proxy_set_header X-Uri $uri;
  proxy_pass $myserver;
}

4.2) Установить или написать на любом удобном ЯП простой эхо сервис.
Ниже приведен код эхо сервиса на python:

from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class H(BaseHTTPRequestHandler):
    def do_GET(self):
        body = {
            "path": self.path,
            "headers": {k: v for k, v in self.headers.items()}
        }
        self.send_response(200)
        self.send_header("Content-Type","application/json")
        self.end_headers()
        self.wfile.write(json.dumps(body).encode())

HTTPServer(("0.0.0.0", 9000), H).serve_forever()

4.3) Написать сами тесты.
Пример самого упрощенного теста на python:

import pytest, requests

CASES = [
    ("/api/v1/old-query/items?id=42", "/api/v2/items?id=42"),
    ("/api/v1/old-query/users/alice", "/api/v2/users/alice"),
]

@pytest.mark.parametrize("inp,expected", CASES)
def test_rewrite(inp, expected):
    r = requests.get("http://localhost:8080"+inp, timeout=2)
    assert r.status_code == 200
    assert r.text.strip() == expected

4.4) Запуск
В самом упрощенном варианте для демонстрации концепции можно запускать эхо сервис и nginx в docker-compose и ваши тесты непосредственно из ide или консоли.

Для продвинутого варианта отлично подойдет библиотека TestContainers, в тесте можно поднять все необходимые контейнеры, в нашем случае это эхо сервис и nginx, в этом же тесте провести необходимые проверки и выключить поднятые ранее контейнеры по завершению. Этот способ отлично подходит для CI.

Плюсы:
а) полноценный тест на боевой сборке вашего nginx, без дополнительных правок исключительно под тесты. Это +1 к доверию такому тестированию.
б) тесты легко встраиваются в CI
в) не добавляет дополнительных технологий в проект

Минусы:
а) придется самостоятельно создавать свое подобие фреймворка для тестирования nginx на вашем ЯП

5) Проверка информационной безопасности с помощью Gixy
Gixy — инструмент для статического анализа конфигураций Nginx, предназначенный для поиска ошибок и уязвимостей. Он проверяет проблемы с alias, try_files, небезопасные регулярки, SSRF-риски, неправильные заголовки и другие конфигурационные ловушки. Используется для повышения безопасности и корректности nginx-конфигов.
Оригинальный проект от яндекса судя по всему достаточно давно не развивается тк последний релиз был 2 года назад. Зато есть форк со свежим релизом от октября 2025 года.
Тема ИБ сейчас как никогда актуальна, поэтому данный инструмент безусловно слоило включить в список.

К примеру для такого nginx-конфига:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log notice;
pid        /tmp/nginx.pid;

events { worker_connections 1024; }

set $myserver ${MY_SERVER};

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile      on;

    upstream echo_upstream { server python_echo:9000; }

    server {
        listen 8080;
        server_name _;

        # Удобная диагностика переписываний
        rewrite_log on;

        location /api/v1/old-query {
          rewrite ^/api/v1/old-query/(.*)$ /api/v2/$1 break;
          proxy_set_header Host $host;
          proxy_set_header X-Orig-Request-URI $request_uri;
          proxy_set_header X-Uri $uri;
          proxy_pass $myserver;
        }

        # Явный fallback, чтобы видеть, что локация не сработала
        location / { return 404 "no test location matched\n"; }
    }
}

Запуск утилиты Gixy:

gixy .\nginx.conf

Выдает следующие уязвимости:

==================== Results ===================

>> Problem: [http_splitting] Possible HTTP-Splitting vulnerability.
Description: Using variables that can contain "\n" or "\r" may lead to http injection.
Additional info: https://github.com/dvershinin/gixy/blob/master/docs/en/plugins/httpsplitting.md
Reason: At least variable "$uri" can contain "\n"
Pseudo config:

server {
        server_name _;

        location /api/v1/old-query {
                proxy_set_header X-Uri $uri;
        }
}

------------------------------------------------

>> Problem: [version_disclosure] Do not enable server_tokens on or server_tokens build
Description: Using server_tokens on; or server_tokens build;  allows an attacker to learn the version of NGINX you are running, which can be used to exploit known vulnerabilities.
Additional info: https://gixy.getpagespeed.com/en/plugins/version_disclosure/
Reason: Missing server_tokens directive - defaults to 'on' which promotes information disclosure
Pseudo config:

server {
        server_name _;
}

------------------------------------------------

>> Problem: [worker_rlimit_nofile_vs_connections] The worker_rlimit_nofile should be at least twice than worker_connections.
Description: The worker_rlimit_nofile should be at least twice than worker_connections.
Additional info: https://gixy.getpagespeed.com/en/plugins/worker_rlimit_nofile_vs_connections/
Reason: Missing worker_rlimit_nofile with at least twice the value of worker_connections
Pseudo config:

events  {
        worker_connections 1024;
}

==================== Summary ===================
Total issues:
    Unspecified: 0
    Low: 0
    Medium: 1
    High: 2

Заключение:
Было интересно систематизировать способы проверки корректности и безопасности конфигурации nginx:
1) п.1(ручное тестирование) и п.2 (nginx-location-match-finder) безусловно могут быть полезны при диагностике проблем.
2) Для написания тестов можно использовать п.3(Test::Nginx) и\или п.4 (Nginx_в _Docker + эхо_сервер + TestContainers + тесты на любом ЯП).
* Если вас не смущает perl в вашем стеке проекта, или вдруг даже это и есть ваш ЯП, то выбор однозначное в пользу Test::Nginx благодаря богатому dsl и "нативности" для nginx.
* Если же perl для вас не подходит по каким то причинам, то вариант с эхо сервисом. Он может быть реализован на любом языке и максимально приближен к продовой конфигурации.
3) Для проверки информационной безопасности поможет п.5(Gixy)

Всем корректности, безопасности и добра !

Комментарии (2)


  1. maxorik
    23.11.2025 21:22

    Спасибо, познавательная статья


    1. rurikovich Автор
      23.11.2025 21:22

      Рад что понравилось :)