Настройка сервера apache mpm-event + php-fpm + http/2

Хотите воспользоваться скриптом автоматической установки? Переходите к скрипту

Не хотите читать предисловие – можно сразу перейти к настройке.

Предисловие

В последнее время в интернете распространяется стойкое убеждение, что сервер apache тормозной и пожирает кучу памяти, и если ты хочешь нормальную производительность для своего сервера - ставь nginx + apache или еще лучше nginx в голом виде и будет тебе счастье. И если надо http/2 - тоже ставь nginx.

Неужели все так плохо с apache?

NGINX лучше APACHE. Так ли это?

Неужели разработчики Apache не могут решить проблему ругаемого везде режима prefork? Неужели прошло столько времени и никто не предпринял ничего для решения известной проблемы?

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

Что это значит?

Предположим загружается одна страница сайта, на которой у нас есть подгрузка картинок, стилей css, js библиотек и может быть еще каких-либо вспомогательных файлов (видео или аудио). На загрузку каждого статического файла (например картинки или файла стилей CSS) apache создавал отдельный поток, в котором загружал модуль php и все сопутствующие библиотеки. Все это долго и чрезвычайно расточительно по потреблению памяти. И самое главное – зачем загружать php, если apache просто должен вернуть файл, который у нас хранится на сервере?

Почему Nginx такой хороший?

Да просто потому что для вызова php он использует интерфейс php-cgi (php-fpm), а для обслуживания статики используются потоки, которые менее ресурсоемки, нежели процессы системы. При запуске php его память не смешивается с памятью, потребляемой сервером.

А что в apache нельзя было сделать что-то подобное?

Вы не поверите!...

Проблема была давно понятна и так же давно эту проблему попытались решить. Долгое время решение носило статус беты, но уже несколько лет оно перешло в статус stable и начиная в версии Apache 2.4.17 устанавливается по умолчанию в новых установках сервера. Apache имеет модульную структуру и тот модуль, который отвечает за способ приема запросов и их обработки называется MPM (мульти-процессный модуль).
По-умолчанию в старых версиях apache используется MPM prefork, который создает отдельный процесс в системе на каждое обращение к серверу. Сейчас доступны MPM worker и MPM event. Самый современный и экономный в плане ресурсов памяти и процессора - это MPM event. Именно он устанавливается по умолчанию в новых версиях apache (начиная с 2.4.17).

http/2

Начиная с версии 2.4.17, в apache доступна возможность использовать http/2 для всех соединений. Для этого должен быть включен MPM event и сайт должен использовать https.

Использование MPM event означает, что нельзя использовать php в традиционном режиме в виде модуля (хотя такая возможность существует и эта связка даже запустится на тестовых сайтах). PHP в виде модуля с MPM event приведет к периодическим падениям и ошибкам работы с памятью.

Лучше всего в связке с MPM event показывает себя PHP-FPM. Эта комбинация дает нам, то чем похваляются любители NGINX. Это малое потребление памяти, ресурсов процессора и отдача статических страниц без загрузки PHP и сопутствующих библиотек. Такая комбинация показывает в реальном окружении производительность сравнимую с производительностью чистого NGINX + PHP-FPM.

А если нет разницы - зачем ставить что-то другое?

В реальном применении привычность и стабильность поведения сервера значит очень многое. Apache – это стандарт де-факто практически для любой системы и Joomla в частности. Работа с файлами htaccess описана практически в каждом руководстве.

В синтетических тестах комбинация apache+php-fpm показывает сравнимое с NGINX потребление ресурсов и скорость ответа. Реальная скорость работы будет зависеть от опытности системного администратора и конфигурации физического сервера, на котором исполняются программы.

По моим опытам в нагруженных системах комбинация apache+php-fpm значительно превосходила традиционную комбинацию nginx + apache (это оказалось самой тормознутой комбинацией из всех – хуже был только apache + mod_php) и особо не уступала чистому NGINX.

Поэтому лично я в своих серверах использую именно такую комбинацию.

Как настроить apache + php-fpm + http/2?

А вот здесь лично меня ожидало жестокое разочарование. Несмотря на то, что  в интернете существует не одно описание настройки подобных комбинаций, как оказалось – никто из авторов не утруждал себя реальными тестами на боевых серверах. Логи не разделялись по виртуальным хостам, а система все равно периодически падала по неизвестным причинам. Потоки php не убивались, как это должно было быть и в результате вся система вела себя нестабильно. Хотя на тестовых сайтах все работало чудесно.

