Как предотвратить тайм-аут шлюза с помощью fastcgi на nginx

СТАТИЧЕСКИЙ КОНТЕНТ ПРОТИВ ДИНАМИЧЕСКОГО КОНТЕНТА

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

Пример статического контента – это сообщение в блоге, которое вы читаете. Поскольку статический контент не часто меняется (или не меняется вообще), его кеширование и доставка очень просты.

Статический контент одинаков для всех пользователей

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

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

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

Создание файла .fcgi¶

Для начала нужно создать файл сервера FastCGI. Давайте назовём его
yourapplication.fcgi:

#!/usr/bin/python
from flup.server.fcgi import WSGIServer
from yourapplication import app

if __name__ == '__main__'
    WSGIServer(app).run()

Этого достаточно для работы Apache, однако nginx и старые версии lighttpd
требуют явного указания сокетов для связи с сервером FastCGI. Для этого
нужно передать путь к сокет-файлу в :

WSGIServer(application, bindAddress='/path/to/fcgi.sock').run()

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

Сохраните файл yourapplication.fcgi где-нибудь, где вы сможете потом
найти его. Неплохо положить его в /var/www/yourapplication или в
какое-то другое подходящее место.

Убедитесь, что у этого файла установлен флаг выполнения, чтобы сервер
мог его выполнить:

Использование Nginx в качестве обратного прокси

Чтобы настроить Nginx в качестве обратного прокси-сервера для HTTP-сервера, откройте файл конфигурации блока сервера домена и укажите местоположение и прокси-сервер внутри него:

server {
    listen 80;
    server_name www.example.com example.com;

    location /app {
       proxy_pass http://127.0.0.1:8080;
    }
}

URL прокси-сервера указывается с использованием директивы proxy_pass и может использовать HTTP или HTTPS как протокол, и имя домена или IP-адрес, а также необязательный порт и URI в качестве адреса.

В приведенной выше конфигурации Nginx передает все запросы к расположению /app прокси-сервера по адресу http://127.0.0.1:8080.

В дистрибутивах на основе Ubuntu и Debian серверные файлы блоков хранятся в каталоге /etc/nginx/sites-available, а на CentOS – в каталоге /etc/nginx/conf.d.

Чтобы лучше проиллюстрировать, как работают директивы location и как proxy_pass, давайте рассмотрим следующий пример:

server {
    listen 80;
    server_name www.example.com example.com;

    location /blog {
       proxy_pass http://node1.com:8000/wordpress/;
    }
}

Если посетитель http://example.com/blog/my-post получит доступ, nginx проксирует этот запрос http://node1.com:8000/wordpress/my-post.

Когда адрес прокси-сервера содержит URI /wordpress/, URI запроса, который передается на прокси-сервер, заменяется URI, указанным в директиве. Если адрес прокси-сервера указан без URI, полный URI запроса передается на прокси-сервер.

Настройка proxy_pass в nginx

Рассмотрим самый простой пример. Буду использовать свой технический домен zeroxzed.ru в этом и последующих примерах. Допустим, у нас есть сайт blog.zeroxzed.ru. В DNS создана A запись, указывающая на ip адрес сервера, где установлен nginx — nginx_srv. Мы будем проксировать все запросы с этого сервера на другой сервер в локальной сети blog_srv, где реально размещается сайт. Рисуем конфиг для секции server.

Заходим по адресу http://blog.zeroxzed.ru. Мы должны попасть на blog_srv, где тоже должен работать какой-то веб сервер. В моем случае это будет тоже nginx. У вас должно открыться содержимое, аналогичное тому, что вы увидите, набрав http://192.168.13.31 в локальной сети. Если что-то не работает, то проверьте сначала, что по адресу директивы proxy_pass у вас все корректно работает.

Посмотрим логи на обоих сервера. На nginx_srv вижу свой запрос:

Проверяем blog_srv:

