Настройка производительного веб-сервера на NGINX + PHP-FPM

Настройка производительного веб-сервера на NGINX + PHP-FPM

PHP-FPM (Fast Process Manager) – это отдельная реализация обработчика FastCGI для выполнения PHP скриптов. На базе связки веб-сервера NGINX (который обрабатывает статику) и PHP-FPM вы можете построить более быстрый и производительный веб-сервер для своих веб-проектов по сравнению с использованием «классической» связки NGINX, Apache и модуль mod_php (стек LAMP).

LEMP – набор программного обеспечения с открытым исходным кодом, которая обычно устанавливается совместно для запуска на сервере для размещения веб-сайтов и веб-приложений. Этот аббревиатурой обозначающет набор ОС Linux с веб-сервером Nginx (он заменяет Apache в более распространенном стеке LAMP), с БД MySQL (MariaDB) и c php для обработки динамических данных.

В данной статье мы рассмотрим установку и оптимизацию стека LEMP для размещения нагруженного веб-проекта на сервере с CentOS 7 на базе связки NGINX+ PHP-FPM + MariaDB/MySQL + установим для сайта SSL сертификата Let’s Encrypt .

Подключение репозитория, обновление сервера

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

# yum install epel-release -y
# yum update -y

Репозиторий установился, но пакетов для обновлений не найдено, так как установлен свежий образ CentOS.

centos - обновление сервера

Установка и настройка веб-сервера Nginx

Для установки свежей версии Nginx, подключим репозиторий разработчика, выполнив команду:

# rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

Или создав конфигурационный файл репозитория /etc/yum.repos.d/nginx.repo со следующим содержимым:

[nginx]  

name=nginx repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=0 enabled=1 

Если вы используете CentOS 8, измените версию в URL.

Установите пакет веб-сервера Nginx с помощью менеджера пакетов yum (или dnf):

# yum install nginx -y

установка nginx веб-сервера в centos linux

Теперь можно запустить nginx и добавить его в автозагрузку с помощью systemctl:

# systemctl start nginx
# systemctl enable nginx

Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.

Чтобы проверить, что веб-сервер работает, откройте в браузере IP-адрес сервера.

nginx установлен

Если у вас тестовая страница не открылась, проверьте настройки разрешенных служб, портов, зон в firewalld на своем сервере.

Настроим конфигурационный файл для отдельного домена build-centos.info. Создадим для сайта отдельную директорию и сам конфигурационный файл:

# mkdir -p /var/www/build-centos.info && mkdir -p /var/www/build-centos.info/log

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

# nano /etc/nginx/conf.d/build-centos.info.conf

И добавим в него следующее содержимое:

server {
    listen 80;
    server_name build-centos.info;
    root /var/www/build-centos.info;
    index index.php index.html index.htm;
    access_log /var/www/build-centos.info/log/access.log main;
    error_log /var/www/build-centos.info/log/error.log;

    location / {
    return 301 https://build-centos.info$request_uri;
    }

    location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico|woff)$ {
    return 301 https://build-centos.info$request_uri;
    }

    location ~ .php$ {
    return 301 https://build-centos.info$request_uri;
    }

  location = /favicon.ico {
    log_not_found off;
    access_log off;
    }

    location = /robots.txt {
    rewrite ^ /robots.txt break;
    allow all;
    log_not_found off;
    access_log off;
    }

    location ~ /.ht {
    deny all;
    }
}

server {
     listen  80;
     server_name  www.build-centos.info;
     rewrite ^ https://build-centos.info$request_uri? permanent;
}

server {
    listen 443 ssl http2;
    server_name build-centos.info;
    root /var/www/build-centos.info;
    index index.php index.html index.htm;
    access_log /var/www/build-centos.info/log/ssl-access.log main;
    error_log /var/www/build-centos.info/log/ssl-error.log;

    keepalive_timeout           60;
    ssl_certificate             /etc/letsencrypt/live/build-centos.info/fullchain.pem;
    ssl_certificate_key         /etc/letsencrypt/live/build-centos.info/privkey.pem;
    ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    add_header                  Strict-Transport-Security 'max-age=604800';

    location / {
    try_files $uri $uri/ /index.php?$args;
    }

    location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico|woff)$ {
    access_log off;
    expires max;
    }

    location ~ .php$ {
    try_files  $uri =404;
    fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param DOCUMENT_ROOT /var/www/build-centos.info;
    fastcgi_param SCRIPT_FILENAME /var/www/build-centos.info/$fastcgi_script_name;
    fastcgi_param PATH_TRANSLATED /var/www/build-centos.info/$fastcgi_script_name;
    include fastcgi_params;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param CONTENT_TYPE $content_type;
    fastcgi_param CONTENT_LENGTH $content_length;
    fastcgi_param HTTPS on;
    fastcgi_intercept_errors on;
    fastcgi_ignore_client_abort off;
    fastcgi_connect_timeout 60;
    fastcgi_send_timeout 180;
    fastcgi_read_timeout 180;
    fastcgi_buffer_size 128k;
    fastcgi_buffers 4 256k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;
    }

    location = /favicon.ico {
    log_not_found off;
    access_log off;
    }

    location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
    }

    location ~ /.ht {
    deny all;
    }
}

server {
     listen  443 ssl http2;
     server_name  www.build-centos.info;
     rewrite ^ https://build-centos.info$request_uri? permanent;
}

Конфигурационный файл содержит настройки для доступа по защищенному протоколу https, так как многие популярные CMS в данный момент по умолчанию работают через него. В дальнейшем мы установим и настроим бесплатный SSL сертификат Let’s Encrypt (по аналогии с установкой Let’s Encrypt сертификата на IIS сайта в Windows Server).

Установка php-fpm и дополнительных модулей php

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

Php-fpm это очень легкий и быстрый менеджер процессов PHP. Он не использует HTTP протокол (как apache), и работает со специальным протоколом FastCGI. За счет легковесности и простоты FPM позволяет намного быстрее обрабатывать PHP запросы. При этом, в сравнении с аналогичной конфигурацией с apache, памяти будет использоваться намного меньше.

Nginx в свою очередь дает существенный выигрыш при отдаче статики. В нашей конфигурации ngnix будет выступать прокси-сервером (кэширующим и front-end сервером), а в качестве бэкенда будет работать php-fpm.

Для установки свежих версий php, используем репозиторий REMI:

# rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

После установки, отредактируйте файл /etc/yum.repos.d/remi-php74.repo:

настройка репозитория remi для php

Запустите установку php-fpm и популярных модулей php:

# yum install php-fpm php-cli php-mysql php-gd php-ldap php-odbc php-pdo php-opcache php-pear php-xml php-xmlrpc php-mbstring php-snmp php-soap php-zip

установка php-fpm и популярных модулей php

Запустите сервис php-fpm и добавитье его в автозагрузку:

# systemctl start php-fpm
# systemctl enable php-fpm

Created symlink from /etc/systemd/system/multi-user.target.wants/php-fpm.service to /usr/lib/systemd/system/php-fpm.service.

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

# lsof -i:9000

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
php-fpm 1551 root 7u IPv4 2078435 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 1552 apache 9u IPv4 2078435 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 1553 apache 9u IPv4 2078435 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 1554 apache 9u IPv4 2078435 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 1555 apache 9u IPv4 2078435 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 1556 apache 9u IPv4 2078435 0t0 TCP localhost:cslistener (LISTEN)

Сервис php-fpm нужно запустить через unix-сокет. В конфигурационном файле /etc/php-fpm.d/www.conf удалите строку listen = 127.0.0.1:9000 и добавьте:

listen = /var/run/php-fpm/php-fpm.sock
listen.mode = 0660
listen.owner = nginx
listen.group = nginx

Чтобы запускать php-fpm не от пользователя apache (по-умолчанию), укажите следующие параметры в конфигурационном файле:

user = nginx
group = nginx

После изменения конфигурационного php-fpm нужно перезапустить сервис:

# systemctl restart php-fpm

Установка Let’s Encrypt и подключение сертификата

Чтобы выпустить бесплатный сертификат Let’s Encrypt, нужно установить нужное certbot.

# yum install certbot

Затем выполните:

# certbot certonly

После запуска команды, вам нужно будет заполнить все данные, указав почтовый ящик, домен и так далее:

# certbot certonly

Saving debug log to /var/log/letsencrypt/letsencrypt.log
How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Plugins selected: Authenticator standalone, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): [email protected]
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree in order to register with the ACME server at https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A
-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about EFF and our work to encrypt the web, protect its users and defend digital rights.
-------------------------------------------------------------------------------
(Y)es/(N)o: N
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c' to cancel): build-centos.info
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for build-centos.info
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/build-centos.info/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/build-centos.info/privkey.pem
Your cert will expire on 2018-01-24. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew"

- Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal.

Чтобы сертификат был корректно выпущен, ваш домен должен быть существующим и направлен на соответствующий веб-сервер.

После выпуска сертификата, выполните перезагрузку веб-сервера nginx и проверье результат.

# systemctl restart nginx

ssl сертфикат для сайта

Соединение в браузере защищено!

Для автоматического продление сертификатов измените конфигурационный файл /etc/letsencrypt/renewal/build-centos.info.conf следующим образом:

# renew_before_expiry = 30 days
version = 0.18.1
archive_dir = /etc/letsencrypt/archive/ build-centos.info
cert = /etc/letsencrypt/live/build-centos.info/cert.pem
privkey = /etc/letsencrypt/live/build-centos.info/privkey.pem
chain = /etc/letsencrypt/live/build-centos.info/chain.pem
fullchain = /etc/letsencrypt/live/build-centos.info/fullchain.pem

# Options used in the renewal process
[renewalparams]
authenticator = webroot
installer = None
account = e9c86e6aa57b45f9614bc7c0015927a5
post_hook = nginx -s reload
[[webroot_map]]
www.build-centos.info = /var/www/build-centos.info
build-centos.info = /var/www/build-centos.info

После изменения файла, добавьте в крон задание:

30 2 * * * root /usr/bin/certbot renew --post-hook "nginx -s reload"

Чтобы проверить, что nginx работает с php, я создал файл index.php и добавил в него:

nginx + php-fpm проверка работы php скрипта

Установка MySQL/MariaDB на веб сервере

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

Настройка Nginx и PHP-FPM для высоконагруженных проектов

Чтобы ваш веб-сервер работал с высокой производительностью и мог обработать большое количество запросов от клиентов, одного железа недостаточно. Важно правильно настроить работу связки nginx и php-fpm.

Настройка nginx

Откройте файл /etc/nginx/nginx.conf и изменит конфигурацию Nginx следующим образом:

  • worker_processes 2;
    — уставите количество рабочих процессов равным количеству ядер на сервере.
  • worker_connections 1024;
    — определяет количество соединений одного рабочего процесса. Выставляйте значения от 1024 до 4096.
  • use epoll;
    — оптимальный вариант метода соединений для Linux.
  • multi_accept on;
    — nginx будет принимать максимальное количество соединений.

Блок http:

  • tcp_nodelay on;
    — отправляет заголовки и начало файла в одном пакете.
  • tcp_nopush on;

Для проектов в которых содержится большое количество статических файлов, обязательно включайте gzip сжатие:

gzip on;

Добавьте большое количество типов файлов, чтобы все проверки на googlespeed проходили:
gzip_types application/atom+xml application/javascript text/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json font/ttf application/x-font-ttf application/vnd.ms-fontobject application/font-woff application/font-woff2 application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vnd.wap.wml text/vtt text/x-component text/x-cross-domain-policy;

Настройка сжатия позволит ускорить ваш проект.

  • keepalive_timeout 30;
    — веб-сервер будет ожидать 30 секунд, прежде чем закрыть keepalive соединения
  • keepalive_requests 100;
    — максимальное количество keepalive запросов от одного клиента
  • reset_timedout_connection on;
    — включите данный параметр, если не хотите, чтобы соединение от клиента, который перестал отвечать, сбрасывались.
  • client_body_timeout 10;
    — веб-сервер будет ждать 10 секунд подтверждение запроса от клиента, по истечению этого времени, соединение сбросится.
  • send_timeout 2;
    — если клиент прекращает чтение ответа от веб-сервера, nginx сбросит соединение с ним.

Если на вашем сайте не предусмотрена загрузка больших файлов, ограничьте это с помощью nginx:

  • client_max_body_size 2m;
    — сервер не примет запросы больше 2 Мб.

оптимизация конфигурации nginx для нагруженных проектов

Если контент на вашем проекте меняется не так часто, вы можете использовать кеширование «expires max;» Либо добавьте соответствующую опцию в конфигурационный файл вашего хоста для нужного типа файлов, например:

location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico|woff)$ {
expires 7d;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Кеш для указанных типов файлов будет хранится 7 дней. Вы можете управлять кешем с помощью данной функции. После всех модификаций, не забывайте выполнять перезапуск nginx:

# systemctl restart nginx

Настройка php-fpm

При установке php-fpm вы сразу перевели его на unix-сокет. Это дает существенных прирост в производительности. По оценкам производительность вырастает в 2-3 раза. Остальные же параметры php-fpm нужно настраивать под каждый проект отдельно, рассмотрим пример настройки для сервера с 1024 Мб памяти.

Для php-fpm мы можем выделить примерно 512 мб, оставив остальное под БД и nginx.

В конфигурационный файл /etc/php-fpm/www.conf, добавим:

  • pm.max_children = 18
    — максимальное число дочерних процессов
  • pm.start_servers = 6
    — число дочерних процессов, создаваемых при запуске
  • pm.min_spare_servers = 4
    — минимальное число неактивных процессов сервера
  • pm.max_spare_servers = 16
    — максимальное число неактивных процессов сервера
  • pm.max_requests = 400
    — число запросов дочернего процесса, после которого процесс будет перезапущен.

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

На текущий сервер я сразу же установил последнюю версию CMS Bitrix, для проверки производительности. На мой взгляд это самая ресурсоемкая CMS и результаты получились неплохие, если учитывать, что это виртуальная машина на KVM с одним ядром (vCPU) и 1024 ОЗУ:

тест производительности bitrix на nginx + php-fpm

Оптимизацию настроек MariaDB я не расписывал, так как есть соответствующая статья на сайте. Я сформировал параметры для my.cnf по статье и база показала отличный результат.

При запуске сайте вы заметите невооруженным взглядом, что nginx + php-fpm будет намного быстрее обрабатывать ваши запросы и возвращать страницы, чем apache2 + mod_php. Если у вас есть возможность провести нагрузочные тесты во время настройки сервера, то это несомненно будет плюсом, если же такой возможности нет, вы можете изменить параметры для своих ресурсов исходя из нашего мануала.

Linux
Настройка производительного веб-сервера на NGINX + PHP-FPM