Налаштування продуктивного веб-сервера на 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 .

зміст:

  • Підключення сховища, оновлення сервера
  • Установка і настройка веб-сервера Nginx
  • Установка php-fpm і додаткових модулів php
  • Установка Let's Encrypt і підключення сертифіката
  • Установка MySQL / MariaDB на веб сервері
  • Налаштування Nginx і PHP-FPM для високонавантажених проектів

Підключення сховища, оновлення сервера

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

# Yum install epel-release -y
# Yum update -y

Репозиторій встановився, але пакетів для оновлень не знайдено, так як встановлений свіжий образ 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 і додати його в автозавантаження за допомогою 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-адреса сервера.

Якщо у вас тестова сторінка не відкрилася, перевірте налаштування дозволених служб, портів, зон в 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:

запустіть установку 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 і добавити його в автозавантаження:

# 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 тисяча п'ятсот п'ятьдесят одна 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

З'єднання в браузері захищено!

Для автоматичного продовження сертифікатів змініть конфігураційний файл /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 і додав в нього:

Установка 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 Мб.

Якщо контент на вашому проекті змінюється не так часто, ви можете використовувати кешування "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 ОЗУ:

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

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