Как мы видим, запрос сначала пришел на nginx_srv, был переправлен на blog_srv, куда он пришел уже с адресом отправителя 94.142.141.246. Это адрес nginx_srv. Реальный же ip адрес клиента мы видим только в самом конце лога. Это неудобно, так как директива php REMOTE_ADDR не будет возвращать настоящий ip адрес клиента. А он очень часто бывает нужен. Мы это дальше исправим, а пока создадим в корне сайта на chat_srv тестовую страничку для проверки ip адреса клиента следующего содержания:

Назовем ее myip.php. Перейдем по адресу http://blog.zeroxzed.ru/myip.php и проверим, как сервер определит наш адрес. Никак не определит Он покажет адрес nginx_srv. Исправляем это и учим nginx передавать реальный ip адрес клиента на сервер.

Как это будет работать?

Допустим, у нас есть несколько доменов example.com, sample.org, test.io. Первые два будут обрабатываться Apache, последний только Nginx. Все запросы будут поступать к Nginx, который работает на порту 80, если это запрос к одному из доменов Apache и он требует работы PHP, тогда он будет передан веб-серверу Apache, который работает на порту 8080.

Если же это запрос статического файла, то мы будем обрабатывать его тут же с помощью Nginx для увеличения производительности. Что касается поддержки SSL, то мы собираемся использовать модуль mod_pref чтобы заменить все необходимые заголовки для нормальной работы связки. Начнем с настройки Apache.

Заголовки прохождения запроса

Когда Nginx передает запрос через прокси, он автоматически определяет два поля заголовка в проксируемых запросах от клиента, Host и Connection и удаляет пустые заголовки. Host устанавливается на переменную $proxy_host и Connection устанавливается на закрытие.

Чтобы настроить или установить заголовки для прокси-соединений, используйте директиву proxy_set_header, а затем значение заголовка. Вы можете найти список всех доступных заголовков запросов и их допустимых значений здесь. Если вы хотите запретить передачу заголовка на прокси-сервер, установите для него пустую строку “”.

В следующем примере мы меняем значение поля заголовка Host на $host и удаляем поле заголовка Accept-Encoding, устанавливая его значение в пустую строку.

location / {
    proxy_set_header Host $host;
    proxy_set_header Accept-Encoding "";
    proxy_pass http://localhost:3000;
}

Передача https через nginx с помощью proxy pass

Если у вас сайт работает по https, то достаточно настроить ssl только на nginx_srv, если вы не беспокоитесь за передачу информации от nginx_srv к blog_srv. Она может осуществляться по незащищенному протоколу. Рассмотрю пример с бесплатным сертификатом let’s encrypt. Это как раз один из кейсов, когда я использую proxy_pass. Очень удобно настроить на одном сервере автоматическое получение всех необходимых сертификатов. Подробно я рассматривал отдельно. Сейчас будем считать, что у вас стоит certbot и все готово для нового сертификата, который потом будет автоматически обновляться.

Для этого нам надо на nginx_srv добавить еще один location — /.well-known/acme-challenge/. Полная секция server нашего тестового сайта на момент получения сертификата будет выглядеть вот так:

Перечитывайте конфиг nginx и получайте сертификат. После этого конфиг меняется на следующий:

Проверяем, что получилось.

Другие способы

Установи
правильные значения системных переменных

Размести
корневой каталог Web-сервера на выделенном разделе

Помести
nginx в chroot/jail-окружение

Любая
современная *nix-система позволяет запереть приложение в изолированной
среде исполнения. В Linux для этого можно использовать технологии KVM,
Xen, OpenVZ и VServer, во FreeBSD – Jail, в Solaris – Zones. Если ни одна
из этих технологий не доступна, ты можешь поместить nginx в классический
chroot, который хоть и намного более хрупок, но большинство взломщиков
остановить сможет.

Установи
правила SELinux для защиты nginx

