apache+nginx+gzip_static+yuicompressor

В этой статье я опишу принципиальные различия Apache и Nginx, архитектуру фронтэнд-бэкэнд, установку Apache в качестве бэкэнда и Nginx в качестве фронтэнда. А также опишу технологию, позволяющую ускорить работу веб-сервера: gzip_static+yuicompressor.

Nginx


Nginx – сервер легкий; он запускает указанное число процессов (обычно число процессов = числу ядер), и каждый процесс в цикле принимает новые соединения, обрабатывает текущие. Такая модель позволяет с низкими затратами ресурсов обслуживать большое количество клиентов. Однако, при такой модели, нельзя выполнять длительные операции при обработке запроса (например mod_php), т.к. это по сути повесит сервер. При каждом цикле внутри процесса по сути выполняются две операции: считать блок данных откуда-то, записать куда-то. Откуда-то и куда-то – это соединение с клиентом, соединение с другим веб-сервером или FastCGI-процессом, файловая система, буфер в памяти. Модель работы настраивается двумя основными параметрами:
  • worker_processes – число запускаемых процессов. Обычно устанавливают равным числу ядер процессора.
  • worker_connections – максимальное число соединений, обрабатываемых одним процессом. Напрямую зависит от максимального числа открытых файловых дескрипторов в системе (1024 по умолчанию в Linux).

Apache


Apache – сервер тяжелый (следует заметить, что при желании его можно достаточно облегчить, однако это не изменит его архитектуры); он имеет две основных модели работы – prefork и worker.
При использовании модели prefork Apache создает новый процесс для обработки каждого запроса, и этот процесс выполняет всю работу: принимает запрос, генерирует контент, отдает пользователю. Настраивается эта модель следующими параметрами:
  • StartServers – задает число запускаемых процессов при старте веб-сервера.
  • MinSpareServers – минимальное число висящих без дела процессов. Нужно это для того, чтобы при поступлении запроса быстрее начать его обрабатывать. Веб-сервер будет запускать дополнительные процессы, чтобы их было указанное количество.
  • MaxSpareServers – максимальное число висящих без дела процессов. Это нужно, чтобы не занимать лишнюю память. Веб-сервер будет убивать лишние процессы.
  • MaxClients – максимальное число параллельно обслуживаемых клиентов. Веб-сервер не запустит более указанного количества процессов.
  • MaxRequestsPerChild – максимальное число запросов, которые обработает процесс, после чего веб-сервер убьет его. Опять же, для экономии памяти, т.к. память в процессах будет постепенно «утекать».

Эта модель была единственной, которую поддерживал Apache 1.3. Она стабильная, не требует от системы многопоточности, но потребляет много ресурсов и немного проигрывает по скорости модели worker.
При использовании модели worker Apache создает несколько процессов, по несколько потоков в каждом. При этом каждый запрос полностью обрабатывается в отдельном потоке. Чуть менее стабильна, чем prefork, т.к. крах потока может привести к краху всего процесса, но работает немного быстрее, потребляя меньше ресурсов. Настраивается эта модель следующими параметрами:
  • StartServers – задает число запускаемых процессов при старте веб-сервера.
  • MinSpareThreads – минимальное число потоков, висящих без дела, в каждом процессе.
  • MaxSpareThreads – максимальное число потоков, висящих без дела, в каждом процессе.
  • ThreadsPerChild – задает число потоков, запускаемых каждым процессом при старте процесса.
  • MaxClients – максимальное число параллельно обслуживаемых клиентов. В данном случае задает общее число потоков во всех процессах.
  • MaxRequestsPerChild – максимальное число запросов, которые обработает процесс, после чего веб-сервер убьет его.

Фронтэнд-бэкэнд