Огромное количество времени ушло на понимание причин такого поведения и способов решения. Как оказалось, рабочего решения в интернете не существует (ну или я не умею гуглить, яндексить и бинговать). Про ProxySet disablereuse=on почему-то никто в интернете не пишет... (теперь в интернете гуглится мой вопрос и мой же ответ на stackoverflow.com). Спасибо ребятам из systemintegra.ru за то, что помогли разобраться в проблеме. Опрос знакомых сисадминов к сожалению ни к чему не привел...

В результате родилось это руководство, по которому вы сумеете самостоятельно установить и настроить сервер apache, который поддерживает соединение по протоколу http/2, использует php-fpm и MPM event. На данный момент времени это одна из самых стабильных, и эффективных конфигураций apache, которые можно использовать на рабочем сервере.

Если вы хотите отблагодарить автора за его труд - я могу порекомендовать хороший хостинг для ваших VPS - https://firstvds.ru/
При покупке сервера вы можете использовать промокод 648341969 . Вы получите скидку и отблагодарите меня за счет реферальной программы. Хостинг хороший и надежный. Только выбирать надо сервера с SSD дисками.

В качестве операционной системы выберем CentOS.

Начало установки

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

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

Начинаем с обновления установленной системы CentOS.

yum update

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

yum install wget

Теперь нужно проверить – выключен ли selinux?

Эта проверка важна на физических серверах, виртуальных машинах и в системе виртуализации KVM. Если сервер OpenVZ, то можно даже не проверять – там selinux отключен по умолчанию.

Команда  sestatus показывает включен ли selinux.

Если включен - его надо отключить в файле: /etc/sysconfig/selinux
Найти строку и установить параметр:
SELINUX=disabledsestatus

Устанавливаем любимый файловый менеджер:

yum install mc

Устанавливаем локаль utf-8, чтобы корректно отображался русский шрифт и различные спец символы (в частности те, которые используются mc).

localectl set-locale LANG=en_US.UTF-8

На случай если подключение будет через локаль windows ubuntu и если локали не совпадут – то все переключится на ANSI кодировку. Локали должны совпадать. Поэтому убедитесь, что локаль вашей windows системы совпадает с локалью на сервере (по умолчанию в windows включается русская локаль). Установите одинаковые локали везде.

С windows компьютеров доступ к серверам привычно осуществляется с помощью программы Putty. Для удобного использования лучше создать ключи доступа.
генерируем ключ rsa:

ssh-keygen -t rsa
cd .ssh

если нет файла authorized_keys:

cp id_rsa.pub authorized_keys

Если такой файл есть:

cat id_rsa.pub >> authorized_keys

Не забываем установить права доступа на указанный файл:

chmod 600 authorized_keys

Забираем приватный ключ id_rsa к себе на локальный компьютер.

Самый простой способ – скопировать через буфер обмена себе на компьютер и создать новый файл с этим ключом.
Затем нужно будет преобразовать файл в формат, пригодный для использования программой putty. Если вы будете пользоваться системой bash на windows – можете обойтись без промежуточных преобразований.
Преобразование осуществляется программой puttygen.exe.
Получить саму программу putty и все сопутствующие утилиты можно по ссылке https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html

Устанавливаем (или убеждаемся что они уже установлены) программы cronie и logrotate:

yum install cronie
yum install logrotate

Установка apache

Устанавливаем репозитарий epel. Полностью epel репозиторий называется так — Extra Packages for Enterprise Linux. Это хранилище пакетов, созданное группой специалистов операционной системы Fedora. Пакеты из epel репозитория никогда не конфликтуют и не переустанавливают базовые пакеты RHEL.

yum install epel-release

Теперь установим репозитарий codeit для получения последних версий apache:

cd /etc/yum.repos.d
wget https://repo.codeit.guru/codeit.el`rpm -q --qf "%{VERSION}" $(rpm -q --whatprovides redhat-release)`.repo
yum install httpd mod_ssl

systemctl enable httpd
systemctl start httpd

Если у вас установлен firewall – конфигурируем его для открытия портов web сервера:

firewall-cmd --zone=public --permanent --add-service=http
firewall-cmd --zone=public --permanent --add-service=https
firewall-cmd --reload

