Перейти к содержимому

Proxy pass что означает

  • автор:

Nginx proxy pass, настройка проксирования запросов в nginx

В Nginx proxy_pass является основной директивой нужной для проксирования (перенаправления в другие блоки конфигурации) запросов, дополнительный функционал реализуется за счет других правил, прописывающихся в файле виртуального хоста.

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

В качестве адреса для проксирования может задаваться доменное имя, ip адрес, комбинация ip адреса и порта.

Рассмотрим два случая:

  • проксирование на другой домен с сохранением запрашиваемого домена в адресной строке
  • проксирование с редиректом (со сменой запрашиваемого домена в адресной строке)

Они довольно специфические, самый базовый вариант использования можно увидеть в статье про запуск на сервере проекта на NodeJS

Настройка проксирования через Nginx proxy_pass

В примере рассматривается настройка проксирования запросов с subdomain.example.com на https://subdomain.example.ru/suf

На сервере, на котором настраивалось проксирование применяется Apache в качестве бэкенд сервера и Nginx в качестве фронтенд сервера. Проксирование реализовано на уровне фронтенда, до Apache запросы в первоначальном виде не доходят. Домен при существующих настройках будет оставаться тем же по которому пришел запрос (в этом отличие от редиректа).

server
server_name subdomain.example.com;
listen *:80;
proxy_read_timeout 200s;
access_log off;

include static.conf;

location /
root /var/www/sites/subdomain.example.com;
proxy_pass https://subdomain.example.ru/suf;

proxy_set_header X-Forwarded-Host subdomain.example.com:80;
proxy_set_header X-Forwarded-Server subdomain.example.com;
proxy_set_header X-Forwarded-For https://subdomain.example.ru/suf;

static.conf здесь — отдельный файл в котором заданы настройки кэширования, также они могут задаваться в любом другом конфиге.

За счет приведенных ниже директив реализуется реверсивное проксирование запросов, это аналог ProxyPassReverse в Apache:

proxy_set_header X-Forwarded-Host subdomain.example.com:80;
proxy_set_header X-Forwarded-Server subdomain.example.com;
proxy_set_header X-Forwarded-For https://subdomain.example.ru/suf;

Добавив конфигурационный файл активируем его стандартным способом — через создание символьной ссылки

ln -s /etc/nginx/sites-availible/example.com /etc/nginx/sites-enabled

Проверяем конфигурацию веб-сервера

Если ошибок нет — даем команду на перечитывание конфигурационных файлов

Nginx proxy_pass

Директива nginx proxy redirect

Схожим образом можно настроить в конфигурационном файле nginx редирект с одного адреса на другой.

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

Очень часто используется простое проксирование на IP адрес из приватной сети

location /
root /var/www/sites/example.com;
proxy_pass https://127.0.0.10;

С самой простой реализацией Nginx proxy_pass, приведенной выше, запускаются проекты на NodeJS и фреймоворке Express. Изначально они стартуют на localhost и порту 3000

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

настройка проксирования запросов в nginx

Здесь в закомментирвоанном виде представлены директивы для перенаправления запросов на порт 9000 к сервису php-fpm.

Читайте о том что делать если на сервере с конфигурацией с proxy_pass стала возникать ошибка с кодом 502.

Часть 2.2. Установка Nginx и настройка его в качестве обратного прокси-сервера

В этой статье описывается, как установить Nginx и настроить его в качестве обратного прокси-сервера.

Предварительные требования

Для выполнения упражнений в этой части необходимо создать ASP.NET Core и развернуть его в папке /var.

Цель этой части

В предыдущей части вы создали веб-приложение ASP.NET Core с помощью средства .NET CLI, и приложение развертывается в папке /var. Приложение также было настроено для прослушивания порта 5000 для HTTP-запросов, а перенаправление HTTPS было удалено.

