nginx: Как обработать 404 напрямую в обратном прокси только для некоторых имен файлов (*.txt)?

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

У меня сложная настройка nginx, где фронтальный nginx на портах 80 и 443 обрабатывает весь внешний доступ, включая TLS.

Для файлов в /texts фронтальный nginx должен проксировать запросы ко второму бэкенд-nginx, который модифицирует существующие текстовые файлы на лету в сложном процессе, потребляя при этом ЦП и другие ресурсы.

Для тех файлов *.txt, которые не существуют (404), я не хочу беспокоить бэкенд вовсе, а вместо этого предоставить клиенту файл по умолчанию /texts/default.txt напрямую. Однако в настоящее время несуществующие файлы все еще обрабатываются только в строке error_page 404 бэкенда. Существующие файлы обслуживаются без проблем, прокси работает.

Вот моя конфигурация:

frontend-nginx.conf:
http {
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  frontend.example.org;
        root         /srv/www;

        location /texts/ {

            location ~ \*.txt$ {
                root /srv/www/backend;

                ####### следующая строка абсолютно не имеет эффекта
                try_files $uri /texts/default.txt;
            }

            proxy_pass          http://localhost:90;
            proxy_redirect      http://localhost:90/ /;
            proxy_set_header    Host             $host;
            proxy_set_header    X-Real-IP        $remote_addr;
            proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header    X-Client-Verify  SUCCESS;
            proxy_set_header    Upgrade          $http_upgrade;
            proxy_set_header    Connection       "upgrade";
            proxy_http_version  1.1;

            proxy_redirect off;
        }
    }
    # https идет сюда, все так же, за исключением TLS
}
backend-nginx.conf:
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;

    server {
        listen       127.0.0.1:90;

        root /srv/www/backend;
        charset utf-8;

        expires -1;  # no-cache
        location ~ /..*\.txt$ {
            # более долгое время кэширования для текстовых файлов
            expires 10m;

            # это действительно работает, но только здесь, в бэкенде
            error_page  404 @404;
        }

        location @404 {
            return 302 $scheme://frontend.example.org/texts/default.txt
        }
    }
}

У меня есть это бесполезное выражение в конфигурационном файле фронтенда, которое кажется мне могло бы обрабатывать 404 редиректы к default.txt, но когда я выполняю

wget -v http://frontend.example.org/texts/notexist.txt

Я получаю редирект только внутри бэкенда (так что проксирование действительно происходит).

location /texts/ {
    proxy_set_header ...;
    proxy_pass ...;

    location ~ \.txt$ {
        root /path/to/root;
        try_files $uri /texts/default.txt;
        proxy_pass ...;
    }
}
location = /texts/default.txt {
    root /path/to/root;
}

Обратите внимание на правильное регулярное выражение для инструкции location. Инструкции proxy_set_header будут унаследованы, но инструкцию proxy_pass нужно повторить в вложенной location.

Инструкция try_files будет проверять существование файла и изменять URI, если его нет.

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

Путь к файлу строится путем конкатенации значения root с URI, так что файл /texts/default.txt находится по адресу /path/to/root/texts/default.txt.

Ответ или решение

Как обрабатывать 404 в Nginx обратном прокси для некоторых файлов (*.txt)

В данной статье мы рассмотрим, как настроить Nginx, чтобы обрабатывать ошибки 404 для текстовых файлов (*.txt) в конфигурации обратного прокси. Это позволит снизить нагрузку на ваш бэкенд, предоставляя вместо этого статический файл при возникновении ошибки 404.

Контекст проблемы

Ваша текущая конфигурация Nginx состоит из двух основных частей: frontend-nginx, который отвечает за внешний трафик (порты 80 и 443), и backend-nginx, который обрабатывает текстовые файлы. При обращении к несуществующим текстовым файлам ваш текущий процесс проксирования переправляет все запросы на бэкенд, который обрабатывает все 404 ошибки, что в данном случае неэффективно.

Шаги к решению

Для решения этой проблемы нам нужно изменить конфигурацию, чтобы Nginx на фронтенде имел возможность обрабатывать ошибки 404 самостоятельно для файлов с расширением .txt. Мы будем использовать директивы try_files в комбинации с правильной настройкой location.

Исходя из вашего текущего настроя, вот как можно оптимизировать конфигурацию.

Конфигурация Frontend-Nginx

server {
    listen       80 default_server;
    server_name  frontend.example.org;
    root         /srv/www;

    location /texts/ {
        # Настройка для обработки текстовых файлов
        location ~ \.txt$ {
            # Используем try_files для проверки существования файла
            try_files $uri /texts/default.txt;

            # Обратите внимание, что proxy_pass нужно будет указать снова
            proxy_pass http://localhost:90;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_http_version  1.1;
        }

        # Дефолтный прокси для остальных запросов в каталоге /texts
        proxy_pass http://localhost:90;
        proxy_redirect http://localhost:90/ /;
        # Код выше будет работать для всех других запросов к /texts/
    }

    location = /texts/default.txt {
        # Настройка для доступа к статическому файлу default.txt
        root /srv/www;
        # Обратите внимание, что путь будет /srv/www/texts/default.txt
    }
}

Конфигурация Backend-Nginx

Ваш бэкенд остаётся почти без изменений, но мы уберём обработку ошибок 404 для текстовых файлов, так как это будет теперь обрабатываться фронтендом:

server {
    listen       127.0.0.1:90;

    root /srv/www/backend;
    charset utf-8;

    expires -1;  # no-cache
    location ~ \.txt$ {
        # Настройки для кэширования текстов
        expires 10m;
        # Здесь не нужна дополнительная обработка ошибок 404
    }
}

Пояснения к изменениям

  1. try_files: мы используем директиву try_files в блоке location, чтобы проверить существование запрашиваемого файла. Если файл не найден, Nginx автоматически предложит файл /texts/default.txt.

  2. Повторное указание proxy_pass: важно, чтобы внутри вложенного блока location ~ \.txt$ была указана директива proxy_pass, которая отправляет запрос на бэкенд, если файл существует.

  3. Отдельное определение default.txt: добавлено отдельное определение для location = /texts/default.txt, чтобы Nginx мог обслуживать этот статический файл напрямую из файловой системы.

Заключение

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

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

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

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