Короткий ответ
Сайт на site.example отдаёт статику, а PHP — 502 или «скачать .php»: смотрите FPM, не nginx -t. Три оси: unit php8.3-fpm/php8.2-fpm active, пул www слушает тот же unix/TCP, что fastcgi_pass, лимиты pm.max_children не исчерпаны. Корень /var/www/site.example, IP 10.0.20.40. CLI php -v не доказывает, что пул жив.
Если unit failed — journalctl -u php8.3-fpm и php-fpm8.3 -t. Если unit active, а сокета нет — другой listen или другой major 8.2 vs 8.3.
Симптомы и как отличить
systemctl is-active php8.3-fpm= failed.ls /run/php/пуст или толькоphp8.2-fpm.sock.- В логе FPM:
WARNING: [pool www] server reached pm.max_children. - Nginx: 502; Apache:
AH01079: failed to make connection to backend.
| Состояние | Статья |
|---|---|
| FPM мёртв, 502 | эта + 502 |
| FPM жив, Fatal 500 | 500 |
| FPM жив, очередь, медленно | медленно |
| Таймаут 60с | 504 |
Возможные причины
- Пакет не установлен / unit disabled после миграции.
- Синтаксис
www.conf: дубльlisten, неверныйuser. - Сокет в
/run/php/не создаётся — нет каталога, PrivateTmp, полный диск. pm = dynamicпри слишком большомpm.start_serversотносительно RAM — fork не проходит, unit падает.pm.max_childrenмал: все воркеры заняты, новые запросы ждут/502.listen.aclvs права nginx.- После
apt: sock сменил имя. - Pool файл в
pool.dсlisten = 127.0.0.1:9000, firewall не при чём — nginx ходит в unix.
Диагностика
1. Unit и тест конфига FPM
systemctl status php8.3-fpm php8.2-fpm --no-pager
sudo php-fpm8.3 -t
sudo journalctl -u php8.3-fpm -n 80 --no-pager
df -h / /runphp-fpm8.3 -t должен сказать test is successful и путь конфига /etc/php/8.3/fpm/php-fpm.conf.
2. Пул и listen
sudo grep -E '^\[|^listen|^user|^group|^pm' /etc/php/8.3/fpm/pool.d/www.conf
ls -l /run/php/
sudo ss -xl | grep php
sudo ss -tlnp | grep -E 'php-fpm|:9000'3. Согласование с фронтом
sudo grep -R fastcgi_pass /etc/nginx/sites-enabled
sudo grep -R php-fpm /etc/apache2/conf-enabled /etc/apache2/sites-enabled 2>/dev/null4. Лимиты pm и текущая нагрузка
sudo grep -E '^pm' /etc/php/8.3/fpm/pool.d/www.conf
# статус пула, если включили pm.status_path
curl -s http://127.0.0.1/fpm-status
ps -C php-fpm8.3 -o pid,user,rss,stat,cmd | headpm.status_path открывайте только с localhost/allow 127.0.0.1.
5. RAM
free -m
ps -C php-fpm8.3 -o rss= | awk '{s+=$1} END {print s/1024 " MiB RSS sum"}'max_children * средний RSS не должен превышать доступную RAM минус MySQL/nginx.
Решение
sudo cp -a /etc/php/8.3/fpm/pool.d/www.conf /root/www.conf.$(date +%F)Сценарий A. Unit не установлен / не запущен
dpkg -l php8.3-fpm php8.2-fpm | grep ^ii
sudo apt-get install -y php8.3-fpm php8.3-mysql php8.3-xml php8.3-curl php8.3-mbstring
sudo systemctl enable --now php8.3-fpmНабор расширений — по фактическому composer/плагинам, не копируйте «все php-*».
Сценарий B. Неверный listen
Канон Ubuntu:
[www]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6sudo systemctl restart php8.3-fpm
ls -l /run/php/php8.3-fpm.sockВ nginx — тот же unix. Не chmod 777 на сокет.
Сценарий C. max_children
Симптом: сайт «встаёт» под ботами/пиком, в логе max_children, процессы есть. Поднимите pm.max_children после расчёта RAM. Параллельно режьте ботов: боты.
Пример: RSS воркера ~80 МиБ, 2 ГиБ под PHP → около 20 children, не 100.
Сценарий D. Unit failed на старте
Часто: www.conf с pm.start_servers = 50 при max_children = 10 — FPM отказывается стартовать. Исправьте неравенства:
pm.min_spare ≤ start ≤ max_spare ≤ max_children.
Полный /run — чистка чужих pid, не отключение tmpfs.
Сценарий E. Apache proxy_fcgi
<FilesMatch ".+\.php$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>После смены сокета systemctl reload apache2. Configtest: Apache.
Сценарий F. Несколько сайтов — отдельные пулы
Для второго vhost не копируйте [www] дважды в один www.conf. Создайте /etc/php/8.3/fpm/pool.d/site.example.conf с [site_example], другим listen сокетом и при необходимости другим user. В nginx — этот сокет. Иначе pm.max_children общие, один сайт душит другой.
На 24.04 каталог /run/php/ создаёт пакет; не делайте listen = /tmp/php.sock — после reboot и PrivateTmp сокет «пропадёт». Оставьте /run/php/php8.3-fpm.sock.
php-fpm8.3 -t после правки обязателен: опечатка pm.max_childrens (лишняя s) не стартует пул, nginx даёт 502, CLI php -v зелёный.
Как проверить, что проблема устранена
systemctl is-active php8.3-fpm
ls -l /run/php/php8.3-fpm.sock
echo '<?php echo php_sapi_name();' | sudo tee /var/www/site.example/fpm-probe.php >/dev/null
curl -s --resolve site.example:80:10.0.20.40 http://site.example/fpm-probe.php
sudo rm /var/www/site.example/fpm-probe.phpОжидание: fpm-fcgi, не cli. Удалите зонд сразу. Главная / должна открывать PHP, не скачивать файл.
Если не помогло
- Сокет есть, 502: права, другой root namespace (контейнер).
- FPM active, PHP не парсит:
security.limit_extensions, файл без.php. - Два пула
wwwиsite— vhost может ходить не туда. - OOM:
journalctl -k | grep php-fpm, уменьшите children. - После
apt upgradeunitphp8.3-fpmactive, а nginx всё ещё вphp8.2-fpm.sock— это не «FPM сломан», это рассинхрон путей. Сверьтеls /run/phpиfastcgi_passоднимdiff.
Профилактика
- Мониторинг unit + число процессов +
max_childrenwarning в логе. - Документировать major PHP на стенде.
- Не менять
listenв одном месте из трёх (пул, nginx, apache).
FAQ
reload или restart FPM?
Смена listen/сокета — restart. Смена php.ini и max_children — обычно reload. Если сомневаетесь и нет длинных запросов — restart в окно.
pm = static лучше?
Предсказуемее по RAM. dynamic экономит ночью. На маленьких VPS static с малым N проще считать.
Нужен ли отдельный пул на сайт?
Да, если разные user или лимиты. Для одного site.example достаточно www.
PHP-FPM слушает 0.0.0.0:9000
Закройте. Только unix или 127.0.0.1. Иначе FPM торчит в сеть.
После апгрейда 8.2→8.3 сайт старый
Включён php8.2-fpm, nginx не переведён. Переключите sock и расширения пакетов 8.3.