Хорошей
альтернативой изолированным средам исполнения являются локальные системы
обнаружения и предотвращения вторжений, такие как SELinux или AppArmor.
Будучи правильно настроенными, они смогут предотвратить попытки взлома
Web-сервера. По дефолту ни одна из них не настроена для работы в связке с
nginx, однако в рамках проектаSELinuxNginx(http://sf.net/projects/selinuxnginx/)
были созданы правила для SELinux, которые может использовать любой
желающий. Остается только скачать и установить:

Настрой
брандмауэр

Обычно
nginx устанавливают на выделенных машинах, готовых к высокой нагрузке,
поэтому зачастую он остается единственным сетевым сервисом, работающим на
сервере. Чтобы обезопасить сервер, достаточно создать совсем небольшой
набор правил, которые будут открывать 80, 110 и 143-й порты (если,
конечно, nginx должен работать еще и как IMAP/POP3-прокси) и закрывать от
внешнего мира все остальное.

Ограничь
количество соединений с помощью брандмауэра

Для
не слишком нагруженного Web-сайта хорошей идеей будет ограничить
количество попыток соединений с одного IP-адреса в минуту. Это сможет
уберечь тебя от некоторых типов DoS-атак и брутфорса. В Linux это можно
сделать с помощью стандартного iptables/netfilter-модуля state:

Правила
урезают лимит на количество подключений с одного IP в минуту до 15. То же
можно сделать и с помощью pf:

Кроме
лимита на количество последовательных подключений (15 в минуту), данное
правило устанавливает дополнительный лимит на количество одновременных
подключений равный 100.

Настрой
PHP

Если
ты используешь nginx в связке с PHP, не забудь настроить и его. Вот как
должен выглядеть конфигурационный файл /etc/php/php.ini защищенного
сервера:

Анализ
и оптимизация времени TTFB

Как исправить 504 gateway time out Nginx?

Самый первый вариант — это если вашему серверу, php-fpm или apache не хватает ресурсов системы, например, памяти или процессора. Вы можете посмотреть свободную память с помощью команды free:

Нагрузку на процессор можно узнать командой htop:

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

Второй вариант — это если так и было запланировано, чтобы скрипт работал долго. В таком случае нужно настроить Nginx, чтобы он дождался ответа от Apache или php-fpm. Для решения проблемы в случае с php-fpm нужно только добавить две строчки в блок настройки fastgci:

Здесь 300 означает 300 секунд, для большинства скриптов, этого будет вполне достаточно, но вы можете еще больше увеличить значение если это нужно. Также ошибка 504 может возникать, когда Nginx используется в качестве прокси для Apache или любого другого веб-сервера, тогда нужно еще настроить время ожидания для прокси. Добавьте эти строки в секцию server:

Тут уже мы задаем таймаут 600 секунд для различных видов действий — подключения, отправки данных, чтения данных и так далее. После завершения настройки Nginx стоит перезапустить:

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

Более подробную информацию иногда можно увидеть в error.log:

Дальше, если проблема именно в php-fpm, вы можете отследить какие скрипты выполняются медленно с помощью встроенной функции slow-log. Для ее активации добавьте следующие строки в конфигурацию вашего пула:

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

Дальше останется только разобраться что с этим делать, например, оптимизировать скрипты или отключить лишние плагины.

Пример FastCGI на bash

Bash скрипт, который формирует ответ:

/var/www/cgi/index.sh
#!/bin/bash
NAME=`"cpuinfo"`
echo "Content-type:text/html"
echo
echo "<html><head>"
echo "<title>$NAME</title>"
echo '<meta name="description" content="'$NAME'">'
echo '<meta name="keywords" content="'$NAME'">'
echo '<meta http-equiv="Content-type" content="text/html;charset=utf-8">'
echo '<meta name="ROBOTS" content="noindex">'
echo "</head><body><pre>"
date
echo -e "\nuname -a"
uname -a
echo -e "\ncpuinfo"
cat /proc/cpuinfo
echo "</pre></body></html>"

Для CGI скриптов следует выставить атрибут выполнения (), а сам скрипт будет выполнен под пользователем, от которого работает Nginx.

Теперь по адресу http://localhost:8300/cgi/index.sh будет выполняться Bash-скрипт:

2018/09/17 16:32:09  1254#1254: *187 FastCGI sent in stderr: "Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?" while reading response header from upstream, client: 127.0.0.1, server: _, request: "GET /cgi/index.sh HTTP/1.1", upstream: "fastcgi://unix:/var/run/fcgiwrap.socket:", host: "localhost:8300"

Такая ошибка указывает на то, что забыли выставить для скрипта.

Настройка Apache для работы прокси

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

Мы будем использовать Apache с интерпретатором PHP, установленным в виде модуля php-fpm. Это обеспечит лучшую общую производительность системы. Сначала установим все нужные пакеты:

Поскольку нам нужно, чтобы Apache работал на порту 8080 нужно изменить конфигурационные файлы веб-сервера:

Замените значение строки Listen с 80 на 8080, затем сохраните изменения в файле. Далее изменим порт для веб-сайта по умолчанию:

Точно так же замените значение порта с 80 на 8080. Затем сохраните изменения и перезапустите веб-сервер:

Теперь вы можете проверить на каком порту будет ожидать соединений Apache, если все было сделано правильно, то это будет 8080:

Чтобы показать настройку прокси Nginx более наглядно, создадим один виртуальный хост (домен). Сначала создадим каталог для нашего хоста:

Затем файлы index.html и phpinfo.php:

Затем настроим файлы конфигурации виртуальных хостов для каждого из доменов:

Обратите внимание на порт, тут тоже нужно указать 8080. Для тестирования работы php нам понадобится скрипт с вызовом функции:. Осталось включить конфигурацию для только что созданного сайта и перезапустить веб-сервер:

Осталось включить конфигурацию для только что созданного сайта и перезапустить веб-сервер:

Хранение кэша в оперативной памяти

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

Создаем обычный каталог, в который будем монтировать часть оперативной памяти:

mkdir /var/ramdisk

… и дадим на него полные права: 

chmod 777 /var/ramdisk

Монтируем часть оперативной памяти как обычный каталог:

mount -t tmpfs -o size=2G ramdisk /var/ramdisk

* в данном примере мы монтируем 2  Гб оперативной памяти как папку /var/ramdisk. Возможно, правильнее будет заранее убедиться в наличие свободной памяти командой free.

Для автоматического монтирования открываем на редактирование fstab:

vi /etc/fstab

… и добавляем:

ramdisk       /var/ramdisk tmpfs   nodev,nosuid,noexec,nodiratime,size=2G   0 0

Теперь, когда у нас есть каталог, данные которого хранятся в оперативной памяти, редактируем параметр proxy_cache_path или fastcgi_cache_path в NGINX:

vi /etc/nginx/nginx.conf

proxy_cache_path /var/ramdisk levels=1:2 keys_zone=all:64m inactive=2h max_size=2g;

… или:

fastcgi_cache_path /var/ramdisk levels=1:2 keys_zone=fastcgi:64m inactive=2h max_size=2g;

Перезапускаем nginx:

systemctl restart nginx

Настройка кэширования для proxy_pass

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

Включение кэширования

Открываем конфигурационный файл nginx:

vi /etc/nginx/nginx.conf

В секцию http добавляем:

http {
    …
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=all:64m inactive=2h max_size=2g;
    …
}

* в данном примере мы задали глобальную настройку для кэширования:

  • /var/cache/nginx — путь хранения кэша.
  • levels — уровень вложенности каталогов. В данном примере мы задаем настройку, при которой в каталог с кэшем будет создан каталог, а в ней — еще один каталог.
  • keys_zone — имя зоны в разделяемой памяти, где будет храниться кэш, а также ее размер.
  • inactive — задает время, после которого кэш будет автоматически чиститься.
  • max_size — максимальный размер данных под кэш. Когда место заканчивается, nginx сам удаляет устаревшие данные.

Создаем каталог для хранения кэша и задаем владельца:

mkdir /var/cache/nginx

chown nginx:nginx /var/cache/nginx

Настройка хостов

Чтобы определенный сайт или отдельная страница кешировала запрос, открываем конфигурационный файл с настройками виртуального домена или хоста, например:

vi /etc/nginx/conf.d/default.conf

… и добавим к proxy_pass кэширование — мы получим что-то на подобие:

    location / {
        if ($http_cookie ~* «.+» ) {
            set $cookie_cache_bypass 1;
        }
        proxy_cache_bypass $cookie_cache_bypass;
        proxy_pass http://localhost:3000;
        …
        proxy_cache all;
        proxy_cache_valid 404 502 503 5m;
        proxy_cache_valid any 1h;
        proxy_cache_use_stale error timeout invalid_header updating;
    }

* где:

  • set $cookie_cache_bypass 1 — задаем значения переменной $cookie_cache_bypass, если передаются куки. Необходимо для предотвращения отдачи устаревших данных.
  • proxy_cache_bypass — не отдавать данные из кэша. В нашем случае, применяется при куках.
  • proxy_pass — передает запросы на бэкэнд.
  • proxy_cache — включаем кэширование.
  • proxy_cache_valid — задает время кеширования. В нашем примере первый параметр задает кэширование страниц с кодами ответов 404, 502, 503 на 5 минут, второй — для всего остального на 1 час.
  • proxy_cache_use_stale — указывает, в каких случаях можно отдать устаревший кэш.

Применение настроек

NGINX настроен. Проверим корректность настроек:

nginx -t

Если ошибок нет, применяем их:

systemctl restart nginx

Теперь заходим на сайт и смотрим в каталог с кэшем — в нем должны появиться каталоги и файлы:

ls /var/cache/nginx/

Мы должны увидеть что-то на подобие:

drwx——. 3 nginx nginx 4096 Jan 25 16:09 0
drwx——. 5 nginx nginx 4096 Jan 25 16:09 2
drwx——. 5 nginx nginx 4096 Jan 25 16:15 3
drwx——. 3 nginx nginx 4096 Jan 25 16:09 4
drwx——. 4 nginx nginx 4096 Jan 26 05:08 5
drwx——. 3 nginx nginx 4096 Jan 25 16:09 6
drwx——. 3 nginx nginx 4096 Jan 26 04:18 7
drwx——. 3 nginx nginx 4096 Jan 25 16:10 8
drwx——. 5 nginx nginx 4096 Jan 25 16:15 a
drwx——. 3 nginx nginx 4096 Jan 25 16:09 b
drwx——. 5 nginx nginx 4096 Jan 26 04:19 e
drwx——. 3 nginx nginx 4096 Jan 25 19:55 f

Настройка proxy_pass в nginx

Рассмотрим самый простой пример. Буду использовать свой технический домен zeroxzed.ru в этом и последующих примерах. Допустим, у нас есть сайт blog.zeroxzed.ru. В DNS создана A запись, указывающая на ip адрес сервера, где установлен nginx — nginx_srv. Мы будем проксировать все запросы с этого сервера на другой сервер в локальной сети blog_srv, где реально размещается сайт. Рисуем конфиг для секции server.

Заходим по адресу http://blog.zeroxzed.ru. Мы должны попасть на blog_srv, где тоже должен работать какой-то веб сервер. В моем случае это будет тоже nginx. У вас должно открыться содержимое, аналогичное тому, что вы увидите, набрав http://192.168.13.31 в локальной сети. Если что-то не работает, то проверьте сначала, что по адресу директивы proxy_pass у вас все корректно работает.

Посмотрим логи на обоих сервера. На nginx_srv вижу свой запрос:

Проверяем blog_srv:

Как мы видим, запрос сначала пришел на nginx_srv, был переправлен на blog_srv, куда он пришел уже с адресом отправителя 94.142.141.246. Это адрес nginx_srv. Реальный же ip адрес клиента мы видим только в самом конце лога. Это неудобно, так как директива php REMOTE_ADDR не будет возвращать настоящий ip адрес клиента. А он очень часто бывает нужен. Мы это дальше исправим, а пока создадим в корне сайта на chat_srv тестовую страничку для проверки ip адреса клиента следующего содержания:

Назовем ее myip.php. Перейдем по адресу http://blog.zeroxzed.ru/myip.php и проверим, как сервер определит наш адрес. Никак не определит :) Он покажет адрес nginx_srv. Исправляем это и учим nginx передавать реальный ip адрес клиента на сервер.

Настройка nginx¶

Установка приложений FastCGI в nginx немного отличается, потому что по
умолчанию программе не передаются параметры FastCGI.

Базовая конфигурация FastCGI nginx для flask выглядит следующим образом:

location = /yourapplication { rewrite ^ /yourapplication/ last; }
location /yourapplication { try_files $uri @yourapplication; }
location @yourapplication {
    include fastcgi_params;
    fastcgi_split_path_info ^(/yourapplication)(.*)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}

Эта конфигурация привязывает приложение к /yourapplication. Привязать
приложение к корню URL несколько проще, потому что не нужно думать о том,
какие значения использовать в PATH_INFO и SCRIPT_NAME:

Настройка Apache¶

Приведённый выше пример достаточно хорош для того, чтобы использовать его
при развёртывании с Apache, однако файл .fcgi будет встречаться в URL
приложения, например: example.com/yourapplication.fcgi/news/. Есть
несколько способов настройки приложения для того, чтобы убрать
yourapplication.fcgi из URL. Предпочтительный способ — это использование
для маршрутизации запросов серверу FastCGI директив конфигурации
ScriptAlias и SetHandler. Следующий пример использует FastCgiServer
для запуска 5 экземпляров приложения, которые будут обрабатывать все
входящие запросы:

LoadModule fastcgi_module usrlib64httpdmodulesmod_fastcgi.so

FastCgiServer varwwwhtmlyourapplicationapp.fcgi -idle-timeout 300 -processes 5

<VirtualHost *>
    ServerName webapp1.mydomain.com
    DocumentRoot varwwwhtmlyourapplication

    AddHandler fastcgi-script fcgi
    ScriptAlias  varwwwhtmlyourapplicationapp.fcgi

    <Location />
        SetHandler fastcgi-script
    </Location>
</VirtualHost>

Эти процессы будут управляться самим Apache. Если вы используете
автономный сервер FastCGI, вы можете вместо этого использовать директиву
FastCgiExternalServer. Заметим, что нижеуказанный путь не является
реальным, он используется просто как идентификатор для других директив,
таких, как as AliasMatch:

FastCgiServer varwwwhtmlyourapplication -host 127.0.0.13000

Если задать ScriptAlias нельзя, например, на веб-узле, настроенном для нескольких
пользователей, то можно воспользоваться промежуточным приложением WSGI для
удаления yourapplication.fcgi из URL. Настройте .htaccess:

<IfModule mod_fcgid.c>
   AddHandler fcgid-script .fcgi
   <Files ~ (\.fcgi)>
       SetHandler fcgid-script
       Options +FollowSymLinks +ExecCGI
   </Files>
</IfModule>

<IfModule mod_rewrite.c>
   Options +FollowSymlinks
   RewriteEngine On
   RewriteBase /
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.*)$ yourapplication.fcgi/$1 
</IfModule>