На этом этапе клиенты должны указать номер порта при подключении к приложению (например, http://localhost:5000 ). Однако это не нужное поведение.

В этой части мы перечислены ниже.

  • Клиенты должны иметь возможность перемещаться без необходимости указать номер порта. Например, клиенты должны подключаться с помощью http://localhost .
  • Веб-приложение должно запускаться автоматически, если оно останавливается по какой-либо причине или после перезагрузки компьютера.

В следующем разделе вы будете использовать Nginx в качестве прокси-сервера для маршрутизации HTTP-запросов, которые выполняются на порт 80 в наше приложение .NET. Вы также настроите автоматическое запуск приложения.

Что такое Nginx?

Nginx — это популярный, упрощенный и быстрый веб-сервер. Он может выполняться как в Linux, так и в Windows, и его можно настроить как обратный прокси-сервер.

Что такое управляющая программа?

Nginx выполняется как управляющая программа. Управляющая программа — это альтернативный термин для службы, которая выполняется в фоновом режиме. Как и службы, которые выполняются в Windows, управляющие программы можно настроить для автоматического запуска во время запуска. Вы настроите ASP.NET Core запуска от имени управляющей программы.

Установка Nginx с помощью APT

Установить Nginx очень просто. Выполните sudo apt install nginx команду, чтобы установить программу на виртуальной машине Ubuntu.

Снимок экрана: команда sudo.

После завершения установки выполните команду whereis nginx , чтобы узнать, где установлена программа. Чтобы узнать, где находятся файлы конфигурации Nginx, просмотрите выходные данные. На следующем снимке экрана показано, что файлы конфигурации находятся в папке /etc/nginx .

Снимок экрана: команда whereis.

Если вы запустите дистрибутив, отличный от Ubuntu или Debian, вы можете найти эквивалентную команду установки диспетчера пакетов или инструкции из официальной документации по установке Nginx.

Управление службами с помощью systemctl

Если вы не видите, что Nginx запущен, его можно запустить явным образом, выполнив команду sudo systemctl start nginx . Хотя в этом упражнении будут systemctl показаны команды для Nginx, эти команды используются для настройки автоматического запуска веб-приложения в качестве управляющей программы.

После завершения установки Nginx уже настроен для автоматического запуска. Nginx выполняется как управляющая программа. Состояние управляющей программы можно проверить с помощью systemctl.

Эта systemctl команда используется для управления службами для таких задач, как отображение состояния службы или запуск и остановка. Некоторые доступные параметры: start, stop, restart, enable, disable и status. Чтобы проверить состояние Nginx, выполните команду systemctl status nginx .

Снимок экрана: команда systemctl.

Эта команда создает некоторые полезные сведения. Как показано на этом снимке экрана, Nginx active (running) находится в состоянии, а идентификатор процесса экземпляра Nginx — 8539. Также обратите внимание на enabled инструкции vendor preset: enabled и инструкции. Enabled означает, что эта управляющая программа запускается при перезапуске компьютера и означает, vendor preset: enabled что Nginx включен по умолчанию при его установке. Таким образом, Nginx запустится автоматически при запуске сервера.

Тестирование установки Nginx

По умолчанию Nginx прослушивает порт 80. Так как он работает, вы должны иметь доступ к главной странице Nginx при просмотре localhost. Используется curl для тестирования Nginx, выполнив команду curl localhost . Желтый выделенный текст на следующем снимке экрана показывает веб-страницу Nginx по умолчанию. Таким образом, Nginx выполняется:

Снимок экрана: команда curl.

Параметры команд systemctl

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

Перезапуск управляющих программ

Может потребоваться время от времени перезапускать управляющие программы. Чтобы перезапустить управляющую программу, выполните команду sudo systemctl restart . Чтобы перезапустить Nginx, выполните команду sudo systemctl restart nginx . Убедитесь, что вы проверяете состояние Nginx до и после выполнения этой команды, чтобы отслеживать изменения идентификатора процесса.

Остановка управляющих программ

Чтобы остановить управляющую программу, выполните команду sudo systemctl stop . Чтобы остановить Nginx, запустите sudo systemctl stop nginx и проверьте состояние Nginx, выполнив команду systemctl status nginx еще раз. На этот раз служба отображается как неактивная (неактивная), но по-прежнему включена. Это означает, что хотя служба не запущена, она запускается автоматически после перезапуска сервера.

Снимок экрана: команда stop.

Эта systemctl status команда также отображает несколько строк предыдущих записей журнала для управляющей программы.

После остановки Nginx выполните еще curl localhost раз.

Подключение отклонено, так как ничего не прослушивает входящий трафик через порт 80.

Снимок экрана: Сайт Localhost в Файле Поглуша.

Отключение управляющих программ

Отключение управляющей программы отличается от остановки управляющей программы. Отключенная управляющая программа может быть запущена, но не запускается автоматически после перезапуска сервера. Чтобы отключить управляющую программу Nginx, sudo systemctl disable nginx выполните и проверьте состояние Nginx.

Снимок экрана: команда

На этом снимке экрана показано, что Nginx не запущен и отключен. Это означает, что Nginx не запускается автоматически после перезапуска.

Запуск управляющих программ

Чтобы запустить управляющую программу, выполните команду sudo systemctl start . Чтобы запустить Nginx, выполните команду sudo systemctl start nginx , а затем снова проверьте состояние службы.

Снимок экрана: команда

На этом снимке экрана показано, что Nginx запущен, но по-прежнему отключен. Несмотря на то, что служба запущена, Nginx не запускается автоматически после перезапуска, так как она отключена.

Включение управляющих программ

Включение службы означает, что она запускается автоматически после перезапуска. Чтобы включить Nginx, запустите sudo systemctl enable nginx и снова проверьте состояние Nginx.

Снимок экрана: команда включения.

На этом снимке экрана показано, что Nginx запущен и будет запущен после перезапуска сервера.

Настройка Nginx в качестве обратного прокси-сервера для маршрутизации запросов в приложение ASP.NET Core.

Теперь, когда вы узнали, как запустить, остановить и перезапустить службу Nginx, вы настроите Nginx в качестве обратного прокси-сервера для маршрутизации запросов, выполненных через порт 80, в приложение ASP.NET Core, прослушивающее порт 5000.

Ниже приведена необходимая конфигурация. Выделены некоторые ключевые части.

http < map $http_connection $connection_upgrade < "~*Upgrade" $http_connection; default keep-alive; >server < listen 80; server_name _; location / < proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; >> > 

Эта конфигурация указывает на следующее:

  • Nginx будет прослушивать порт 80 для всех запросов (директива: listen 80 ).
  • Nginx направит запросы http://localhost:5000 в (директива: proxy_pass http://localhost:5000 )

Строка server_name _ в коде. Используется в качестве директивы catch-all. Дополнительные сведения о server_name см. в официальной документации.

Изменения конфигурации выглядят просто. Мы будем использовать этот код для замены раздела директивы server в файле конфигурации. Но где находится файл конфигурации?

Поиск правильного файла конфигурации Nginx

Основным файлом конфигурации Nginx является /etc/nginx/nginx.conf . Чтобы проверить конфигурацию, используйте команду cat /etc/nginx/nginx.conf и найдите директиву сервера.

Снимок экрана: команда cat.

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

Снимок экрана: команда include.

Директивы include упрощают управление конфигурацией, разделив ее на блоки, которые будут включены в основной файл конфигурации. Основной файл конфигурации может быть простым, а некоторые конкретные части конфигурации можно переместить в другие файлы. Выделенные строки на этом снимке экрана указывают на следующее:

  • Nginx загрузит конфигурацию из каждого conf-файла , расположенного в каталоге /etc/nginx/conf.d .
  • Nginx загрузит конфигурации из каждого файла, расположенного в каталоге /etc/nginx/sites-enabled .

При проверке этих каталогов файлы конфигурации не будут находиться в файле /etc/nginx/conf.d. Однако в / etc/nginx/sites включен один файл.

Снимок экрана: команда conf.

Файл конфигурации по умолчанию выглядит как простое кандидат для размещения нужной конфигурации. Если вы проверяете файл /etc/nginx/sites-enabled/default cat /etc/nginx/sites-enabled/default с помощью, вы увидите, что директива сервера по умолчанию помещается в следующий код.

Снимок экрана: сведения по умолчанию.

Поэтому для изменения конфигурации необходимо изменить файл /etc/nginx/sites-enabled/default .

Изменение файла конфигурации с помощью vi

Вы узнали, как изменять файлы при редактировании файла Startup.cs , чтобы удалить перенаправление HTTPS из ASP.NET конвейера. Теперь вы снова будете использовать vi для изменения файла конфигурации nginx.

Всегда создайте резервную копию файлов, которые вы изменяете. Если после редактирования что-то пошло не так, эту копию можно использовать для восстановления файла до предыдущего состояния. В этом случае выполните команду cp /etc/nginx/sites-enabled/default ~/nginx-default-backup , чтобы скопировать файл конфигурации в домашний каталог. Имя файла резервной копии будет. nginx-default-backup Обратите внимание, что резервная копия не была выполнена в том же каталоге, что и исходный файл. Это связано с тем, что Nginx загружает все файлы конфигурации из этого каталога, и вы не хотите нарушать конфигурацию, загружая две разные версии директивы сервера.

Выполните sudo vi /etc/nginx/sites-enabled/default команду, чтобы изменить файл конфигурации и заменить директиву сервера, как показано на следующем снимке экрана.

Снимок экрана: команда vi.

Ниже приведены некоторые советы и рекомендации по редактированию файлов с помощью Vi:

  • С помощью клавиш со стрелками можно прокручивать их вверх и вниз.
  • Чтобы перейти в режим редактирования, нажмите клавишу INSERT или I . Пока вы в режиме редактирования, в левом нижнем углу появится сообщение —INSERT .
  • В режиме редактирования можно использовать клавиатуру для удаления символов по одному.
  • В режиме редактирования операции копирования и вставки работают вместе с большинством терминалов. Таким образом, вы можете скопировать содержимое из этой статьи и вставить его в vi.
  • Чтобы выйти из режима редактирования, нажмите клавишу ESC.
  • Вы можете легко удалять строки в обычном режиме. В обычном режиме перейдите к началу строки, которую нужно удалить, и введите dd. Команда dd удаляет всю строку. Можно также ввести 5dd, чтобы удалить пять строк одновременно. Однако этот параметр следует использовать с осторожностью, чтобы избежать удаления дополнительного содержимого.
  • Чтобы узнать, как удалить несколько строк в Vi, рекомендуется удалить строки в Vi.
  • Чтобы выйти из vi и сохранить изменения, введите :wq!, а затем нажмите клавишу ВВОД. В этом случае двоеточие ( : ) означает, что вы выполняете команду, w записываете изменения, q означает ! выход и переопределение изменений.
  • Чтобы выйти без сохранения изменений, введите :q!, а затем нажмите клавишу ВВОД.

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

Снимок экрана: команда t.

Как видите, измененный файл конфигурации выглядит правильно.

Чтобы изменения вступили в силу, необходимо перезапустить Nginx:

sudo systemctl restart nginx 

После перезапуска ожидается ответ от приложения ASP.NET Core при выполнении запроса на h ttp://localhost , так как Nginx должен работать в качестве обратного прокси-сервера для запросов, выполненных на порт 80.

Перезапустите службу Nginx, чтобы изменения вступили в силу, а затем выполните запрос к localhost curl localhost . Однако эта команда завершится ошибкой. Следующим шагом является запуск wget localhost , а затем поиск некоторых указаний об источнике проблемы.

Снимок экрана: команда wget.

Устранение неполадок с прокси-сервером Nginx

На предыдущем снимке экрана отображаются следующие сведения:

Resolving localhost (localhost). 127.0.0.1 Connecting to localhost (localhost)|127.0.0.1|:80. connected. HTTP request sent, awaiting response. 502 Bad Gateway 2020-12-27 21:15:53 ERROR 502: Bad Gateway. 

Первая и вторая строки указывают, что вы можете разрешить localhost и подключиться к сокету 127.0.0.1:80 . Таким образом, Nginx должен быть запущен. Чтобы проверить это, выполните команду systemctl status nginx .

Третья строка указывает источник проблемы. Вы получаете сообщение об ошибке HTTP 502 Bad Gateway . Недопустимый шлюз HTTP 502 связан с прокси-серверами. Это означает, что обратному прокси-серверу не удалось подключиться к внутреннему приложению. В этом случае именно ваше веб-приложение ASP.NET Core, которое должно выполняться и прослушивать порт 5000 для запросов. Мы должны проверить, запущено ли веб-приложение.

Чтобы начать устранение неполадок, выполните ту же netstat команду, что и раньше. На этот раз используйте grep для фильтрации порта приложения 5000. Затем выполните команду netstat -tlp | grep 5000 .

Снимок экрана: команда netstat.

В этом примере выходных данных указывается, что порт 5000 не прослушивается. Таким образом, это причина ответа HTTP 502 , который поступает из Nginx, так как он может найти процесс, прослушивающий порт 5000.

Решением является запуск приложения ASP.NET Core приложения. Однако прежде чем продолжить, можно ознакомиться с другим подходом для устранения этой проблемы. Не все проблемы так легко устранить, как просто просмотреть несколько строк содержимого журнала и найти первопричину. Иногда необходимо подробно изучить другие системные журналы и журналы приложений.

Так как вы тесно работаете с Nginx при настройке ASP.NET Core в Linux, мы рекомендуем узнать, какие журналы Nginx и операционная система предоставляют для устранения неполадок.

Проверка журналов Nginx

Если вы запустите cat /etc/nginx/nginx.conf его еще раз, а затем logging settings выполните поиск, обратите внимание на следующее.

Снимок экрана: сведения о журнале.

Это показывает, что Nginx имеет два типа журналов: журналы доступа и журналы ошибок. Они хранятся в каталоге /var/log/nginx/ .

Журналы доступа похожи на файлы журналов IIS. Быстрая проверка содержимого показывает, что они похожи на следующий снимок экрана.

Снимок экрана: команда access.

В журналах доступа не отображаются новые сведения, отличные от состояния ответа HTTP 502, которое вы уже знали. Вы также можете проверить журналы ошибок, выполнив команду cat /var/log/nginx/error.log . Это позволяет узнать больше о причине проблемы.

Снимок экрана: сведения об ошибке.

Указания понятны: Nginx может получить запрос от клиента, upstream http://127.0.0.1:5000 но не может подключиться к серверу в приложении ASP.NET Core, которое должно было выполняться и прослушивать этот порт.

Обходной путь

Чтобы обойти эту проблему, запустите приложение ASP.NET Core вручную. Подключитесь к серверу с помощью второго сеанса терминала, а затем запустите ASP.NET Core, как и раньше.

Снимок экрана: сведения о aspnet.

Пока ASP.NET Core приложение, переключитесь на другой сеанс терминала и выполните ту же curl localhost команду. Теперь вы можете получить доступ к приложению ASP.NET Core, работающему за Nginx. На следующем снимке экрана показано, что вы сделали запрос к localhost, запрос был обработан Nginx и перенаправлен во внутреннее приложение, и вы получили ответ от ASP.NET Core приложения.

Снимок экрана: команда curllocalhost.

Теперь вы настроите Nginx для работы в качестве обратного прокси-сервера для ASP.NET Core приложения, работающее в Linux.

Однако если ASP.NET Core приложение не запускается после перезапуска, какой будет результат? Что произойдет, если веб-приложение аварийно завершает работу и не запускается, пока вы не заметите, что оно не запущено? Следует ли запускать приложение ASP.NET Core после каждого перезапуска процесса?

Дальнейшие действия

Заявление об отказе от ответственности за сведения о продуктах сторонних производителей

В этой статье упомянуты программные продукты независимых производителей. Корпорация Майкрософт не дает никаких гарантий, подразумеваемых и прочих, относительно производительности и надежности этих продуктов.

Обратная связь

Были ли сведения на этой странице полезными?

Основы работы с Nginx: проксирование, балансировка нагрузки, буферизация и кэширование

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

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

Основы проксирования

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

Вторя причина настроить HTTP-проксирование – это наличие в инфраструктуре серверов приложений, которые не могут обрабатывать клиентские запросы напрямую в производственных средах. Многие фреймворки предоставляют встроенные веб-серверы, но большинство из них не столь надежны, как высокопроизводительные серверы, такие как Nginx. Использование обратного прокси Nginx может улучшить пользовательский опыт и повысить безопасность.

Проксирование в Nginx осуществляется путем обработки запроса, направленного на сервер Nginx, и передачи его другим серверам для фактической обработки. Результат запроса передается обратно на Nginx, который затем передает информацию клиенту. Другими серверами в этом случае могут быть удаленные компьютеры, локальные серверы или даже другие виртуальные серверы, определенные в настройке Nginx. Серверы, к которым обращается прокси Nginx, называются upstream серверами.

Nginx может проксировать запросы на серверы, которые обмениваются данными с помощью протоколов http(s), FastCGI, SCGI и uwsgi или memcached через отдельные наборы директив для каждого типа проксирования. В этом мануале мы сосредоточимся на протоколе http. Экземпляр Nginx отвечает за передачу запроса и связь с любым компонентом обмена сообщениями в формате, который может понять upstream сервер.

Директива proxy_pass

Самый простой тип проксирования включает в себя передачу запроса на один сервер, который может связываться с помощью http. Этот тип проксирования известен как proxy pass и обрабатывается одноименной директивой proxy_pass.

Директива proxy_pass в основном встречается в контекстах location. Она также поддерживается блоками if в контексте location и limit_except. Когда запрос совпадает с адресом, указанным в proxy_pass, он пересылается по этому URL-адресу.

Рассмотрим такой пример:

# server context
location /match/here proxy_pass http://example.com;
>
. . .

В приведенном выше фрагменте конфигурации в конце блока server в определении proxy_pass не указывается URI. Для определений, соответствующих этому шаблону, запрошенный клиентом URI будет передан на upstream сервер без изменений.

Например, когда этот блок обрабатывает запрос /match/here/please, URI запроса будет отправлен на сервер example.com как http://example.com/match/here/please.

Рассмотрим альтернативный сценарий:

# server context
location /match/here proxy_pass http://example.com/new/prefix;
>
. . .

В приведенном выше примере прокси-сервер определяется вместе с сегментом URI в конце (/new/prefix). Когда в определении proxy_pass указывается URI, то часть запроса, которая соответствует определению location, заменяется этим URI.

К примеру, запрос /match/here/please будет передаваться на upstream сервер как http://example.com/new/prefix/please. Префикс /match/here заменяется на /new/prefix. Об этом важно помнить.

Иногда такая замена невозможна. В этих случаях URI в конце определения proxy_pass игнорируется, и на upstream сервер передается исходный URI клиента или URI, измененный другими директивами.

Например, при использованием регулярных выражений Nginx не может определить, какая часть URI соответствует выражению, поэтому он отправляет исходный URI-запрос клиента. Или, например, если директива rewrite используется в одном и том же location, она переписывает URI клиента, но он все же обрабатывается в одном блоке. В этом случае будет передан переписанный URI.

Обработка заголовков в Nginx

Чтобы upstream сервер обработал запрос должным образом, одного URI недостаточно. Запрос, поступающий от имени клиента через Nginx, будет выглядеть иначе, чем запрос, поступающий непосредственно от клиента. Большая часть этого – заголовки, которые согласуются с запросом.

Когда Nginx проксирует запрос, он автоматически вносит некоторые поправки в заголовки, полученные от клиента.

  • Nginx избавляется ото всех пустых заголовков. Нет смысла передавать пустые значения другому серверу; это только усложнит передачу запроса.
  • Все заголовки, которые содержат символы подчеркивания, Nginx по умолчанию рассматривает как недопустимые. Он удалит их из запроса. Если вы хотите, чтобы Nginx интерпретировал их как валидные, вы можете установить в директиве underscores_in_headers значение on, в противном случае такие заголовки никогда не попадут на бэкэнд-сервер.
  • Заголовок Host переписывается значением, определяемым переменной $proxy_host. Это может быть IP-адрес или имя и номер порта upstream сервера, как указано в директиве proxy_pass.
  • Заголовок Connection заменяется значением close. Этот заголовок используется для передачи информации о конкретном соединении, установленном между двумя сторонами. В этом случае Nginx устанавливает это значение, чтобы указать upstream серверу, что это соединение будет закрыто после ответа на исходный запрос. Не следует ожидать, что это upstream соединение будет постоянным.

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

Также следует убедиться, что в нестандартных заголовках нет подчеркиваний, что если ваше бэкэнд-приложение будет обрабатывать такие заголовки. Если вам нужны заголовки, в которых используется символ подчеркивания, вы можете установить директиве underscores_in_headers значение on (это валидно либо в контексте http, либо в контексте объявления server по умолчанию для комбинации IP-адреса/порта). Если вы этого не сделаете, Nginx пометит эти заголовки как некорректные и просто сбросит их, прежде чем перейти к upstream серверу.

Заголовок Host имеет особое значение в большинстве прокси-сценариев. Как указано выше, по умолчанию этот заголовок получит значение переменной $proxy_host, которая содержит домен или IP-адрес и порт, взятые непосредственно из определения proxy_pass. Это поведение определяется по умолчанию, так как это единственный адрес, на который точно отвечает upstream сервер Nginx.

Заголовок Host часто имеет такие значения:

  • $proxy_host: устанавливает в Host домен или IP-адрес и порт из определения proxy_pass. Это значение по умолчанию надежно с точки зрения Nginx, но оно не всегда подходит для правильной обработки запроса.
  • $http_host: устанавливает в Host заголовок Host из клиентского запроса. Заголовки, отправленные клиентом, всегда доступны Nginx в качестве переменных. Переменные начинаются с префикса $http_, после которого устанавливается имя заголовка в нижнем регистре, а все тире заменяются нижним подчеркиванием. Помните, что переменная $http_host не сработает, если в запросе клиента нет валидного заголовка Host.
  • $host: эта переменная может принимать в качестве значений имя хоста из запроса, заголовок host из клиентского запроса или имя сервера соответствующего запроса.

В большинстве случаев нужно установить в заголовке Host переменную $host. Это наиболее гибкий вариант, который обычно обеспечивает точное заполнение заголовка.

Настройка или сброс заголовков

Чтобы настроить или установить заголовки для прокси-соединений, можно использовать директиву proxy_set_header. Например, чтобы изменить заголовок Host и добавить дополнительные заголовки, нужно использовать что-то вроде этого:

# server context
location /match/here proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://example.com/new/prefix;
>
. . .

Здесь заголовок Host получит значение переменной $host, в которой должна содержаться информация о запрошенном исходном хосте. Заголовок X-Forwarded-Proto предоставляет прокси-серверу информацию о схеме исходного запроса клиента (будь то http или https-запрос).

X-Real-IP указывает IP-адрес клиента, чтобы прокси-сервер мог правильно принимать решения или вести лог на основе этой информации. Заголовок X-Forwarded-For – это список, содержащий IP-адрес каждого сервера, по которому проходил запрос. В приведенном выше примере устанавливается значение переменной $proxy_add_x_forwarded_for. Эта переменная принимает значение исходного X-Forwarded-Forheader, извлеченного из клиента, и добавляет IP-адрес сервера Nginx в конец.

Конечно, директиву proxy_set_header стоит переместить в контекст server или http, чтоб иметь возможность ссылаться на нее:

# server context
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location /match/here proxy_pass http://example.com/new/prefix;
>
location /different/match proxy_pass http://example.com;
>

Раздел Upstream для балансировки нагрузки проксируемых соединений

В предыдущих примерах вы увидели, как сделать настроить простое HTTP-прокси соединение на одном сервере. Nginx позволяет легко масштабировать эту конфигурацию, указав целые пулы бэкэнд-серверов, на которые можно передавать запросы.

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

Рассмотрим простой пример:

# http context
upstream backend_hosts server host1.example.com;
server host2.example.com;
server host3.example.com;
>
server listen 80;
server_name example.com;
location /proxy-me proxy_pass http:// backend_hosts ;
>
>

В приведенном выше примере был создан контекст upstream под названием backend_hosts. После определения это имя будет доступно в proxy pass как обычный домен. Как вы можете видеть, в блоке server все запросы, сделанные в example.com/proxy-me/…, передаются в пул, который вы определили выше. В этом пуле хост выбирается с помощью настраиваемого алгоритма. По умолчанию это простой процесс round-robin (каждый запрос будет поочередно маршрутизироваться на другой хост).

Изменение алгоритма балансировки в контексте upstream

Настроить алгоритм в пуле upstream можно с помощью таких флагов и директив:

  • round robin: Алгоритм балансировки нагрузки по умолчанию, который используется, если не указано других директив. Каждый запрос будет последовательно передаваться серверам, определенным в контексте upstream.
  • least_conn: Указывает, что новые соединения всегда должны быть привязаны к бэкэнду, который имеет наименьшее количество активных соединений. Это может быть особенно полезно в ситуациях, когда соединения с бэкэндом могут сохраняться в течение некоторого времени.
  • ip_hash: Этот алгоритм балансировки распределяет запросы между серверами на основе IP-адреса клиента. Первые три октета используются в качестве ключа, на основе которого выбирается сервер для обработки запроса. В результате клиенты, как правило, обслуживаются одним и тем же сервером при каждом подключении, что обеспечивает согласованность сеансов.
  • hash: Этот алгоритм балансировки в основном используется с прокси-сервером memcached. Серверы делятся на группы на основе значения произвольно предоставленного хэш-ключа. Ключ может быть текстом, переменной или разными комбинациями. Это единственный метод балансировки, который требует от пользователя предоставить данные (ключ).

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

# http context
upstream backend_hosts least_conn;
server host1.example.com;
server host2.example.com;
server host3.example.com;
>
. . .

В приведенном выше примере сервер будет выбран по наименьшему количеству соединений. Можно также добавить директиву ip_hash, чтобы обеспечить «липкость» сессии.

Что касается метода hash, вы должны указать ключ для хэша. Это может быть что угодно:

# http context
upstream backend_hosts hash $remote_addr$remote_port consistent;
server host1.example.com;
server host2.example.com;
server host3.example.com;
>
. . .

В приведенном выше примере запросы будут распределяться на основе значений IP-адреса и порта клиента. Также здесь есть опциональный параметр consistent, который реализует алгоритм хэширования ketama consistent. Это означает, что если upstream серверы изменятся, это будет иметь минимальное воздействие на кэш.

Установка веса сервера для балансировки

В объявлениях бэкэнд-серверов по умолчанию все серверы весят одинаково. Это предполагает, что каждый сервер может и должен обрабатывать одинаковый объем нагрузки (с учетом эффектов алгоритмов балансировки). Тем не менее, вы также можете установить пользовательский вес своих серверов:

# http context
upstream backend_hosts server host1.example.com weight=3;
server host2.example.com;
server host3.example.com;
>
. . .

Теперь host1.example.com будет получать в три раза больше трафика, чем другие два сервера. Вес каждого сервера по умолчанию равен 1.

Использование буферов для освобождения бэкэнд-серверов

Один из главных вопросов при проксировании – насколько изменится скорость работы при добавлении сервера. Увеличение или уменьшение количества серверов можно значительно смягчить с помощью системы буферизации и кэширования Nginx.

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

  • Подключения клиента к прокси Nginx.
  • И подключения прокси-сервера Nginx к серверу.

Nginx имеет возможность корректировать свое поведение на основе того, какое из этих соединений вы хотите оптимизировать.

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

Nginx по умолчанию использует буферизацию, так как скорость соединения, как правило, меняется в зависимости от клиента. Буферизация настраивается с помощью следующих директив. Их можно установить в контексте http, server или location. Важно иметь в виду, что директивы size касаются каждого запроса, поэтому они могут повлиять на производительность серверов при поступлении множества клиентских запросов.

  • proxy_buffering: эта директива определяет, включена ли буферизация для этого контекста и его дочерних контекстов. По умолчанию имеет значение on.
  • proxy_buffers: Эта директива контролирует количество (первый аргумент) и размер (второй аргумент) буферов. По умолчанию используется 8 буферов, размер которых равен одной странице памяти (либо 4k, либо 8k). Увеличение количества буферов позволяет буферизовать дополнительную информацию.
  • proxy_buffer_size: Исходная часть ответа от бэкэнд-сервера, которая содержит заголовки, буферизуется отдельно от остальных данных. Эта директива устанавливает размер буфера для этой части ответа. По умолчанию она будет того же размера, что и proxy_buffers, но поскольку здесь хранятся только заголовки, ее можно уменьшить.
  • proxy_busy_buffers_size: Эта директива устанавливает максимальное количество занятых буферов. Хотя клиент может считывать данные только из одного буфера за раз, буферы помещаются в очередь для отправки фрагментов данных клиенту. Эта директива управляет размером буферного пространства, которое может находиться в этом состоянии.
  • proxy_max_temp_file_size: Это максимальный размер временного файла каждого запроса на диске. Они создаются, если ответ бэкэнда слишком велик и не помещается в буфер.
  • proxy_temp_file_write_size: Это количество данных, которые Nginx будет записывать во временный файл за один раз, если ответ прокси-сервера слишком велик и не помещается в буфер.
  • proxy_temp_path: Это путь к области на диске, где Nginx должен хранить временные файлы, когда ответ upstream сервера не помещается в буфер.

Как вы можете видеть, Nginx предоставляет довольно много разных директив для настройки поведения буферизации. В большинстве случаев вам не придется использовать их, но некоторые из этих значений могут пригодиться. Возможно, наиболее полезными являются proxy_buffers и proxy_buffer_size.

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

# server context
proxy_buffering on;
proxy_buffer_size 1k;
proxy_buffers 24 4k;
proxy_busy_buffers_size 8k;
proxy_max_temp_file_size 2048m;
proxy_temp_file_write_size 32k;
location / proxy_pass http://example.com;
>

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

# server context
proxy_buffering off;
proxy_buffer_size 4k;
location / proxy_pass http://example.com;
>

Высокая доступность (опционально)

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

Настройка высокой доступности – это инфраструктура без единой точки отказа, и балансировщики нагрузки являются частью этой конфигурации. Имея несколько балансировщиков нагрузки, вы сможете предотвратить простои, если один из балансировщиков станет недоступен.

Кэширование и снижение времени ответа

Буферизация помогает освободить сервер бэкэнда для обработки большего количества запросов, но Nginx также может кэшировать контент с бэкэнд-серверов, устраняя необходимость подключения к upstream серверу для обработки запросов.

Настойка прокси-кэша

Для настройки кэширования ответов бэкэнд серверов можно использовать директиву proxy_cache_path, которая определяет пространство для хранения кэша. Её следует задавать в контексте http.

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

# http context
proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=backcache:8m max_size=50m;
proxy_cache_key «$scheme$request_method$host$request_uri$is_args$args»;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;

Директива proxy_cache_path определяет каталог в файловой системе, где нужно хранить кэш. В этом примере это каталог /var/lib/nginx/cache. Если этот каталог не существует, вы можете создать его и определить права доступа к нему:

sudo mkdir -p /var/lib/nginx/cache
sudo chown www-data /var/lib/nginx/cache
sudo chmod 700 /var/lib/nginx/cache

Параметр levels= указывает, как будет организован кэш. Nginx создаст ключ кеша путем хэширования значения ключа (он настраивается ниже). В результате будет создан каталог, имя которого состоит из одного символа (это будет последний символ хешированного значения), и подкаталог с именем из двух символов (следующие два символа в конце хэша). Это помогает Nginx быстро найти соответствующие значения.

Параметр keys_zone= определяет имя зоны кеша (backcache). Здесь также указывается, сколько метаданных можно хранить. В этом случае сервер будет хранить 8 МБ ключей. На 1 мегабайте Nginx может хранить около 8000 записей. Параметр max_size устанавливает максимальный размер кэшированных данных.

Директива proxy_cache_key устанавливает ключ, который будет использоваться для хранения кешированных значений. Этот же ключ используется для проверки того, можно ли запросить данные из кеша. Здесь используется комбинация схемы (http или https), метода HTTP-запроса, а также запрошенного хоста и URI.

Директива proxy_cache_valid может быть указана несколько раз. Она позволяет определить, как долго должны храниться значения в зависимости от кода состояния. В данном примере удачные и переадресованные ответы хранятся в течение 10 минут, а ответы 404 удаляются каждую минуту.

Теперь зона кэширования настроена, но пока что Nginx не знает, когда именно применять кеширование.

Эта информация указывается в контексте location для бекэнд серверов:

# server context
location /proxy-me proxy_cache backcache;
proxy_cache_bypass $http_cache_control;
add_header X-Proxy-Cache $upstream_cache_status;
proxy_pass http://backend;
>
. . .

Используя директиву proxy_cache, можно указать, что для этого контекста следует использовать зону кэширования backcache. Nginx проверит запись перед тем, как перейти к серверу.

Директива proxy_chache_bypass принимает значение переменной $http_cache_control. Эта переменная сообщает, запросил ли клиент свежий, не кэшированный ответ. При использовании этой директивы Nginx сможет корректно обрабатывать запросы такого типа. Никаких дальнейших настроек не для этого не требуется.

Мы также добавили дополнительный заголовок X-Proxy-Cache. Этот заголовок принимает значение переменной $upstream_cache_status. Это позволяет увидеть, обработан ли запрос из кэша, этих данных не было в кэше или клиент запросил новый ответ. Это особенно полезно для отладки.

Рекомендации по кэшированию результатов

Кеширование увеличивает скорость прокси-сервера. Но не стоит забывать о нескольких нюансах.

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

Если на сайте есть динамические элементы, им следует уделить внимание. Решение этой проблемы зависит от бекэнд-сервера. Для личных данных используется заголовок Cache-Control со значением no-cache, no-store или private.

  • no-cache: ответ не будет отправлен, пока сервер не проверит данные на бекэнд-сервере. Это значение используется с динамическими данными. Хэшированные метаданные заголовка Etag проверяются при каждом запросе. Если бекэнд вернет теже значения, то данные отправляются из кэша клиенту.
  • no-store: данные не должны храниться в кэше ни при каких обстоятельствах. Это самый безопасный подход при работе с личными данными.
  • private: данные не должны кэшироваться в общем кэше. То есть, к примеру, браузер пользователя может кешировать данные, а прокси-сервер нет.
  • public: данные можно кэшировать везде.

Есть связанный с этим поведением заголовок max-age, который определяет срок хранения кэша в секундах.

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

Если вы используете nginx и на бэкэнде, добавьте директиву expires, которая определяет значение max-age заголовка Cache-Control:

location / expires 60m;
>
location /check-me expires -1;
>

Первый блок поддерживает кэш в течение часа. Второй блок присваивает заголовку Cache-Control значение no-cache. Для внесения других изменений примените директиву add_header:

location /private expires -1;
add_header Cache-Control «no-store»;
>

Проксируем и спасаем

1

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

В данном пособии мы узнаем как быстро и просто сделать рабочее зеркало любого сайта, что позволяет сменить IP и назначить любое доменное имя. Мы даже попробуем спрятать домен в url, после чего можно сохранить локально полную копию сайта. Все упражнения можно сделать на любом виртуальном сервере — лично я использую хостинг Хетцнер и OS Debian. И конечно мы будем использовать лучший веб-сервер всех времен и народов — NGINX!

К этому абзацу пытливый читатель уже приобрел и настроил какой нибудь выделенный сервер или просто запустил Linux на старом компьютере под столом, а так же запустил Nginx последней версии со страничкой «Save me now».

Перед началом работы необходимо скомпилировать nginx c модулем ngx_http_substitutions_filter_module, прежнее название — substitutions4nginx.

Дальнейшая конфигурация будет показана на примере сайта www.6pm.com. Это сайт популярного онлайн магазина, торгующего товарами с хорошими скидками. Он отличается категорическим нежеланием давать доступ покупателям из России. Ну чем не оскал цензуры капитализма?

У нас уже есть работающий Nginx, который занимается полезными делом — крутит сайт на системе Livestreet о преимуществах зарубежного шоппинга. Чтобы поднять зеркало 6pm прописываем DNS запись с именем 6pm.pokupki-usa.ru который адресует на IP сервера. Как вы понимаете, выбор имени для суб-домена совершенно произволен. Это имя будет устанавливаться в поле HOST при каждом обращении к нашему новому ресурсу, благодаря чему на Nginx можно будет запустить виртуальный хостинг.

В корневой секции конфигурации nginx прописываем upstream — имя сайта-донора, так будем его называть в дальнейшем. В стандартных гайдах сайт обычно называется back-end, а reverse-proxy называется front-end.

http

Дальше нужно создать секцию server, вот как она выглядит

 server < listen 80; server_name 6pm.pokupki-usa.ru; limit_conn gulag 64; access_log /var/log/nginx/6pm.access.log; error_log /var/log/nginx/6pm.error.log; location / < root /var/www/6pm; try_files $uri @static; >location @static < include '6pm.conf'; proxy_cookie_domain 6pm.com 6pm.pokupki-usa.ru; proxy_set_header Accept-Encoding ""; proxy_set_header Host www.6pm.com; proxy_pass http://6pm; proxy_redirect http://www.6pm.com http://6pm.pokupki-usa.ru; proxy_redirect https://secure-www.6pm.com https://6pm.pokupki-usa.ru; >> 

Стандартные директивы listen и server определяют имя виртуального хоста, при обращении к которому будет срабатывать секция server. Файлы логов лучше сделать отдельными.

Объявляем корневой локейшин, указываем путь до его хранилища — root /var/www/6pm; затем используем try_files. Это очень важная директива nginx, которая позволяет организовать локальное хранилище для загруженных файлов. Директива сначала проверяет нет ли файла с именем $uri и если не находит его — переходит в именованный локейшин @ static

$uri — переменная nginx, которая содержит путь из HTTP запроса

Префикс “@” задаёт именованный location. Такой location не используется при обычной обработке запросов, а предназначен только для перенаправления в него запросов. Такие location’ы не могут быть вложенными и не могут содержать вложенные location’ы

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

include ‘6pm.conf’ — логика модуля substitutions.

proxy_cookie_domain — новая функция, которая появилась в nginx версии 1.1.15, без этой директивы приходилось делать так. Больше не нужно ломать голову, прописываете одну строчку и куки просто начинают работать.

proxy_set_header Accept-Encoding «»; — очень важная команда, которая заставляет сайт донор отдавать вам контент не в сжатом виде, иначе модуль substitutions не сможет выполнить замены.

proxy_set_header Host — еще одна важная команда, которая в запросе к сайту донору выставляет правильное поле HOST. Без нее будет подставляться имя нашего прокси сервера и запрос будет ошибочным.
proxy_pass — прямая адресация не работает в именованном локейшине, именно поэтому мы прописали адрес сайта донора в директиве upstream.
proxy_redirect — многие сайты используют редиректы для своих нужд, каждый редирект нужно отловить и перехватить здесь, иначе запрос и клиент уйдет за пределы нашего уютного доменчика.

Теперь посмотрим содержимое 6pm.conf. Я не случайно вынес логику трансформации в отдельный файл. В нем можно разместить без какой либо потери производительности тысячи правил замены и сотни килобайт фильтров. В нашем случае мы хотим лишь завершить процесс проксирования, поэтому файл содержит всего 5 строк:

Меняем коды google analytics:

subs_filter 'UA-8814898-13' 'UA-28370154-3' gi; subs_filter "'.6pm.com']," "'6pm.pokupki-usa.ru']," gi; 

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

Меняем все прямые ссылки на новые.

subs_filter "www.6pm.com" "6pm.pokupki-usa.ru" gi; subs_filter "6pm.com" "6pm.pokupki-usa.ru" gi; 

Как правило, в нормальных сайтах все картинки лежат на CDN сетях, которые не утруждают себя проверкой источника запросов, поэтому достаточно замены ссылок только основного домена. В нашем случае 6pm выпендрился и разместил часть картинок на доменах, которые отказывают посетителям из России. К счастью, модуль замены поддерживает регулярные выражения и не составляет никакого труда написать общее правило для группы ссылок. В нашем случае обошлось даже без regexp, просто поменяли два символа в домене. Получилось так:

subs_filter "http://a..zassets.com" "http://l3.zassets.com" gi; 

Единственное, но очень серьезное ограничение модуля замены — он работает только с одной строкой. Это ограничение заложено архитектурно, поскольку модуль работает на этапе, когда страница загружена частично (chunked transfer encoding) и нет никакой возможности выполнить полнотекстовый regexp.

Все, можно посмотреть на результат, все работает, даже оплата заказа проходит без затруднений.

  1. Абсолютные ссылки вида «www.example.com/some/path»
  2. Ссылки относительно корня сайта вида «/some/path»
  3. Относительные ссылки вида «some/path»

С п.1 все просто — мы заменяем все ссылки на новый путь с поддиректорией
С п.3 так же просто — мы ничего не трогаем и все работает само если не использовался атрибут base href. Если этот атрибут используется, что бывает крайне редко в современных сайтах, то достаточно его заменить и все будет работать.

Настоящая сложность возникает с п.2. из-за того что мы должны изменить кучу ссылок вида /. на /subdomain/. . Если сделать это в лоб, то сайт скорее всего полностью перестанет работать, ибо такая замена сломает множество конструкций использующих слеш, что испортит почти все скрипты javascript.

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

Вернемся к нашему пациенту:

 location /6pm < root /var/www/6pm; try_files $uri @6pm-static; access_log /var/log/nginx/6pm.access.log; >location @6pm-static < include '6pm2.conf'; proxy_cookie_domain 6pm.com pokupki-usa.ru; proxy_cookie_path / /6pm/; rewrite ^/6pm/(.*) /$1 break; proxy_set_header Accept-Encoding ""; proxy_set_header Host www.6pm.com; proxy_pass http://6pm; proxy_redirect http://www.6pm.com http://pokupki-usa.ru/6pm; proxy_redirect http://www.6pm.com/login http://pokupki-usa.ru/6pm; proxy_redirect https://secure-www.6pm.com https://pokupki-usa.ru/6pm; 

Конфигурация сервера претерпела некоторые изменения.

Во-первых, вся логика перенесена из директивы sever напрямую в location. Нетрудно догадаться, что мы решили создать директорию /6pm в которую будем выводить проксируемый сайт.

proxy_cookie_path / /6pm/ — переносим куки из корня сайта в поддиректорию. Это делать не обязательно, но в случае если проксируемых сайтов окажется много, их куки могут пересечься и затереть друг друга.

rewrite ^/6pm/(.*) /$1 break; — эта магия вырезает из клиентского запроса поддиректорию, которую мы добавили, в результате директива proxy_pass отправляет на сервер-донор корректное значение.

Чуть сложнее стало ловить редиректы. Теперь все ссылки на корень нужно перебросить на /6pm.

Посмотрим на логику трансформации:

subs_filter_types text/css text/javascript; # Fix direct links subs_filter "http://6pm.com" "http://pokupki-usa.ru/6pm" gi; subs_filter "http://www.6pm.com" "http://pokupki-usa.ru/6pm" gi; # Fix absolute links subs_filter 'src="https://habr.com/'%20'src="https://habr.com/6pm/'%20gi;%20subs_filter%20'href="/' 'href="/6pm/' gi; subs_filter 'action="/' 'href="/6pm/' gi; # Fix some js subs_filter "\"/le.cgi" "\"/6pm/le.cgi" gi; subs_filter "\"/track.cgi" "\"/6pm/track.cgi" gi; subs_filter "\"/onload.cgi" "\"/6pm/onload.cgi" gi; subs_filter "\"/karakoram" "\"/6pm/karakoram" gi; subs_filter "/tealeaf/tealeaf.cgi" "/6pm/tealeaf/tealeaf.cgi" gi; # Css and js path subs_filter "script\('/" "script('/6pm/" gi; subs_filter "url\(/" "url(/6pm/" gi; subs_filter 'UA-8814898-13' 'UA-28370154-3' gi; subs_filter "'.6pm.com']," "'pokupki-usa.ru/6pm']," gi; subs_filter "http://a..zassets.com" "http://l3.zassets.com" gi; 

Во-первых, мы включили фильтрацию файлов css и javascript (парсинг html включен по-умолчанию)
Во-вторых, начинаем аккуратно находить и заменять разные типы ссылок относительно корня. Нам попался средней сложности сайт, в котором часть скриптов содержат такие пути.

К сожалению, мне не удалось до конца написать фильтр для случая поддиректории. Я не дошел до преобразования динамических запросов скриптов корзины с покупками, хотя не сомневаюсь что это решаемо. Просто моих знаний в Javascript не достаточно чтобы выполнить необходимую отладку, буду рад советам как запустить корзину покупок, которая сейчас в упомянутом примере не работает.

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

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *