15%

Спести 15% на всички хостинг услуги

Тествай уменията си и получи Отстъпка за всеки хостинг план

Използвайте код:

Skills
За начало
10.10.2024

PHP-FPM (FastCGI Process Manager): Пълно ръководство за настройка, конфигурация и оптимизация

PHP-FPM (PHP FastCGI Process Manager) е високопроизводителна алтернативна система за управление на PHP процеси, която имплементира протокола FastCGI, за да отдели изпълнението на PHP от процеса на уеб сървъра. Вместо да стартира нов PHP интерпретатор за всяка входяща HTTP заявка — както прави традиционният CGI — PHP-FPM поддържа постоянен пул от работни процеси, които приемат, изпълняват и връщат PHP отговори с драстично по-ниски разходи.

За всеки производствен уеб сървър, работещ с WordPress, Laravel, Symfony или персонализирани PHP приложения, PHP-FPM е стандартният обработчик. Той позволява прецизен контрол върху жизнения цикъл на процесите, ограниченията на паметта, опашката от заявки и изолацията на приложенията — възможности, които просто не са налични с mod_php или обикновен CGI.

Как PHP-FPM се различава от CGI и mod_php

За да разберете защо PHP-FPM е важен, полезно е да видите точно какво замества и защо тези алтернативи са недостатъчни при мащабиране.

ФункцияCGImod_phpPHP-FPM
Модел на процеситеНов процес за всяка заявкаВграден в ApacheПостоянен пул от работни процеси
Ефективност на паметтаМного нискаУмеренаОтлична
Свързаност с уеб сървъраТяснаТясна (само Apache)Отделена (всеки сървър)
Изолация на сайтНямаНямаПълна (отделни пулове)
Плавно презарежданеНеНеДа
Бавен лог / профилиранеНеНеДа
Динамично мащабиране на процесиНеНеДа
Поддръжка на Unix сокетНеНеДа
Съвместимост с NGINXНеНеДа

CGI стартира нов OS процес за всяка заявка. При умерен трафик това създава хиляди цикли fork/exec/exit в минута, претоварвайки CPU и паметта. mod_php вгражда PHP интерпретатора директно във всеки Apache работен процес, което означава, че всеки Apache процес — дори такъв, обслужващ статично изображение — носи пълното PHP изпълнение в паметта. PHP-FPM решава и двата проблема: работните процеси са постоянни и напълно отделени от уеб сървъра, така че NGINX или Apache обработват статичните файлове нативно, докато PHP-FPM обработва само PHP изпълнението.

Архитектура на PHP-FPM: Подробен поток на заявките

Разбирането на вътрешния път на заявките е от съществено значение за настройка и отстраняване на грешки.

  1. Браузърът изпраща HTTP заявка за ресурс .php.
  2. Уеб сървърът (NGINX или Apache) получава заявката и я съпоставя с location блок или директива FilesMatch.
  3. Уеб сървърът препраща заявката към PHP-FPM чрез протокола FastCGI — или чрез Unix домейн сокет (/run/php/php8.2-fpm.sock), или чрез TCP сокет (127.0.0.1:9000).
  4. Главният процес на PHP-FPM насочва заявката към наличен работен процес от конфигурирания пул.
  5. Работният процес изпълнява PHP скрипта, записва в stdout и връща отговора на уеб сървъра.
  6. Уеб сървърът доставя рендерирания HTML на клиента.
  7. Работният процес не приключва — той се връща в пула на неактивните процеси, готов за следващата заявка.

Unix сокетите се предпочитат пред TCP за локална комуникация, тъй като заобикалят изцяло TCP/IP стека, намалявайки латентността с 10–20% в тестове и елиминирайки разходите от свързване с порт и loopback маршрутизация.

Режими на управление на процесите

PHP-FPM поддържа три режима pm (мениджър на процеси), като изборът на грешен е една от най-честите грешки при конфигуриране.

pm = static

Фиксиран брой работни процеси работи постоянно, независимо от трафика. Използвайте това на dedicated сървъри, където искате предвидима, предварително разпределена памет и можете да си позволите разходите при неактивност.

pm = static
pm.max_children = 20

pm = dynamic

PHP-FPM стартира базов брой работни процеси и мащабира нагоре или надолу в рамките на определени граници. Това е най-често използваният режим и правилната настройка по подразбиране за повечето среди за VPS Хостинг.

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500

pm = ondemand

Работните процеси се стартират само когато пристигне заявка и се прекратяват след pm.process_idle_timeout секунди неактивност. Това минимизира потреблението на памет при неактивност и е идеално за сайтове с нисък трафик или споделени среди, където съществуват десетки пулове едновременно.

pm = ondemand
pm.max_children = 20
pm.process_idle_timeout = 10s

Критичен проблем: ondemand въвежда латентност при студен старт при първата заявка след период на неактивност. За приложения, чувствителни към латентност, dynamic винаги е по-добрият избор.

Правилно изчисляване на pm.max_children

Тук повечето администратори допускат скъпоструващи грешки. Задаването на твърде висока стойност за pm.max_children причинява изчерпване на паметта и OOM прекратявания; твърде ниска стойност причинява опашки от заявки и грешки 502 при натоварване.

Правилната формула:

pm.max_children = (Available RAM for PHP) / (Average PHP worker memory usage)

За да намерите средната памет на PHP работен процес:

ps --no-headers -o "rss,cmd" -C php-fpm8.2 | awk '{ sum+=$1 } END { printf "Average: %d MBn", sum/NR/1024 }'

На VPS с 2 GB RAM, където NGINX, MySQL и OS консумират ~600 MB, разполагате с приблизително 1 400 MB за PHP. Ако всеки работен процес използва ~70 MB, безопасната стойност на pm.max_children е 20. Никога не я задавайте на база предположения.

Инсталиране на PHP-FPM

Debian / Ubuntu

sudo apt update
sudo apt install php8.2-fpm
sudo systemctl enable php8.2-fpm
sudo systemctl start php8.2-fpm

CentOS / AlmaLinux / RHEL (с Remi хранилище)

sudo dnf install epel-release
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf module enable php:remi-8.2
sudo dnf install php-fpm
sudo systemctl enable php-fpm
sudo systemctl start php-fpm

Проверете дали услугата работи и потвърдете пътя на сокета:

sudo systemctl status php8.2-fpm
ls -la /run/php/

Конфигуриране на PHP-FPM пулове

Основната конфигурация на PHP-FPM се намира в /etc/php/8.2/fpm/php-fpm.conf, но отделните дефиниции на пулове принадлежат в /etc/php/8.2/fpm/pool.d/. На RHEL-базирани системи файловете на пуловете се намират в /etc/php-fpm.d/.

Всеки пул е изолирана среда за изпълнение. Работата с множество PHP приложения на един и същи сървър — например WordPress сайт и Laravel API — означава създаване на отделни файлове на пулове с отделни потребители, пътища на сокети и ограничения на ресурсите. Това е правилната архитектура за многотенантни настройки и е значително по-сигурна от споделянето на един пул.

Пример: Конфигурация на производствен пул

[myapp]
user = myapp
group = myapp

; Unix socket — always prefer this over TCP for local communication
listen = /run/php/myapp-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; Process manager
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 1000

; Slow log — log requests taking longer than 2 seconds
slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2s

; Status and ping endpoints
pm.status_path = /fpm-status
ping.path = /fpm-ping

; Environment isolation
clear_env = yes
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin

; PHP value overrides per pool
php_admin_value[error_log] = /var/log/php-fpm/myapp-error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M

Директивата clear_env = yes е критична за сигурността настройка, която често се пренебрегва. Без нея PHP работните процеси наследяват всички променливи на средата от главния процес, потенциално изтичайки чувствителни системни данни в $_ENV на вашето приложение.

Интегриране на PHP-FPM с NGINX

NGINX няма нативна възможност за изпълнение на PHP — той разчита изцяло на FastCGI за делегиране на PHP заявки. Това всъщност е архитектурно предимство: NGINX обработва статичните файлове при почти нулева цена, докато PHP-FPM обработва само това, което изисква изпълнение.