Теперь настроим yourapplication.fcgi:

Настройка lighttpd¶

Базовая настройка FastCGI для lighttpd выглядит следующим образом:

fastcgi.server = ("/yourapplication.fcgi" =>
    ((
        "socket" => "/tmp/yourapplication-fcgi.sock",
        "bin-path" => "/var/www/yourapplication/yourapplication.fcgi",
        "check-local" => "disable",
        "max-procs" => 1
    ))
)

alias.url = (
    "/static/" => "/path/to/your/static"
)

url.rewrite-once = (
    "^(/static($|/.*))$" => "$1",
    "^(/.*)$" => "/yourapplication.fcgi$1"
)

Не забудьте включить модули FastCGI, alias и rewrite. Эта настройка закрепит
приложение за /yourapplication. Если нужно, чтобы приложение работало в
корне URL, понадобится обойти недоработку lighttpd при помощи промежуточного
приложения .

Передача https через nginx с помощью proxy pass

Если у вас сайт работает по https, то достаточно настроить ssl только на nginx_srv, если вы не беспокоитесь за передачу информации от nginx_srv к blog_srv. Она может осуществляться по незащищенному протоколу. Рассмотрю пример с бесплатным сертификатом let’s encrypt. Это как раз один из кейсов, когда я использую proxy_pass. Очень удобно настроить на одном сервере автоматическое получение всех необходимых сертификатов. Подробно настройку let’s encrypt я рассматривал отдельно. Сейчас будем считать, что у вас стоит certbot и все готово для нового сертификата, который потом будет автоматически обновляться.