Основная проблема Apache – на каждый запрос выделен отдельный процесс (как минимум – поток), который к тому же увешан различными модулями и потребляет немало ресурсов. Вдобавок, этот процесс будет висеть в памяти до тех пор, пока не отдаст весь контент клиенту. Если у клиента узкий канал, а контент достаточно объемный, то это может занять длительное время. Например, сервер сгенерирует контент за 0,1 сек, а отдавать клиенту его будет 10 сек, все это время занимая системные ресурсы.
Для решения этой проблемы используется архитектура фронтэнд-бэкэнд. Суть ее в том, что запрос клиента приходит на легкий сервер, с архитектурой типа Nginx (фронтэнд), который перенаправляет (проксирует) запрос на тяжелый сервер (бэкэнд). Бэкэнд формирует контент, очень быстро его отдает фронтэнду и освобождает системные ресурсы. Фронтэнд кладет результат работы бэкэнда в свой буфер и может долго и упорно отдавать его (результат) клиенту, потребляя при этом намного меньше ресурсов, чем бэкэнд. Дополнительно фронтэнд может самостоятельно обрабатывать запросы статических файлов (css, js, картинки и т.д.), управлять доступом, проверять авторизацию и т.д.

Настройка связки Nginx (фронтэнд) + Apache (бэкэнд)


Предполагается, что Nginx и Apache у вас уже установлены. Необходимо настроить сервера так, чтобы они слушали разные порты. При этом, если оба сервера установлены на одной машине, бэкэнд лучше вешать только на loopback-интерфейс (127.0.0.1). В Nginx это настраивается директивой listen:
listen 80;

В Apache это настраивается директивой Listen:
Listen 127.0.0.1:81

Далее нужно указать Nginx проксировать запросы на бэкэнд. Это делается директивой proxy_pass   127.0.0.1:81;. Это вся минимальная конфигурация. Однако выше мы говорили, что отдачу статических файлов лучше тоже поручить Nginx. Допустим, что у нас типичный сайт на PHP. Тогда нам нужно проксировать на Apache только запросы к .php файлам, обрабатывая все остальное на Nginx (если ваш сайт использует mod_rewrite, то реврайты тоже можно делать на Nginx, а .htaccess файлы просто выкинуть). Также необходимо учесть, что запрос клиента приходит на Nginx, а запрос к Apache делает уже Nginx, поэтому HTTP-заголовка Host не будет, а адрес клиента (REMOTE_ADDR) Apache определит как 127.0.0.1. Заголовок Host подставить несложно, а вот REMOTE_ADDR Apache определяет сам. Решается эта проблема при помощи mod_rpaf для Apache. Работает он следующим образом: Nginx знает IP клиента и добавляет некий HTTP-заголовок (например X-Real-IP), в который прописывает этот IP. mod_rpaf получает этот заголовок и прописывает его содержимое в переменную REMOTE_ADDR Apache. Таким образом, php-скрипты, выполняемые Apache будут видеть реальный IP клиента.
Теперь конфигурация усложнится. Сначала позаботьтесь, чтобы и в Nginx, и в Apache существовал один и тот же виртуальный хост, с одинаковым корнем. Пример для Nginx:
server {
	listen	80;
	server_name	example.com;
	root	/var/www/example.com/;
}

Пример для Apache:
<VirtualHost 127.0.0.1:81>
	DocumentRoot "/var/www/example.com/"
	ServerName example.com
</VirtualHost>

Теперь задаем настройки для вышеописанной схемы:
Nginx:
server {
	listen  80;
	server_name  example.com;
	location / {
		root  /var/www/example.com/;
		index  index.php;
	}
	location ~ \.php($|\/) {
		proxy_pass  http://127.0.0.1:81;
		proxy_set_header  X-Real-IP  $remote_addr;
		proxy_set_header  Host  $host;
	}
}

Apache:
# настройки mod_rpaf
RPAFenable On
RPAFproxy_ips 127.0.0.1
RPAFheader X-Real-IP

<VirtualHost 127.0.0.1:81>
	DocumentRoot "/var/www/example.com/"
	ServerName example.com
</VirtualHost>

Регулярное выражение \.php($|\/) описывает две ситуации: запрос к *.php и запрос к *.php/foo/bar. Второй вариант необходим для работы многих CMS. При запросе example.com/ запрос будет переписан в example.com/index.php (т.к. мы определили index-файл) и также будет проксирован на Apache.

Ускоряемся: gzip_static+yuicompressor