делаем рестарт сервера

apachectl restart

На случай если получаем сообщение по типу httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName при перезапуске httpd (сервера апача), идем и в файле /etc/httpd/conf/httpd.conf

ищем вот эти строки:

ищем вот эти строки:
# ServerName gives the name and port that the server uses to identify itself.
# This can often be determined automatically, but we recommend you specify
# it explicitly to prevent problems during startup.
#
# If your host doesn't have a registered DNS name, enter its IP address here.
#
ServerName пишем сюда IP адрес сервера

После ServerName прописываем IP адрес нашего сервера.

В файле /etc/httpd/conf.modules.d/00-proxy.conf  лучше будет закомментировать этот модуль
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
Практически наверняка вы его не будете использовать.
А лишние подлюченные модули только создают проблемы.

Установка PHP

Если у вас уже был установлен php в виде модуля апача, то перед установкой php-fpm нужно будет удалить предыдущие версии php:
yum remove mod_php* php*

Для установки новой версии php в CentOS приходится использовать сторонний репозитарий.

Для CentOS на выбор есть два популярных репозитария: webtatic и Remi. После некоторого тестирования и реального использования в боевом сервере репозитарий от Remi показал себя наиболее полным и стабильно поддерживаемым. Поэтому при выборе репозитария я советую использовать Remi.