Для этого нам надо на nginx_srv добавить еще один location — /.well-known/acme-challenge/. Полная секция server нашего тестового сайта на момент получения сертификата будет выглядеть вот так:

Перечитывайте конфиг nginx и получайте сертификат. После этого конфиг меняется на следующий:

Проверяем, что получилось.

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

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

Сначала нужно открыть конфигурационный файл Apache в редакторе nano (или в другом редакторе на ваш выбор):

$ sudo nano /etc/apache2/sites-available/000-default.conf

Внутри этого файла найдите блок с первой строкой <VirtualHost *:80> . Первый пример ниже продемонстрирует, как изменить этот файл так, чтобы использовать обратный прокси для одного бэкенд-сервера, а второй пример – для установки балансировки нагрузки для нескольких бэкенд-серверов.

1 пример: обратное прокси для одного бэкенд-сервера

Скопируйте текст ниже вместо всего текста, расположенного в блоке VirtualHost, то есть чтобы в итоге блок выглядел вот так:

<VirtualHost *:80>
 ProxyPreserveHost On

 ProxyPass / http://127.0.0.1:8080/
 ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>

Если вы продолжаете следовать этому руководству и используете тестовые серверы, которые создали ранее, то скопируйте 127.0.0.1:8080, как и написано в примере. Если у вас есть свои собственные серверы приложений, то используйте их адреса.

