Вопрос или проблема
У меня сложная настройка 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
}
}
Пояснения к изменениям
-
try_files: мы используем директиву
try_files
в блокеlocation
, чтобы проверить существование запрашиваемого файла. Если файл не найден, Nginx автоматически предложит файл/texts/default.txt
. -
Повторное указание proxy_pass: важно, чтобы внутри вложенного блока
location ~ \.txt$
была указана директиваproxy_pass
, которая отправляет запрос на бэкенд, если файл существует. -
Отдельное определение default.txt: добавлено отдельное определение для
location = /texts/default.txt
, чтобы Nginx мог обслуживать этот статический файл напрямую из файловой системы.
Заключение
С помощью вышеуказанных шагов, ваша конфигурация Nginx теперь будет эффективно обрабатывать 404 ошибки для файлов с расширением .txt
, избегая избыточной нагрузки на бэкенд. Это не только оптимизирует использование ресурсов, но и улучшает производительность вашего сайта.
Не забывайте проверять конфигурацию Nginx на наличие синтаксических ошибок с помощью команды nginx -t
перед перезагрузкой сервера. Оптимизация конфигурации всегда является важной частью управления веб-сервером, особенно когда речь идёт о повышении производительности и снижении нагрузки на системы.