Если хотите установить из репозитария webtatic (Сайт проектка https://webtatic.com/), инструкция здесь:

Команда установки:

rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
yum install php72w-fpm php72w-opcache php72w-cli php72w-gd php72w-mbstring php72w-mcrypt php72w-mysqlnd php72w-xml php72w-soap php72w-xmlrpc

Если устанавливать через репозитарий Remi, то инструкция такая:

wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7*.rpm
yum install yum-utils

Выбираем какую версию php будем устанавливать:

yum-config-manager --enable remi-php72

Теперь ставим PHP:

yum install php-fpm php-opcache php-cli php-gd php-mbstring php-mcrypt php-mysqlnd php-xml php-soap php-xmlrpc

После установки php-fpm надо будет еще правильно его настроить. Идеи настройки были взяты из руководства https://www.stephenrlang.com/2018/02/centos-7-apache-2-4-with-php-fpm/ и доработаны для стабильной работы в условиях боевого сервера. К сожалению, если полностью скопировать настройки оттуда – сервер ведет себя нестабильно.

Создаем файл /etc/httpd/conf.d/php.conf со следующим содержимым:

# Tell the PHP interpreter to handle files with a .php extension
# Proxy declaration
<Proxy "unix:/var/run/php-fpm/default.sock|fcgi://php-fpm">
	ProxySet disablereuse=on connectiontimeout=10 timeout=60
</Proxy>
# Redirect to the proxy
<FilesMatch \.php$>
	SetHandler proxy:fcgi://php-fpm
</FilesMatch>
#
# Allow php to handle Multiviews
#
AddType text/html .php
#
# Add index.php to the list of files that will be served as directory
# indexes.
#
DirectoryIndex index.php
#
# Uncomment the following lines to allow PHP to pretty-print .phps
# files as PHP source code:
#
#<FilesMatch \.phps$>
#	SetHandler application/x-httpd-php-source
#</FilesMatch>
#<LocationMatch "/status">
#  SetHandler proxy:fcgi://php-fpm
#</LocationMatch>

#ProxyErrorOverride on

Директива ProxyErrorOverride on нужна для нормальной работы кастомных ошибок, которые настраиваются через htaccess в каждом сайте с помощью директивы ErrorDocument 404. Нужно учитывать, что в этом случае вместо 500 ошибок так же будет выводиться кастомная страница или стандартное сообщение об ошибке Apache. Если для написания сайта используется php фреймворк (например Laravel или Joomla) лучше оставить директиву ProxyErrorOverride отключенной – иначе сайт может работать неверно (например не будет работать перевод сайта в offline). Связано это с действием директив php throw. В том случае, если вы пишите сайт на голом php – возможно включение этой директивы поможет вам в работе. Ее можно включить на уровне виртуальных хостов (и это самый лучший способ так сделать).

Теперь приступаем к редактированию файла /etc/php-fpm.d/www.conf 

Ищем в нем строку listen = 127.0.0.1:9000, закрываем ее комментарием и добавляем строки, которые указаны ниже. В итоге должно получиться вот так:

listen = /var/run/php-fpm/default.sock
listen.allowed_clients = 127.0.0.1
listen.owner = apache
listen.group = apache
listen.mode = 0660
user = apache
group = apache

Если вы хотите чтобы в apache логи php-fpm разбивались индивидуально по сайтам, а не сваливались в одну кучу в одном файле, нужно будет закомментировать еще две строки в этом же файле (/etc/php-fpm.d/www.conf):

;php_admin_value[error_log] = /var/log/php-fpm/www-error.log
;php_admin_flag[log_errors] = on

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

security.limit_extensions = .php .html

Здесь мы добавляем расширение .html для того, чтобы в нем могли исполняться php скрипты.

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

php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache

и если необходимо - создайте эти подкаталоги:

mkdir /var/lib/php/session
mkdir /var/lib/php/wsdlcache

Теперь проверим что конфигурационный файл php-fpm корректен:

php-fpm -t

Если надо установить отладку (учтите что для версии php 7.3 пока еще отладка не доступна), установите пакет rpm php72w-pecl-xdebug (не делайте этого на рабочем сервере! – это только дома для тестирования!):

yum  install php72w-pecl-xdebug

Пишу еще раз! Не устанавливайте xdebug на продакшен сервере! Это только для домашнего тестирования и отладки!

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

systemctl enable php-fpm
systemctl start php-fpm

Продолжаем настройку PHP –  в файле /etc/php.ini найдите эти параметры и исправьте на приведенные значения (или на те, которые вас устроят):

memory_limit = 256M
upload_max_filesize = 32M
post_max_size = 32M

Устанавливаем MariadDB вместо MySQL

cd /etc/yum.repos.d/ 

echo "# MariaDB 10.3 CentOS repository list - created 2018-10-22 16:03 UTC" > MariaDB.repo
echo "# http://downloads.mariadb.org/mariadb/repositories/" >> MariaDB.repo
echo "[mariadb]" >> MariaDB.repo
echo "name = MariaDB" >> MariaDB.repo
echo "baseurl = http://yum.mariadb.org/10.3/centos7-amd64" >> MariaDB.repo
echo "gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB" >> MariaDB.repo
echo "gpgcheck=1" >> MariaDB.repo

yum install MariaDB-server MariaDB-client
systemctl start mariadb
systemctl enable mariadb

Теперь выполним настройки безопасности MySQL и установим пароль доступа к ней. Запускаем команду:

mysql_secure_installation

Когда будет задан вопрос о root пароле, то устанавливаем его. На остальные вопросы просто жмем Enter.

После выполнения этой процедуры лучше разрешить подключение к mysql только через локальные подключения.

В конфигурационном файле /etc/my.cnf.d/server.cnf в разделе [mysqld] раскомментируем строку bind-address и задаем значение 127.0.0.1:
bind-address=127.0.0.1

Полезная утилита zip для разархивирования установщиков скриптов:

yum install unzip

Нужно создать папку для сайта с именем 000-default в директории /var/www/html . Затем создать из нее сайт.
Это на случай, если кто-то решит воспользоваться плохим конфигурированием вашего сервера. По умолчанию для сайтов, которые не существуют на вашем сервере, нужно возвращать 403 код ошибки. Иначе, по вашей ошибке или по злому намерению других людей, возможно создание дублей ваших сайтов.

Установка certbot на CentOS

yum install python2-certbot-apache

Настройка редактора по умолчанию

Если вы будете менять crontab, то лучше поменять vim (стандартный редактор, установленный по умолчанию)  на что-то более удобоваримое, например, редактор nano или стандартный редактор mc - mcedit.
Если выберете nano – вначале убедитесь что он установлен:

yum install nano

Затем в файле .bashrc  добавить строку в конце

export EDITOR=nano

или

export EDITOR=mcedit

В зависимости от выбранного редактора. (Я советую mcedit - он проще)

Установка времени

Изменим время на московское:

mv /etc/localtime /etc/localtime.bak
ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime

Генерируем самоподписанный сертификат SSL на 10 лет:

openssl req -new -days 3650 -x509 -nodes -out /etc/pki/tls/certs/localhost.crt -keyout /etc/pki/tls/private/localhost.key

Указываем только страну, остальное Enter.

Автоматическая установка с помощью скрипта

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

Ссылка на это решение сайт RISH

© Hika.su