В блоке используется три директивы:

  • ProxyPreserveHost – заставляет Apache передать оригинальный заголовок Host бэкенд-серверу. Это полезно, так как в этом случае бэкенд-сервер получает адрес, который используется для доступа к приложению;
  • ProxyPass – основная директива для настройки прокси. В данном случае она указывает, что все, что идет после корневого адреса URL (/), должно быть отправлено на бэкенд-сервер по указанному адресу. Например, если Apache получит запрос /primer, то он подключится к http://ваш_бэкенд-сервер/primer и отправит соответствующий ответ;
  • ProxyPassReverse – должна иметь такие же настройки, как и ProxyPass. Она сообщает Apache, как изменить заголовки в ответе от бэкенд-сервера. Таким образом гарантируется, что браузер клиента будет перенаправлен на прокси-адрес, а не на адрес бэкенд-сервера.

После внесения изменений Apache необходимо перезапустить:

$ sudo systemctl restart apache2

Теперь, если вы наберете в браузере адрес своего сервера, вы увидите ответ от вашего бэкенд-сервера вместо приветственной страницы Apache.

2 пример: балансировка нагрузки между несколькими бэкенд-серверами

Если у вас есть несколько бэкенд-серверов, будет хорошей идеей при использовании прокси распределить трафик между ними; сделать это можно при помощи функции балансировки нагрузки утилиты mod_proxy.

