Веб сервер Apache на сегодня считается достаточно медленным и для оптимизации работы сервера и ускорения работы сайта рекомендуется от него полностью отказываться, но бывают ситуации когда без него не обойтись. В таком случае наиболее частым приемом становится установка веб сервера Nginx в качестве прокси сервера для Apache. Таким образом принимать запросы от пользователям у нас уже будет быстрый сервер Nginx и дальше уже решать: отправить запрос Apache или выдать клиенту все данные самому, если у него есть такая возможность, например данные на нем закэшированы.
Основные варианты использования:
Защита от DDOS: Nginx будет пропускать только реальные http запросы на медленный Apache, а остальные или отдавать из кэша или блокировать. При определенном варианте, при таком режиме можно даже защищаться от DDOS атак.
GZIP сжатие: Nginx может осуществлять GZIP сжатие данных перед отправкой клиенту и таким образом уменьшить скорость загрузки и нагрузку на сеть.
Балансировка: Nginx может выступать в качестве балансировщика нагрузки и распределять запросы по нескольким физическим серверам.
Пропустим процедуру установки и попробуем разобраться как же настроить оба сервера для их работы в паре. Рассмотрим простейший вариант когда Apache будет обрабатывать скрипты, а nginx просто транслировать их клиенту. По такому принципу у меня работает task менеджер redmine. Apache занимается только обработкой запросов от mod_passanger, а все остальные сайты на сервере напрямую отдает nginx.
Настройки Apache
Тут от настроек не так много, главное установить нужный порт и настроить видимость сервера только внутри себя. Порт 80 мы использовать больше не можем, так как им будет пользоваться nginx поэтому возьмем порт 81.
Редактируем файл /etc/httpd/httpd.conf
#ставим внутренний адрес и меняем порт на 81 Listen 127.0.0.1:81 #KeepAlive запросы позволяют устанавливать постоянные соединения между клиентом и сервером. Это экономит ресурсы на отсутствии повторной установки соединений. KeepAlive Off
Для небольшой оптимизации так же отключим функцию отложенного закрытия соединения так как в нашем варианте настройки она только замедлит работу.
Создаем виртуальный хост для нашего сайта с минимальными настройками. Это может быть общий файл httpd-vhosts.conf или на каждый сайт свой файл.
# Указываем выбранный порт: <VirtualHost 127.0.0.1:81> ServerName site.ru ServerAlias www.site.ru DocumentRoot /home/www/html/site CustomLog /var/log/httpd/site.ru_access.log combined ErrorLog /var/log/httpd/site.ru_error.log <Directory "/home/www/htmlsite"> AllowOverride none </Directory> </VirtualHost>
Директива AllowOverride включает использование файла .htaccess. В этом случае при каждом запросе Apache будет обращаться к директории сайта для его поиска. Лучше переместить все настройки в конфигурационный файл немного ускорив обработку.
Настройка Nginx
Настроим основной конфигурационный файл /etc/nginx/nginx.conf
user nginx; worker_processes auto; #можно указать количество ядер процессора worker_rlimit_nofile 8192; worker_priority -1; #чтобы не вешало сервер при большой нагрузке # Общий лог для ошибок error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 8096; # Максимальное количество рабочих соединений use epoll; # Метод обработки соединений. for Linux 2.6+ } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; #Связка из 3х параметров для ускорения отдачи ответов с сервера sendfile on; tcp_nopush on; tcp_nodelay on; #Keepalive соединения позволяют избежать необходимости повторного создания соединения между клиентом и сервером # Будет ждать 30 секунд перед закрытием keepalive соединения keepalive_timeout 30; types_hash_max_size 2048; # Максимальное количество keepalive запросов от одного клиента keepalive_requests 50; #Много проблем могут создать медленные (тупящие) клиенты. Медленная передача тела запроса от клиента к серверу и неожиданное закрытие клиентом соединений могут создать большое количество лишних соединений на сервере. reset_timedout_connection on; # Если клиент перестал читать отвечать, Nginx будет сбрасывать соединение с ним client_body_timeout 10; # Будет ждать 10 секунд тело запроса от клиента, после чего сбросит соединение send_timeout 10; # Если клиент прекратит чтение ответа, Nginx подождет 2 секунды и сбросит соединение #Ограничивайте отправку больших запросов на сервер (например, загрузку больших файлов), если это не предусмотрено сайтом client_max_body_size 10m; # Не отдавать версию nginx в заголовке ответа server_tokens off; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; }
Вот тут уже KeepAlive запросы необходимо включить.
Если мы хотим использовать кэширование, то в этот файл необходимо добавить ещё его настройку:
# Cache ## Создаем кеш зону sitecache (память под ключи в 50Мб) с настройками: # inactive: xранить кеш 10 минут # max_size: максимальный размер кеш данные 200Мб proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=sitecache:50m inactive=10m max_size=200m; proxy_temp_path /var/cache/nginx/temp; # Ключ по которому сохраняются и берутся данные из кеша proxy_cache_key "$request_method|$is_args|$host|$request_uri"; #proxy_cache_key "$scheme$proxy_host$uri$is_args$args"; # Защита от раздачи одинаковой куки в кешированном ответе proxy_hide_header "Set-Cookie"; # Игнорировать параметры кеша заданные бекэндом proxy_ignore_headers "Cache-Control" "Expires"; # Указывает в каких случаях клиенту можно отдать несвежий ответ из кеша proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_503 http_504 http_403; proxy_cache_valid any 1d;
Если хотим ограничить количество запросов с одного хоста за определенный промежуток времени, то необходимо задать следующую настройку:
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/m;
Обычно эту настройку применяют для отработки DDOS атак. Тут мы выделяем 10Мб в памяти для обработки зоны one и настраиваем её на ограничение в 10 запросов в минуту. Все, что больше будет отвергнуто сервером с ответом 503(или заданным настройками). Для разных сайтов лучше создавать разные зоны.
Далее настроим зону самого сайта
Для этого создадим файл /etc/nginx/conf.d/site.ru.conf
server { listen 80; server_name site.ru www.site.ru; # Ведём журнал доступа: access_log /var/log/nginx/site.ru_access.log; #access_log off; error_log /var/log/nginx/site.ru_error.log; # Разделяем статику и динамку, статику храним в кэше 7 дней: location ~* \.(jpg|jpeg|gif|png|ico|css|bmp|swf|js|doc|docx|pdf|xls|xlsx|rar|zip|tbz|7z|exe|woff|woff2|ttf|svg|eot|txt|htm|html)$ { root /home/www/html/site.ru/; expires 7d; access_log off; #не писать в лог если файл не найден # log_not_found off; include conf.d/gzip.inc; #подключаем gzip сжатие } # .htaccess и .htpasswd и .git не отдаем: location ~ /\.(ht|git) { deny all; } location / { proxy_pass http://127.0.0.1:81/; include conf.d/proxypass.inc; #включаем кэширование запросов #proxy_cache sitecache; #proxy_cache_valid 200 301 302 304 10m; #Позволяет запустить фоновый подзапрос для обновления просроченного элемента кэша, в то время как клиенту возвращается устаревший закэшированный ответ. #proxy_cache_background_update on; #With proxy_cache_lock enabled, if multiple clients request a file that is not current in the cache (a MISS), only the first of those requests is allowed through to the origin server. The remaining requests wait for that request to be satisfied and then pull the file from the cache. Without proxy_cache_lock enabled, all requests that result in cache misses go straight to the origin server. #proxy_cache_lock on; } #auth_basic "Restricted Access"; #auth_basic_user_file /var/www/all.htpasswd; } # только для главной, если ddos #location = / { # limit_req zone=one burst=2 nodelay; # limit_req_status 444; #} #убираем www if ($host ~* www\.(.*)) { set $host_without_www $1; rewrite ^(.*)$ http://$host_without_www$1 permanent; } }
Выдача кода 444 при DDOS атаке максимально разгружает сервер на каждом запросе. Это самый «легкий» ответ который сервер может отдать клиенту.
Определим подключаемые файлы:
conf.d/gzip.inc
gzip on; # Минимальная длина ответа, при которой модуль будет жать, в байтах gzip_min_length 1100; # Разрешить сжатие для всех проксированных запросов gzip_proxied any; # Запрещает сжатие ответа методом gzip для IE6 gzip_disable "msie6"; # Уровень gzip-компрессии gzip_comp_level 3; gzip_vary on; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript
Файл conf.d/proxy.inc
proxy_buffering off; proxy_connect_timeout 59s; proxy_send_timeout 120; proxy_read_timeout 180; proxy_buffer_size 64k; proxy_buffers 16 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; proxy_pass_header Set-Cookie; #важный параметр если мы хотим передавать Cookie proxy_redirect off; proxy_hide_header Vary; proxy_hide_header X-Powered-By; proxy_set_header Accept-Encoding ''; #If you want to get the cache-control and expire headers from apache, comment out 'proxy_ignore_headers' and uncomment 'proxy_pass_header Expires;' and 'proxy_pass_header Cache-Control #proxy_pass_header Expires; #proxy_pass_header Cache-Control; proxy_ignore_headers Cache-Control Expires; proxy_set_header Referer $http_referer; proxy_set_header Host $host; proxy_set_header Cookie $http_cookie; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Так как запросы от клиента у нас принимает nginx, то только он знает его настоящий ip. На Apache при этом приходит уже ip nginx, то есть 127.0.0.1. Для многих скриптов это критично важно и для «проброски» адреса существует специальный модуль.
До Apache версии 2.4.6 использовался mod_rpaf
https://centos.pkgs.org/7/nux-misc-x86_64/mod_rpaf-0.8.4-1.el7.nux.x86_64.rpm.html
После этой версии надо использовать mod_remoteip.
LoadModule remoteip_module /usr/lib/apache2/modules/mod_remoteip.so
<IfModule remoteip_module> RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 127.0.0.1 </IfModule>
После проведенных настроек перезагружаем оба сервера и проверяем работу
service httpd restart && service nginx restart