server {
    listen 80;
    server_name example.com;
    root /var/www/myapp/public;
    index index.php index.html;

    # Serve static files directly, no PHP involvement
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Delegate PHP to PHP-FPM
    location ~ .php$ {
        # Security: prevent executing uploaded files as PHP
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;

        fastcgi_pass unix:/run/php/myapp-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;

        # Performance tuning
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_read_timeout 300;
    }

    # Block access to the FPM status page from public
    location ~ ^/(fpm-status|fpm-ping)$ {
        allow 127.0.0.1;
        deny all;
        fastcgi_pass unix:/run/php/myapp-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Бележка за сигурността: Редът try_files $uri =404; преди fastcgi_pass не е по избор. Без него NGINX ще препраща заявки за несъществуващи файлове към PHP-FPM, позволявайки атаки за обхождане на пътища, при които нападателят качва изображение, съдържащо PHP код, и подмамва сървъра да го изпълни.

Интегриране на PHP-FPM с Apache

Apache изисква mod_proxy_fcgi за комуникация с PHP-FPM. За разлика от mod_php, този подход позволява на Apache да стартира PHP-FPM като отделен потребител, подобрявайки изолацията.

sudo a2enmod proxy_fcgi setenvif
sudo systemctl restart apache2

Конфигурация на виртуален хост:

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/myapp/public

    <Directory /var/www/myapp/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    <FilesMatch ".php$">
        SetHandler "proxy:unix:/run/php/myapp-fpm.sock|fcgi://localhost/"
    </FilesMatch>

    ErrorLog ${APACHE_LOG_DIR}/myapp-error.log
    CustomLog ${APACHE_LOG_DIR}/myapp-access.log combined
</VirtualHost>

Активиране и използване на страницата за статус на PHP-FPM

Вградената страница за статус е един от най-недостатъчно използваните диагностични инструменти на PHP-FPM. След като pm.status_path е конфигуриран в файла на пула, направете заявка директно:

sudo -u www-data SCRIPT_NAME=/fpm-status SCRIPT_FILENAME=/fpm-status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/myapp-fpm.sock

Или, по-практично, чрез curl след излагането му на ограничен вътрешен endpoint:

curl http://127.0.0.1/fpm-status?full

Ключови метрики за наблюдение:

  • listen queue: Заявки, чакащи свободен работен процес. Всяка стойност над 0 при продължително натоварване означава, че pm.max_children е твърде ниска.
  • active processes: Работни процеси, изпълняващи PHP в момента. Ако това постоянно е равно на pm.max_children, сте достигнали капацитета.
  • slow requests: Кумулативен брой заявки, надхвърлили request_slowlog_timeout. Нарастващ брой показва проблеми на ниво приложение.

Използване на бавния лог за отстраняване на проблеми с производителността

Бавният лог записва пълен PHP stack trace за всяка заявка, надхвърляща конфигурирания праг. Това е безценно за идентифициране на N+1 проблеми с заявки, блокиращи I/O извиквания или неефективни цикли, без да е необходим пълен профилер.

slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2s

Запис в бавния лог изглежда така:

[21-Jun-2025 14:32:11]  [pool myapp] pid 18432
script_filename = /var/www/myapp/public/index.php
[0x00007f3b4c001e80] PDOStatement->execute() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:338
[0x00007f3b4c001d40] runQueryCallback() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:295

Това незабавно ви казва, че тесното място е заявка към базата данни, а не PHP логика — насочвайки усилията ви за оптимизация прецизно.

PHP-FPM с OPcache: Същественото съчетание

PHP-FPM сам по себе си управлява процесите; OPcache елиминира разходите от парсване и компилиране на PHP изходни файлове при всяка заявка. Заедно те формират пълния стек за производителност на PHP в Linux.

Активирайте и настройте OPcache в /etc/php/8.2/fpm/php.ini или в специален /etc/php/8.2/fpm/conf.d/10-opcache.ini:

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.jit_buffer_size=128M
opcache.jit=tracing

Задаването на validate_timestamps=0 деактивира проверките за модификация на файлове при всяка заявка — значително подобрение на производителността в производствена среда. Когато разгръщате нов код, задействайте изрично нулиране на кеша:

sudo systemctl reload php8.2-fpm

На VPS с cPanel, настройките на OPcache често са достъпни в интерфейса за конфигурация на PHP, но ръчното настройване чрез файлове .ini винаги осигурява по-фин контрол.

Укрепване на сигурността на PHP-FPM

Стартирайте всеки пул като специален системен потребител

Никога не стартирайте PHP-FPM пулове като root или като споделен потребител www-data за множество приложения. Създайте специален системен потребител за всяко приложение:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp

След това задайте user = myapp и group = myapp в конфигурацията на пула. Това гарантира, че компрометирано PHP приложение не може да чете файлове, принадлежащи на други приложения на същия сървър.

Ограничете PHP функциите

В блока php_admin_value на пула деактивирайте функциите, които нямат легитимна употреба в уеб приложения:

php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

Ограничете Open Basedir

Ограничете достъпа на PHP до файлове само в директорията на приложението:

php_admin_value[open_basedir] = /var/www/myapp:/tmp

Използвайте Unix сокети със строги разрешения

TCP сокетите (127.0.0.1:9000) са достъпни за всеки процес на сървъра. Unix сокетите с listen.mode = 0660 ограничават достъпа само до притежаващия потребител и група.

Проверка на пълния стек

След конфигуриране на PHP-FPM и вашия уеб сървър, проверете цялата верига преди да пуснете в производство.

Презаредете всички услуги:

sudo systemctl reload php8.2-fpm
sudo systemctl reload nginx
# or
sudo systemctl reload apache2

Тествайте синтаксиса на конфигурацията на NGINX преди презареждане:

sudo nginx -t

Създайте временен info файл (премахнете го след проверката — той излага чувствителни данни за сървъра):

echo "<?php phpinfo();" | sudo tee /var/www/myapp/public/phpinfo.php

Отворете http://example.com/phpinfo.php в браузър и потвърдете:

  • Server API показва FPM/FastCGI
  • PHP Version съответства на инсталираната версия
  • Секцията OPcache е налична и активирана

След това незабавно премахнете файла:

sudo rm /var/www/myapp/public/phpinfo.php

PHP-FPM в среди с множество приложения и висок трафик

На Dedicated сървър, хостващ десетки PHP приложения, архитектурата с множество пулове става от съществено значение. Всяко приложение получава свой собствен пул с независимо настроени pm.max_children, ограничения на паметта и пътища за бавен лог. Неправилно работещо приложение, което изчерпва своя пул от работни процеси, не засяга другите приложения.

За сценарии с висок трафик, комбинирайте PHP-FPM с:

  • NGINX FastCGI кеширане (fastcgi_cache) за обслужване на кешираните PHP отговори като статични файлове, заобикаляйки изцяло PHP-FPM за повтарящи се заявки
  • Redis или Memcached за съхранение на PHP сесии, заменяйки стандартните файлово-базирани сесии, които създават I/O конкуренция при натоварване
  • Хоризонтално мащабиране чрез стартиране на PHP-FPM на сървъри за приложения зад балансьор на натоварването, с NGINX на отделен front-end възел

Ако вашият стек включва SSL терминиране, съчетаването на PHP-FPM с правилно конфигурирани SSL сертификати на ниво NGINX гарантира, че TLS ръкостисканията се обработват преди заявките да достигнат PHP-FPM, поддържайки PHP работните процеси фокусирани изключително върху логиката на приложението.

За изчислително интензивни PHP натоварвания — извод за машинно обучение чрез PHP обвързвания, обработка на изображения или транскодиране на видео — обмислете GPU Хостинг, където PHP-FPM може да делегира тежките изчисления към GPU-ускорени библиотеки, поддържайки стандартна обработка на заявки за уеб слоя.

Ключова матрица за решения и технически контролен списък

Преди разгръщане на PHP-FPM в производство, проверете всеки елемент от този контролен списък:

Избор на мениджър на процеси

  • Използвайте pm = dynamic за общи VPS натоварвания
  • Използвайте pm = static само на dedicated сървъри с предвидим, постоянен трафик
  • Използвайте pm = ondemand само за пулове с нисък трафик или за разработка

Планиране на капацитета

  • Измерете действителната памет на работния процес с ps преди задаване на pm.max_children
  • Запазете поне 20% от общата RAM за OS, уеб сървъра и базата данни
  • Задайте pm.max_requests между 500–1000 за предотвратяване на натрупване на изтичане на памет

Сигурност

  • Всеки пул на приложение работи като свой собствен системен потребител
  • clear_env = yes е зададен във всеки пул
  • open_basedir ограничава достъпа до файлове до директорията на приложението
  • disable_functions блокира функциите за изпълнение на shell команди
  • Използват се Unix сокети вместо TCP сокети

Наблюдаемост

  • pm.status_path е конфигуриран и достъпен само от localhost
  • slowlog е активиран с request_slowlog_timeout от 2–5 секунди
  • Ротацията на логовете е конфигурирана за всички лог файлове на PHP-FPM

Производителност

  • OPcache е активиран с validate_timestamps=0 в производствена среда
  • NGINX FastCGI кеширането е конфигурирано за кешируеми endpoints
  • PHP обработчикът на сесии е настроен на Redis или Memcached, не на файлове

Оперативни

  • sudo systemctl reload php8.2-fpm се използва за промени в конфигурацията без прекъсване (не restart)
  • phpinfo.php се премахва от document root незабавно след проверката
  • Конфигурацията на пула е под контрол на версиите заедно с кода на приложението

ЧЗВ

Каква е разликата между PHP-FPM и mod_php?

mod_php вгражда PHP интерпретатора във всеки Apache работен процес, консумирайки памет дори при обслужване на статични файлове и тясно свързвайки PHP с Apache. PHP-FPM работи като напълно отделна услуга, комуникира чрез FastCGI, работи с всеки уеб сървър включително NGINX и позволява изолация на процесите на приложенията с независими ограничения на ресурсите.

Как да избера между Unix сокет и TCP сокет за PHP-FPM?

Използвайте Unix сокет (listen = /run/php/app-fpm.sock) когато PHP-FPM и уеб сървърът работят на една и съща физическа или виртуална машина. Unix сокетите заобикалят TCP/IP стека, намалявайки латентността и елиминирайки конфликтите с портове. Използвайте TCP сокет (listen = 127.0.0.1:9000) само когато PHP-FPM работи на различен хост от уеб сървъра.

Защо получавам грешки 502 Bad Gateway при натоварване?

Грешка 502 от NGINX, сочеща към PHP-FPM, почти винаги означава, че опашката за слушане е пълна — всички работни процеси са заети и нови връзки се отказват. Проверете pm.status_path за ненулева стойност на listen queue. Решението е или увеличаване на pm.max_children (ако RAM позволява), или оптимизиране на бавните PHP скриптове, идентифицирани чрез бавния лог.

Как да презаредя PHP-FPM без прекъсване на активните връзки?

Използвайте sudo systemctl reload php8.2-fpm вместо restart. Сигналът reload (SIGUSR2) кара главния процес да рестартира работните процеси плавно: съществуващите заявки завършват нормално, докато новите работни процеси поемат актуализираната конфигурация. Твърдото restart прекратява незабавно всички работни процеси, прекъсвайки текущите заявки.

Може ли PHP-FPM да работи с множество PHP версии едновременно на един сървър?

Да. Инсталирайте множество PHP версии (напр. php7.4-fpm и php8.2-fpm) и конфигурирайте всеки пул на приложение да използва подходящия път на сокета. В NGINX насочете fastcgi_pass към правилния сокет за всеки server блок. Това е стандартен модел на споделена инфраструктура, управлявана чрез VPS контролни панели и е напълно поддържан на VPS Хостинг с root достъп.

15%

Спести 15% на всички хостинг услуги

Тествай уменията си и получи Отстъпка за всеки хостинг план

Използвайте код:

Skills
За начало