Как и в первом примере, тут вам тоже необходимо заменить текст в блоке VirtualHost на следующий:

<VirtualHost *:80>
<Proxy balancer://mycluster>
 BalancerMember http://127.0.0.1:8080
 BalancerMember http://127.0.0.1:8081
</Proxy>

 ProxyPreserveHost On

 ProxyPass / balancer://mycluster/
 ProxyPassReverse / balancer://mycluster/
</VirtualHost>

В целом текст похож на предыдущий, однако вместо указания одного бэкенд-сервера появляется новый блок Proxy, в котором указано несколько серверов. Блок называется balancer://mycluster (название можно изменить) и состоит из одного или нескольких BalancerMembers, которые определяют адреса лежащих в основе бэкенд-серверов.

Директивы ProxyPass и ProxyPassReverse используют пул балансировки нагрузки под названием mycluster вместо конкретного сервера.

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

Для того, чтобы изменения вступили в силу, перезапустите Apache:

$ sudo systemctl restart apache2

Теперь проведите такой же тест, как и в первом примере: введите IP-адрес вашего сервера в браузер и вместо стандартного приветствия Apache вы увидите один из ответов бэкенд-серверов. Если вы используете тестовые серверы, то это будет либо “Hello world!”, либо “Hello Timeweb!”. Обновите страницу несколько раз и, если вы увидели оба текста, значит все работает корректно.

