====== nginx: tips & howto ====== ===== Генератор конфига ===== * https://nginxconfig.io * https://nginxbeautifier.com / https://github.com/vasilevich/nginxbeautifier * https://github.com/1connect/nginx-config-formatter * https://git.blindage.org/21h/nginx-formatter Отдельно хочу отметить утилиту [[https://github.com/yandex/gixy|gixy]] для провеки конфига на наличие разного рода ошибок.\\ ===== Конфиги сниппеты ===== * https://github.com/h5bp/server-configs-nginx/tree/master/h5bp * https://github.com/gulch/Trickz-Snipz/blob/master/nginx/NGINX-GCONF/nginx.conf * https://github.com/gulch/Trickz-Snipz/tree/master/nginx/NGINX-GCONF/templates * https://github.com/david-rahrer/nginx-opencart/blob/master/nginx/sites-available/example.com-le.vhost ===== Редиректы ===== ==== Редирект всех запросов на определенный файл ==== root /var/www/foobar.com; index index.php; location / { try_files $uri $uri/ @redirect; } location ~ \.php$ { try_files $uri @redirect; ... } location @redirect { return 301 /index.php; } Works like a charm, как говорится. ==== Перенаправление на SSL-адрес (HTTPS) с нестандартным портом ==== via http://www.f-notes.info/nginx:ssl_non-stadard_port error_page 497 https://$server_name:8443$request_uri; ==== Редирект на https://foobar.com ==== server { listen 80; server_name foobar.com www.foobar.com return 301 https://www.foobar.com$request_uri; } server { listen 443 ssl; server_name foobar.com; ssl_certificate /etc/nginx/ssl/www.foobar.com.crt; ssl_certificate_key /etc/nginx/ssl/www.foobar.com.key; return 301 https://www.foobar.com$request_uri; } server { listen 443 ssl; server_name www.foobar.com; root /var/www/html ssl_certificate /etc/nginx/ssl/www.foobar.com.crt; ssl_certificate_key /etc/nginx/ssl/www.foobar.com.key; } ==== Еще примеры ==== * https://pai-bx.com/wiki/nginx/2332-useful-redirects-in-nginx/ * ===== Банхаммер3000 ===== ==== Блокируем через geoip ==== http://blog.ls20.com/optimizing-nginx-config-for-your-website-or-blog/ Начиная с версии [[https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/|1.9.11]] введена поддержка динамических модулей Примеры использования модуля - http://nginx.org/en/docs/http/ngx_http_geoip_module.html yum install nginx-module-geoip apt-get install nginx-module-geoip Добавляем в самое начало файла ''/etc/nginx/nginx.conf'' перед блоком **http {}** load_module "modules/ngx_http_geoip_module.so"; Коды названий стран [[https://dev.maxmind.com/geoip/legacy/codes/iso3166/|ISO 3166 Country Codes]] В блок **http {}** перед **include** добавить geoip_country /usr/share/GeoIP/GeoIP.dat; map $geoip_country_code $allowed_country { default yes; RU no; UA no; BY no; CN no; } Для блокировки нужно добавить в **server {}** if ($allowed_country = no) { return 444; 444 - закрыть соединение без отправки ответа клиенту. FIXME почитать про GeoIP2 * https://medium.com/@karljohnson/geoip-discontinuation-upgrade-to-geoip2-with-nginxon-centos-c2a3dbcf8fd * 1 ==== Блокируем поисковых ботов ==== * https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker * https://github.com/mariusv/nginx-badbot-blocker map $http_user_agent $bad_bot { default 0; ~(?i)(alexa.com|AltaVista|ApacheBench|Aport|Ahrefs|AhrefsBot|Baiduspider|BLEXBot|CCBot|CommentReader|Copier|Crowsnest|DISCo|discobot|ExpertSearch|ExpertSearchSpider|FairShare|FeedFetcher|FlaxCrawler|FastSeek|FlappyBot|FlashGet|GetRight|GetWeb!|Grabber|g00g1e|HTTrack|ia_archiver|LeechFTP|LeechGet|Linguee|LinkBot|MauiBot|MJ12|MJ12bot|netvampire|Offline|PycURL|Python|QuerySeekerSpider|Ruby|Seopult|Semrush|SEMrushBot|SputnikBot|spbot|SputnikFaviconBot|SputnikImageBot|Sogou|TalkTalk|Teleport|uTorrent|urllib|Vampire|vkShare|WebCopy|WebCopier|WebCollector|WebSpider|WebStripper|WebWhacker|Yeti|YottosBot) 1; } В **server {}** добавить в нужное место if ($bad_bot = 1) { return 403; } Для проверки представимся ahrefsom curl http://localhost -H 'User-Agent: Ahrefs' -I ==== Блокируем реферальный спам ==== 1 Добавляес в ''http {}'' спам домены map $http_referer $bad_referer { hostnames; default 0; "~*best\-seo\-solutions\.com" 1; "~*buy\-cheap\-online\.net" 1; "~*get\-free\-traffic\-now\.biz" 1; } Добавляес в ''server {}'' для нужного сайта server { if ($bad_referer) { return 444; } } Можно использовать [[https://github.com/Stevie-Ray/referrer-spam-blocker|готовый черный список]] через include http { include referral-spam.conf; } В этом нам поможет [[http://nginx.org/en/docs/http/ngx_http_map_module.html|ngx_http_map_module]] ===== PHP-FPM ===== ==== ondemand или dynamic ==== * [[https://www.linux.org.ru/forum/web-development/13089187?lastmod=1482082470587#comment-13089427|Как быть с пулами в php-fpm, если сайтов больше 2-x?]] * [[https://ma.ttias.be/a-better-way-to-run-php-fpm/|A better way to run PHP-FPM]] * [[https://hcbogdan.com/php/2016/09/16/php-fpm-dynamic/|Настраиваем php-fpm / hcbogdan]] //Во-первых пул это просто набор процессов. Это не какой-то отдельный процесс.\\ При политике ondemand воркеры создаётся только тогда когда приходит запрос. Через несколько секунд (задаётся в настройках) после завершения обработки запроса (если не поступит нового запроса который можно передать воркеру) воркер убивается.\\ При dynamic демон всегда поддерживает некоторое заданное количество воркеров в пуле, и распределяет запросы между ними. Если для обработки запросов не хватает воркеров то демон создаёт дополнительных (вплоть до некоторого конфигурируемого значения). Когда потребность в дополнительных воркерах отпадает демон убивает лишние, так что-бы осталось нужное количество.\\ Профит от повторного использования воркеров в том что не тратится время на повторное создание процесса. Но если у тебя тормозной код то на его фоне ты этого времени всё-равно не заметишь.\\ На сколько я понимаю это происходит как-то так. Попаболь в том что воркеры не особо спешат освобождать память использованную для обработки запроса (кстати я не в курсе баг это или какая-то непонятная фича). По этому если твоё приложение на обработку каждого запроса тратит (например) 100 мб памяти и у тебя есть 3 воркера, каждый из которых за свою жизнь получил хотя-бы один запрос, то у тебя в системе будет висеть три процесса каждый из которых выжирает по 100 мб памяти, даже если запросов в тот пул сейчас нет вообще. Побаболь наступает тогда когда у тебя есть куча малопосещаемых сайтов с жадным до памяти кодом. У меня используется dynamic для пулов которые без запросов не остаются, и ondemand для малопосещаемых сайтов.// ==== Калькулятор max_children ==== cli * [[https://myshell.co.uk/blog/2012/07/adjusting-child-processes-for-php-fpm-nginx/|Adjusting child processes for PHP-FPM (Nginx)]] * https://tresnet.ru/archives/1313 ui calc * https://cmorrell.com/php-fpm/ * [[https://chrismoore.ca/2018/10/finding-the-correct-pm-max-children-settings-for-php-fpm/|Finding the correct pm.max_children settings for PHP-FPM]] / https://spot13.com/pmcalculator/ / https://github.com/spot13/pmcalculator ==== Разное FPM ==== * [[https://www.getpagespeed.com/server-setup/nginx/no-input-file-specified|NGINX vs PHP-FPM: No input file specified]] * [[https://www.vennedey.net/resources/3-Secure-webspaces-with-NGINX-PHP-FPM-chroots-and-Lets-Encrypt|Secure webspaces with NGINX, PHP-FPM chroots and Let's Encrypt]] / [[https://www.vennedey.net/jailspaces|Jailspaces]] * [[https://publications.jbfavre.org/web/php-fpm-apps-server-nginx.en|PHP-FPM, application server made by PHP]] * [[http://docs.mirocow.com/doku.php?id=system:php:chroot|php-fpm в chroot и некоторые трудности]] * [[http://mailman.nginx.org/pipermail/nginx-ru/2013-June/051221.html|Re: Проблема с chroot в связке Nginx + PHP-FPM]] * https://blog.programs74.ru/how-to-installing-and-configuring-server-for-web-hosting/ * [[https://haydenjames.io/php-fpm-tuning-using-pm-static-max-performance/|PHP-FPM tuning: Using ‘pm static’ for max performance]] ==== Дебаг PHP-FPM с помощью strace ==== * [[https://shubhamjain.co/2015/09/10/debugging-stuck-php-fpm-process-with-strace/|Debugging Stuck PHP-FPM Process With Strace]] * [[https://www.bggofurther.com/2015/04/using-strace-with-multiples-pids|Using strace with multiples PIDs]] * [[https://blog.sleeplessbeastie.eu/2019/10/14/how-to-strace-php-fpm-processes/|How to strace PHP-FPM processes / blog.sleeplessbeastie.eu]] * [[https://stackoverflow.com/questions/33643131/how-strace-php-fpm-process|how strace php-fpm process?]] * [[https://medium.com/@nickpeirson/analyse-running-php-processes-with-free-open-source-tools-538ae18f5fe1|Inspecting rogue PHP processes]] ===== Разное ===== ==== Ограничение доступа для групп адресов ==== ''/etc/nginx/includes/admin-ips'' allow 1.2.3.4/32; allow 1.2.3.8/32; ''/etc/nginx/includes/private-ips'' allow 10.0.0.0/8; allow 172.16.0.0/12; allow 192.168.0.0/16; ''/etc/nginx/includes/testing-ips'' allow 4.5.6.7; allow 8.9.10.11; ''/etc/nginx/conf.d/foobar.conf'' location ^~ /admin/ { include includes/admin-ips; deny all; } location ^~ /beer/ { include includes/admin-ips; include includes/testing-ips; include includes/private-ips; deny all; } location ^~ /vodka/ { include includes/admin-ips; include includes/testing-ips; deny all; } ==== Как работает SNI ==== * https://www.itsfullofstars.de/2020/12/server-name-indication/ ==== Что такое CORS ==== * [[https://ibnrubaxa.medium.com/nginx-vs-cors-7a63029d9a34|NGINX vs. CORS]] * [[https://enable-cors.org/server_nginx.html|CORS on Nginx]] * [[https://evilinside.ru/nastrojka-cors-v-nginx/|Настройка CORS в Nginx]] ==== Отключить кэширование для директории ==== Например есть такое location /static { alias /var/www/foobar.com/static; add_header Pragma "cache"; add_header Cache-Control "public"; } И есть апишечка где кэш очень вреден location /api/ping-pong { add_header Pragma "no-cache"; add_header Cache-Control "private, max-age=0, no-cache, no-store"; } ==== X509_check_private_key:key values mismatch ==== Нарушен порядок в crt/pem файле. -----BEGIN CERTIFICATE----- Сертификат_сервера -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- Сертификат корневого центра сертификации (CA) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- СЕРТИФИКАТ ПРОМЕЖУТОЧНОГО ЦЕНТРА СЕРТИФИКАЦИИ Сертификат промежуточного центра сертификации (Intermediate) -----END CERTIFICATE----- ==== HTTPOnly и Secure Cookie ==== * https://rdevelab.ru/blog/no-category/post/samesite-cross-domain-cookies * https://itgala.xyz/nginx-httponly-and-secure-cookie/ ==== favicon.ico ==== По стандарту, "картинка (иконка) сайта" должна быть. Поэтому в еррлоги активно пишется на каждый запрос, что favicon.ico not found. Можно для nginx создать секцию location /favicon.ico { root ... log_not_found off; access_log off; } Есть опция **empty_gif** location /favicon.ico { empty_gif; access_log off; } Таким образом будет отдаваться прозрачный гиф 1х1px на все запросы иконки. А теперь объединим. location /favicon.ico { access_log off; try_files $uri @emptygif; } location @emptygif { internal; empty_gif; } via * http://nginx.org/en/docs/http/ngx_http_empty_gif_module.html * http://dragonflybsd.blogspot.ru/2012/10/nginx-faviconico.html ==== Закрываем сайт на обслуживание ==== **Варианты** **1) в location /** ## System Maintenance (Service Unavailable) if (-f $document_root/system_maintenance.html ) { error_page 503 /system_maintenance.html; return 503; } (if нежелателен - там куча ограничений, нюансов и оно довольно сильно грузит сервер, [[http://wiki.nginx.org/IfIsEvil|IfIsEvil]]) **2) try_files closed.html @apache =503;**\\ (проблема в том, что в таком варианте код ответа при обслуживании будет 200). Хотя можно сделать отдельный location closed.html и в нем выставить код ответа 503, по желанию оттуда же отдать и саму страницу. Можно написать как try_files /maintenance.html $uri $uri/ @wordpress; но если индекса нет и апач перекидывает на какую-то внутреннюю страницу с рядом опций - могут быть проблемы, если такой файл вдруг появится, а это не предусмотрено системой. Плюс, если была встроенная фильтрация на бэкенде - так ее можно обойти. Ну и 2 лишние проверки получаем. С другой стороны, для простых движков этот вариант будет быстрее и если вся статика не вынесена по отдельным location, автоматом начнётся раздача статики. Но снова безопасность, надо тогда создавать location на потенциально опасные места и там запрещать, обязательно. В частности на .ht, .svn, .git, служебные области. В общем, лучше первая версия этого варианта. **3) через переменную и if** set $Maintenance = off; if ($Maintenance = 'on') ... но см выше про if. **4) выделить блок, закрывающий сайт на обслуживание в отдельный файл maint.conf**, сделать 2 файла maint-on.conf и maint-off.conf, и вешать симлинк на нужную версию файла с именем maint.conf и потом делать reload. Можно не симлинком а копированием. Самый быстрый способ, но требует немного кодинга. via http://dragonflybsd.blogspot.ru/2012/10/nginx.html ==== Как убедиться, что работает gzip_static ==== Нашёл здесь - https://stackoverflow.com/questions/2460821/how-can-i-check-that-the-nginx-gzip-static-module-is-working Находим PID # ps ax | grep nginx 1071 ? Ss 0:01 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf 17947 pts/0 S+ 0:00 grep --color=auto nginx 18315 ? S 0:25 nginx: worker process Запускаем trace # strace -p 18315 2>&1 | grep gz open("/home/admin/web/foobar.com/public_html/uploads/posts/2017-01/1485714800-275451094.jpg.gz", O_RDONLY|O_NONBLOCK|O_LARGEFILE) = 34 open("/home/admin/web/foobar.com/public_html/uploads/posts/2017-01/1485714801-2083693483.jpg.gz", O_RDONLY|O_NONBLOCK|O_LARGEFILE) = 34 open("/home/admin/web/example.com/public_html/uploads/posts/2016-11/thumbs/1480346913_09b7vuxzf2vgwqd.jpg.gz", O_RDONLY|O_NONBLOCK|O_LARGEFILE) = -1 ENOENT (No such file or directory) ==== monit ==== https://mmonit.com/wiki/Monit/Nginx server { listen 80; server_name monit.domain.com; location / { proxy_pass 127.0.0.1:2812; proxy_set_header Host $host; } } ==== Много соединений в TIME_WAIT ==== Apache (backend) nginx (frontend). В netstat сотни/тысячи коннектов в состоянии TIME_WAIT. В итоге система упирается в количество доступных сетевых сокетов, что приводит к невозможности устанавливать новые соединения. Скорее всего это нормально если включён keepalive. Если устанавливается много новых подключений и быстро разрываются, то образуется очередь из TIME_WAIT. Решением было установить для параметров ядра **TCP_TW_RECYCLE** и **TCP_TW_REUSE** значение **1**, по-умолчанию **0** Применять с осторожностью echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse Или добавить в ''/etc/sysctl.conf'' net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_tw_recycle=1 net.ipv4.tcp_fin_timeout=15 net.ipv4.ip_local_port_range = 10240 65000 * TCP_TW_RECYCLE Description: Enables fast recycling of TIME_WAIT sockets. Use with caution and ONLY in internal network where network connectivity speeds are “faster”. * TCP_TW_REUSE Description: Allows for reuse of sockets in TIME_WAIT state for new connections, only when it is safe from the network stack’s perspective. **Обновлено** Ошибка **sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory** net.ipv4.tcp_tw_recycle [[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4396e46187ca5070219b81773c4e65088dac50cc|был удалён из ядра]] Linux 4.12 в 2017. The tcp_tw_recycle was already broken for connections behind NAT, since the per-destination timestamp is not monotonically increasing for multiple machines behind a single destination address. After the randomization of TCP timestamp offsets in commit 8a5bd45f6616 (tcp: randomize tcp timestamp offsets for each connection), the tcp_tw_recycle is broken for all types of connections for the same reason: the timestamps received from a single machine is not monotonically increasing, anymore. Remove tcp_tw_recycle, since it is not functional. Also, remove the PAWSPassive SNMP counter since it is only used for tcp_tw_recycle, and simplify tcp_v4_route_req and tcp_v6_route_req since the strict argument is only set when tcp_tw_recycle is enabled. Почитать * https://www.speedguide.net/articles/linux-tweaking-121 * http://web.archive.org/web/20140616114533/http://performancewiki.com/linux-tuning.html ==== TCP_CORK/TCP_NOPUSH и TCP_NODELAY ==== Игорь Сысоев / http://sysoev.ru Да, в Линкусе TCP_CORK (tcp_nopush) и TCP_NODELAY взаимоисключающие, но nginx проявляет недюженный интеллект, пытаясь совместить преимущества обеих опций. "tcp_nopush on" полезно для sendfile(), он в этом случае выводит данные полными пакетами. После того, как весь запрос обработан, TCP_CORK/TCP_NOPUSH выключается, что приводит в сбросу последнего неполного пакета. "tcp_nodelay on" полезно для keep-alive. nginx включает TCP_NODELAY только по окончании запроса, после которого соединение переходит в состоянии keep-alive. До этого nginx выводит данные вызовами writev() достаточно большими порциями для заполнения пакета ("postpone_output 1460"), поэтому данные должны уходить без задержек и TCP_NODELAY не нужен. А вот с последним неполным пакетом может случится небольшая задержка, если соединение не закрывается. Для этого и нужно включить TCP_NODELAY. В Линуксе обработка этих двух опций tcp_nopush on; tcp_nodelay on; такова: 1) если данные будут выводить комбинацией writev(заголовок)/sendfile(), то проверяется, не было ли уже включен TCP_NODELAY. Если было, то TCP_NODELAY выключается и включается TCP_CORK. По окончании передачи TCP_CORK выключается. Включать TCP_NODELAY не нужно, так как выключание TCP_CORK сбрасывает данные. 2) если при переходе в keep-alive TCP_CORK не была включена, то включается TCP_NODELAY, чтобы сбросить неполный пакет. Кстати, возможно, для "proxy_buffering off" имеет смысл включать TCP_NODELAY до отдачи ответа. ==== Как определить количество рабочих процессов, задаваемых параметром worker_processes? ==== via http://www.httpd.kiev.ua/tips/nginx/number-of-worker-processes/ Ответ автора nginx Игоря Сысоева: //Если весь сайт помещается в память сервера, к диску обращений нет, и это выделенный сервер для nginx, то 1. Не будет лишних переключений контекста. Если нужно ходить на диск, то 5-10 - это позволит обрабатывать соединения процессами, незаблокироваными на диске. // Кроме этого необходимо понаблюдать за состоянием процессов nginx в работе в часы пик. Командой ps посмотреть состояние рабочих процессов (worker process): # ps ax -o %cpu,vsz,wchan,command | grep "nginx\|PID" %CPU VSZ WCHAN COMMAND 0,0 1428 pause nginx: master process /usr/local/nginx/sbin/nginx 0,0 2284 - nginx: worker process (nginx) 0,0 2128 kqread nginx: worker process (nginx) Если один из рабочих процессов находится в состоянии ожидания "kqread" в колонке "WCHAN", то значит их количество достаточно. Ну а если уж все они постоянно находятся в этом состоянии, то их количество можно сократить до одного. И не забывайте контролировать логи ошибок nginx, если количество соединений превысит значение, которое в может обслужить nginx текущим количеством процессов, то в логах это будет соответствующее сообщение. ==== Правильная отдача заголовков при технических работах на сайте ==== (via http://www.zagirov.name/correct-return-header-on-service) Есть ситуация: проводятся какие-то технические работы на сайте и нужно сайт правильно закрыть. Это нужно чтобы поисковики знали, что сайт не доступен, а не добавляли страницы в индекс или помечали страницы как удалённые. server { listen 80 default; server_name _; root /var/www/default/www; charset utf-8; error_page 404 403 =503 /503.html; location = /503.html { add_header Retry-After "Sun, 27 Feb 2011 23:59:59"; } } Строка error_page **404 403 =503 /503.html** означает, что перенаправляем все запросы с ошибками 404 и 403 на файл 503.html, попутно меняя код ответа на 503. И при запросе файла 503.html отдаём заголовок Retry-After, чтобы поисковики знали, когда можно опять запросить страницу. Вместо даты можно указать количество секунд перед следующей попыткой. В файле 503.html можно написать что-нибудь осмысленное для пользователей и даже встроить флэш-игру, чтобы не было скучно. ==== Схема frontend-backend ==== * http://blog.korphome.ru/2010/12/31/centos-nginx-%D0%B2-%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B5-frontend%D0%B0-%D0%BA-apache/ ===== Кэширование ===== * [[http://wiki.enchtex.info/practice/nginx/cache|Настройка кеширования в nginx]] * [[http://debian-help.ru/web-servers/nastroika-keshirovaniya-statiki-s-pomoshyu-nginx-v-debian/|Настройка кэширования статики с помощью nginx в Debian]] * [[http://habrahabr.ru/post/253121/|Гид по заголовкам кэширования HTTP для начинающих]] * [[https://angristan.xyz/ghost-nginx-cache/|Caching Ghost with Nginx]] * [[https://nystudio107.com/blog/static-caching-with-craft-cms|Static Page Caching with Craft CMS]] ===== Разное ===== * http://kevin.deldycke.com/2011/09/nginx-php-fpm-mysql-configuration/ * http://kbeezie.com/view/nginx-configuration-examples/ * http://wiki.rsu.edu.ru/index.php/Nginx * http://tweaked.io/guide/nginx/ * [[http://slonik-v-domene.livejournal.com/141951.html|Apache vs Nginx: Расставим точки над ё.]] * [[https://www.kinamo.be/en/kb/determining-the-correct-number-of-child-processes-for-php-fpm-on-nginx|Determining the correct number of child processes for PHP-FPM on NGinx]] * [[https://nls.io/blog/optimize-nginx-and-php-fpm-max_children|Optimize nginx and PHP-FPM (max_children)]] * [[https://www.getpagespeed.com/server-setup/nginx-try_files-is-evil-too|try_files is evil too]] * [[https://medium.com/southbridge/nginx-as-reverse-proxy-a62815edd8c1|Nginx как обратный прокси на Docker]] * [[https://tech.geekjob.ru/nginx-tips-tricks/|Выгружаем конфиг из памяти]] * [[https://blog.serverdensity.com/troubleshoot-nginx/|Troubleshoot Nginx: 10 typical errors]] * https://blog.blakeerickson.com/block-referral-spman-nginx * https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/blob/master/deny.d/deny.conf * [[https://github.com/trimstray/nginx-admins-handbook|Nginx Admin's Handbook]] * [[https://github.com/jukbot/setup-nginx-webserver|Setup a perfect webserver on CentOS/Redhat 7.x guide with understanding]] * [[https://github.com/kalyabin/kalyabin-ru/wiki/(debian)-Установка-и-настройка-php-fpm|(debian) Установка и настройка php fpm kalyabin-ru]]