Gzip в Web это хорошо. Текстовые файлы отлично сжимаются, трафик экономится, и контент быстрее доставляется пользователю. Nginx умеет сжимать на лету, так что тут проблем нет. Однако на сжатие файла тратится определенное время, в том числе процессорное. И тут на помощь приходит директива Nginx gzip_static. Суть ее работы в следующем: если при запросе файла Nginx находит файл с таким же именем и дополнительным расширением ".gz", например, style.css и style.css.gz, то вместо того, чтобы сжимать style.css, Nginx прочитает с диска уже сжатый style.css.gz и отдаст его под видом сжатого style.css.
Настройки Nginx будут выглядеть так:
http {
	...
	gzip_static      on;
	gzip             on;
	gzip_comp_level  9;
	gzip_types       application/x-javascript text/css;
	...

Прекрасно, мы один раз будем генерировать .gz файл, чтобы Nginx много раз его отдал. А дополнительно мы будем сжимать css и js при помощи YUI Compressor. Эта утилита максимально минимизирует css и js файлы, удаляя пробелы, сокращая наименования и т.д.
А заставить все это сжиматься автоматически, да еще и обновляться автоматически можно при помощи cron и небольшого скрипта. Пропишите в cron для запуска раз в сутки следующую команду:
/usr/bin/find /var/www -mmin 1500 -iname "*.js" -or -iname "*.css" | xargs -i -n 1 -P 2 packfile.sh

в параметре -P 2 укажите число ядер вашего процессора, не забудьте прописать полный путь к packfile.sh и изменить /var/www на ваш веб-каталог.
В файл packfile.sh пропишите:
java -jar /var/www/gzip/yuicompressor-2.4.2.jar "$1" | gzip -c -9 > "$1.gz"

не забудьте указать правильный путь к yuicompressor-2.4.2.jar.

Это все, готов выслушать критику :)

Комментарии 71

    0
    Схема стандартная, но верная. Еще бы добавить склейку js / css файлов в один js / css с трансляцией относительных путей на пути от корня и обновление сжатого файла автоматом, при обновлении несжатого.
      +10
      Да, и gzip_comp_level лучше 5-6 ставить. 9 — перебор.
        0
        Я бы добавил так: gzip_comp_level выставить на 9, прогнать любым скриптом для создания нагрузки задачу со списком статики и выставить на 5-6. В итоге получим максимальное сжатие статики и приемлимую нагрузку во время сжатия динамики.
          +4
          Тут дело в том, что сжатые на 9 данные и разжимаются (браузером) медленнее… А разница между 0 и 5 гораздо больше чем между 5 и 9.
          Вот гляньте: habrahabr.ru/blogs/client_side_optimization/24325/
      –1
      Спасибо! Очень познавательно.
        +1
        Из выше-указанного непонятно почему нельзя использовать nginx для обработки php и отказаться от Apache, что освободит еще немного памяти, да и системных коннектов будет жрать в 2 раза меньше. Обычно установка nginx предполагает высокую нагрузку, если же mod_php отрабатывает долго то никакой nginx и lighttpd не поможет.

        Автор пробовал lighttpd, при грамотной настройке он вел себя стабильнее чем nginx при обработке статики и динамики, по крайней мере ветка 1.4, и в нем также имеется сжатие статики.
          +2
          Лишь предположу.
          Дело в архитектуре nginx. Скажем nginx настроен на 8 воркеров. Это значит, что одновременно может исполняться только 8 скриптов. Остальны ждут своей очереди. При большом кол-во запросов и медленных скриптах, это очередь может быть очень длинной, и пользователь будет видеть лишь белую страницу.
          Apache, наоборот, обрабатывает все скрпиты параллельно, лишь бы ресурсов хватило.
            +1
            spanw-fcgi проблему решает чуть больше чем полностью. По крайней мере на lighttpd никаких проблем при 30-40 параллельных запросов на скрипты не было, всё работало быстро.
              +1
              Ну так и nginx можно настроить так, чтобы он работал в связке со spawn-fcgi. В интернете полно мануалов.
                –1
                я это и имел в виду ;-)
                +1
                Не сказал бы что это проще настраивать, чем поднять apache с php. И с Apache'м приходит много разных плюшек, по типу rewrite в .htaccess.
                  0
                  Во-первых, настроить не так и сложно, есть куча мануалов.
                  Во-вторых, реврайт настроить не проблема — есть и mod_rewrite (который настроить не тяжелее, чем аналог из Apache) и mod_magnet для более тяжелых случаев. Более того автор пишет
                  если ваш сайт использует mod_rewrite, то реврайты тоже можно делать на Nginx, а .htaccess файлы просто выкинуть

                  В-третьих, есть достаточно много плюшек и для lighttpd.
              0
              использовать nginx для обработки php и отказаться от Apache

              Обрабатывать PHP прям внутри Nginx? Так он же асинхронный однопоточный…

              Или вы все же про php-fpm/fcgi?
                0
                про spawn-cgi
                0
                Прежние ветки лайти текли дай бог. Поэтому все давно на него забили и перешли на nginx.
                Кроме того, какое-то время проект просто не развивался вообще, в том время как nginx почти еженедельно выпускал обновления.

                > Автор пробовал lighttpd, при грамотной настройке он вел себя стабильнее чем nginx при обработке статики и динамики

                Что значит «стабильнее», и какие ваши доказательства? :)
                  0
                  Стабильнее значит, что на продакшене у него было более быстрое время ответа и он не «залипал» периодически, как это часто было с Apache и реже с nginx. Например, на статическом сервере, который отдавал «потоковое» видео (mp4 и flv) и скрины к нему, nginx через некоторое время начинал отдавать даже мелкие картинки (4-5кб) по 5-10, на лайти такого замечено не было.
                    +1
                    Как говорится, «до вас никто не жаловался».
                0
                А есть аналогичная сжималка, но не на яве? Уж очень не хочется ее ставить на сервер.
                  0
                  Вы всегда можете заливать на сервер уже сжатые скрипты, задачи для сжатия css и js существуют для многих систем сборки, вот для Ant например. Еще есть вариант использовать расширение для Апача от Google — кроме возможностей по сжатию CSS и JS еще много функционала для ускорения сайта.
                    +1
                    Спасибо.
                    У меня на одном сервере все формируется, а потом распределяется по нескольким, но на даже на первый сервер не хочу яву :)
                    0
                    Есть много разных сжималок на php, с помощью которых можно в рантайме/по крону сжимать/объединять, вот например или более массивный Minify.
                      0
                      Спасибо, посмотрю.
                    +4
                    При правильно настроенной конфигурации Nginx+Apache, когда статика отдается фронтом, рекомендую обязательно установить в Apache относительно небольшим MaxClients.

                    Нужно выбрать число таким, чтобы система не свопировала и оставалась память для MySQL и системы. Обычно достаточно 10-25. Увеличить таймаут на NGINX, чтобы он удерживал запросы и защищал бекэнд от перегрузки.
                      0
                      google closure compiler сжимает js лучше чем yuicompressor, особенно в advanced mode =)
                      • НЛО прилетело и опубликовало эту надпись здесь
                          0
                          Хранить текст в Javascript'ах не комильфо, а длинные Unicode-последовательности кагбэ намекают на это ;-)
                          • НЛО прилетело и опубликовало эту надпись здесь
                              +2
                              Например, хранить отдельные файлы для языка/модуля с расширением .json

                              В плюсах:
                              — мультиязычность, с возможностью динамической смены языка
                              — основной скрипт одноразово сжимается с помощью GCC|gzip
                              — можно легко генерировать из php, а потом кешировать тем же nginx'ом

                              Минусы исходят из плюсов:
                              — отдельный файл, а значит требуется дополнительное время на его загрузку, хотя этим можно пренебречь
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • НЛО прилетело и опубликовало эту надпись здесь
                                    0
                                    Сжимать .json с помощью GCC бессмысленно, ведь там будут в основном тексты, по-этому каждый русский символ будет 2 байтным, если кодировка UTF-8.
                                      0
                                      эти 6 символов как правило одни и те же по всему файлу, поэтому со свистом сжимаются гзипом в дофига и больше раз.
                          +1
                          Не забываем выключать keep-alive в apache.
                            +1
                            А нет ли решения, которое позволяло бы сжимать css/js на лету, кэшировать результат, и в следующий раз, если файл не изменился, отдавать из кэша?
                            • НЛО прилетело и опубликовало эту надпись здесь
                                0
                                Спасибо. Неверно сформулировал вопрос — я имел в виду не compress, а minify.

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

                                  0
                                  Есть решения для различных фреймворков.
                                    0
                                    Оригинальные файлы остаются без изменений, а минифицированные файлы лежат в .gz.
                                    К тому же, nginx проверяет время модификации файла. Если оригинальный файл свежее, чем .gz, то отдаваться будет оригинальный файл.
                                  0
                                  Можно сделать rewrite добавляя .gz в конце, а на 404 = 200 и скрипт, который делает gz и отдает его же.
                                    +1
                                    Проблема будет в том, что при реврайте на .gz файл, заголовок Content-Type будет соответствовать .gz файлу. В принципе можно сделать что-то вроде:
                                    types { }
                                    default_type application/javascript;

                                    Но это делается в контексте location, поэтому придется писать location на каждый тип файла.
                                      0
                                      да будет дефолтовый
                                      типы можно пропистаь и в контексте html. sample инклюдит mime.types именно там.
                                      не знаю может и js.gz воспримется нормально, типа
                                      application/x-javascript js js.gz;
                                        +1
                                        Да, mime.types инклудится в контексте http (поправка). В контексте location это делается для того, чтобы переопределить типы:
                                        location ~ \.js$ {
                                           types { }
                                           default_type application/javascript;
                                        }

                                        Прописывание application/x-javascript js js.gz; не помогает, только что проверил.
                                          0
                                          Да, тогда и в правду не стоит выпендриваться :)
                                          и делать минификацию и сжатие по крону в gz, собирая nginx с модулем gzip_static
                                    +1
                                    При разработке на ruby on rails я всегда пользуюсь jammit и не трачу время на сжатие и склеивание стилей и скриптов, расширение все делает за меня. При этом, если в системе доступна java, оно втоматически прогонит файлы через closure/yui compiler'ы.
                                    0
                                    С версией JRT 6 Update 22 (build 1.6.0_22-b04) yuicompressor-2.4.2 не дружит по ходу. Вчера заметил.
                                      0
                                      # java -version
                                      java version «1.6.0_22»
                                      Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
                                      Java HotSpot(TM) 64-Bit Server VM (build 17.1-b03, mixed mode)

                                      Вот с этим работает.
                                      +6
                                      мои 2 копейки:

                                      1. ошибки лучше на продакшене закрывать статикой
                                      error_page  404 500 501 502 503 504 /error.html;
                                      
                                      location = /error.html {
                                              internal;
                                      }
                                      


                                      2. Для CMS с ЧПУ надо делать наоборот все в дефолтовом location а статитку по регулярке, ну и заглушка на техработы
                                      try_files 	/maintenance.html @apache;
                                      location @apache {
                                      	proxy_intercept_errors 	on;
                                      	# тут еще вставляем управление кэшем
                                      	proxy_pass	http://127.0.0.1:8080;
                                      }
                                      location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|xml|swf)(\?.*)?$  {
                                      	expires max;
                                      }                                                         
                                      


                                      3. заглушка для нежелательных файлов
                                      location ~ /\.ht {
                                          deny  all;
                                      }
                                      
                                        0
                                        пардон, спрошу нубские вопросы:
                                        1. internal — означает, что nginx в случае ошибки при запросе к несуществующему example.com/aybabtu перенаправляет /error.html в корень example.com (т.е. example.com/error.html)?
                                        2. обработка ошибок из первого случая не работает без proxy_intercept_errors из второго?
                                          +1
                                          1. internal означает что запрос /error.html получит 404
                                          2. верно, я его поэтому и оставил
                                            0
                                            подождите, но получается, что error_page 404 /error.html? но при запросе к /error.html получаем 404, значит, получаем /error.html?
                                              +1
                                              получается что запрос к /error.html ничем не отличается от запроса к любому несуществующему урлу
                                              Да содержимое будет из этого файла
                                          0
                                          1. internal означает что запрос /error.html получит 404
                                          2. верно, я его поэтому и оставил
                                          0
                                          try_files /maintenance.html @apache;

                                          Поисковики не одобряют см habrahabr.ru/blogs/webdev/103406/#comment_3217649
                                            0
                                            Черт, забыл
                                            тогда пусть будет так:
                                                    error_page  404 500 501 502 504 /error.html;
                                            
                                                    location = /error.html {
                                                            internal;
                                                    }
                                            
                                                    error_page 503 /maintenance.html;
                                            
                                                    location /maintenance.html {
                                                    	#pass
                                                    }
                                            
                                                    location / {
                                            
                                                            if (-f $document_root/maintenance.html) {
                                                                    return 503;
                                                            }
                                            
                                                            # далее по примерам
                                            
                                          +1
                                          mod_rpaf работает некорректно. В частности перестают работать директивы allow from, deny from в .htaccess из-за того что не происходит подмены ip из X-Real-IP. Я использую mod_realip2, который полностью решил эту проблему.
                                            +1
                                            может стоит все правила по ip вынести в nginx?
                                              0
                                              Пока не нашел mod_realip2 так и делал. Но через .htaccess это делать удобнее. К тому же есть люди кроме меня, которым надо менять правила. Они имеют доступ к .htaccess, но не имеют доступа к настройкам хоста в nginx.
                                            0
                                            вообщем-то для полного офигения не хватает убрать отсюда апач, прикрутить оптимизацию картинок через www.smushit.com или через набор оптимизаторов
                                              0
                                              не максимально, есть CSS Tidy | Google Compiler
                                                0
                                                gzip_static по умолчанию в nginx отключен, и обычно надо пересобирать nginx чтобы ее использовать
                                                  0
                                                  Есть такое дело. Параметр --with-http_gzip_static_module для ./configure. В Gentoo Linux USE-флаг static-gzip.
                                                  0
                                                  Не понял принципиального отличия между моделью работы nginx и prefork Apache…
                                                  На 2-х ядерном процессое у nginx'а 2 потока, так же можно сконфигурировать Апач:
                                                  StartServers = 2
                                                  MinSpareServers = 2
                                                  MaxSpareServers = 2
                                                  MaxRequestsPerChild = 10000000…
                                                  запрос передавать на fastcgi — и получится тот же nginx?
                                                    0
                                                    Дело в том, что поток Apache занимается лишь одним клиентом — такая архитектура. Поток же nginx в цикле пробегает по коннектам и уделяет каждому понемногу времени. Объясняю своими словами, надеюсь корректно описал суть :)
                                                      0
                                                      а апач как это делает?
                                                      я так понял, что это работает приерно так: процесс получил, запрос, передал его fastCGI, получил следующий, передал, получил результат от fastCGI, передал его сокету, полуил запрос на статику, считал, передал сокету… и т.д. В чём тогда разница между nginx и prefork Apache?
                                                        0
                                                        Один поток Apache делает вот что: получает запрос от клиента, обрабатывает запрос, выдает результат клиенту. Один поток занимается одним клиентом и больше ничем. Т.е. с параметрами, которые Вы привели выше, Apache не сможет обработать более двух клиентов параллельно.
                                                        А один поток nginx работает иначе: в бесконечном цикле он пробегается по массиву сокетов, при необходимости считывает/записывает небольшой блок данных из/в сокет(а). Т.е. за каждый цикл он обслуживает сразу кучу клиентов (не более значения опции worker_connections). Это принцип работы poll. epoll работает еще эффективнее, но суть примерно такая же.
                                                    0
                                                    Использование NGINX перед апачем имеет одну проблему. которую нужно иметь ввиду.
                                                    Иногда некоторые криворукие программисты делают из флэшек запросы на получение других флэшек методом GET.
                                                    Apache такие запросы обрабатывает нормально. а вот nginx их не разрешает.
                                                    Т.е. если вы берёте абстрактнгый веб проект и хотите его ускорить, то без переписывания кусков флэша — может не обойтись.
                                                    + Не забывайте что использование front'end'a автоматически лишит вас информации об IP пользователя. и вам придется обязательно в настройках NGINX позаботится о правильной конверсии header'ов
                                                      0
                                                      ошибка в посте… не GET a POST
                                                      следует читать
                                                      >>Иногда некоторые криворукие программисты делают из флэшек запросы на получение других флэшек методом POST.
                                                        0
                                                        почему в пресловутом абстрактном веб-проэкте вообще не отказаться от использования апача?

                                                        nginx прекрасно справляется и с отдачей статики, и с обработкой динамики на фастцги сервере. для чего нужен то апач?
                                                        0
                                                        насчет. mod_rpaf и remote ADDR. есть и другой какой-то способ
                                                          0
                                                          # Включаем модуль
                                                          RPAFenable On
                                                          # Доводит до ума X-Host
                                                          RPAFsethostname On
                                                          # Адрес фронтенда (nginx)
                                                          RPAFproxy_ips ТУТ.ВАШ.IP.АДР 127.0.0.1
                                                          # Имя отправляемого заголовка
                                                          RPAFheader X-Forwarded-For

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

                                                        Самое читаемое