Настройка proxy_pass в nginx

Рассмотрим самый простой пример. Буду использовать свой технический домен zeroxzed.ru в этом и последующих примерах. Допустим, у нас есть сайт blog.zeroxzed.ru. В DNS создана A запись, указывающая на ip адрес сервера, где установлен nginx — nginx_srv. Мы будем проксировать все запросы с этого сервера на другой сервер в локальной сети blog_srv, где реально размещается сайт. Рисуем конфиг для секции server.

server {
    listen 80;
    server_name blog.zeroxzed.ru;
    access_log /var/log/nginx/blog.zeroxzed.ru-access.log;
    error_log /var/log/nginx/blog.zeroxzed.ru-error.log;

location / {
    proxy_pass http://192.168.13.31;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
}

Заходим по адресу http://blog.zeroxzed.ru. Мы должны попасть на blog_srv, где тоже должен работать какой-то веб сервер. В моем случае это будет тоже nginx. У вас должно открыться содержимое, аналогичное тому, что вы увидите, набрав http://192.168.13.31 в локальной сети. Если что-то не работает, то проверьте сначала, что по адресу директивы proxy_pass у вас все корректно работает.

Посмотрим логи на обоих сервера. На nginx_srv вижу свой запрос:

77.37.224.139 - - [19/Jan/2018:15:15:40 +0300] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

Проверяем blog_srv:

94.142.141.246 - - [19/Jan/2018:15:15:40 +0300] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" "77.37.224.139"

Как мы видим, запрос сначала пришел на nginx_srv, был переправлен на blog_srv, куда он пришел уже с адресом отправителя 94.142.141.246. Это адрес nginx_srv. Реальный же ip адрес клиента мы видим только в самом конце лога. Это неудобно, так как директива php REMOTE_ADDR не будет возвращать настоящий ip адрес клиента. А он очень часто бывает нужен. Мы это дальше исправим, а пока создадим в корне сайта на chat_srv тестовую страничку для проверки ip адреса клиента следующего содержания:

<?php
echo $_SERVER
?>

Назовем ее myip.php. Перейдем по адресу http://blog.zeroxzed.ru/myip.php и проверим, как сервер определит наш адрес. Никак не определит  Он покажет адрес nginx_srv. Исправляем это и учим nginx передавать реальный ip адрес клиента на сервер.

Настройка прокси Nginx

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

Сначала установите Nginx, если вы этого еще не сделали:

Дальше создадим виртуальный хост Nginx с несколькими доменами, с помощью которого и будет выполняться проксирование Nginx:

Для использования nginx в качестве прокси мы передаем в команде proxy_pass адрес и порт веб-сервера, а в заголовках передаем те значения, которые будут нужны Apache для правильного формирования документа. Сохраните файл и активируйте его:

Затем проверьте конфигурацию и перезапустите Nginx:

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

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

Заключение

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

Пожалуйста, опубликуйте ваши мнения по текущей теме материала. За комментарии, дизлайки, отклики, подписки, лайки низкий вам поклон!

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

Наталья Кайдаавтор-переводчик статьи «Server-side Optimization with Nginx and pm-static»

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: