
Как подключить PHP-FPM к Nginx через FastCGI
Настраиваем связку Nginx и PHP-FPM: находим socket, передаём SCRIPT_FILENAME, запрещаем выполнение чужих файлов и разбираем 404 и 502.
Содержание
Nginx умеет отдать готовый файл, но не исполняет PHP-код. Запрос к .php он передаёт отдельной службе PHP-FPM по протоколу FastCGI. Служба держит группу рабочих PHP-процессов — pool — и принимает запросы через локальный Unix-сокет либо TCP-порт.
Для рабочей связки нужно найти настоящий адрес этого сокета, дать Nginx право подключаться к нему и передать PHP-FPM точный путь к скрипту. Начнём с действующей службы, потому что копирование имени сокета с чужого сервера часто заканчивается 502.
Определите активную службу и socket
Имена зависят от дистрибутива и версии. Не копируйте /run/php/php8.x-fpm.sock без проверки:
systemctl list-units --type=service | grep -E 'php.*fpm'
systemctl status php-fpm --no-pager
sudo grep -R '^listen\s*=' /etc/php* /etc/php-fpm* 2>/dev/null
sudo ss -xlpn | grep php
В вашей системе служба может называться иначе. Сверьте pool, который обслуживает сайт, пользователя процесса, listen.owner, listen.group и listen.mode. Nginx должен иметь право подключаться, но делать socket доступным всем пользователям не нужно.
Базовая конфигурация
В следующем примере публичные файлы находятся в /var/www/example/public, а PHP-FPM принимает запросы через /run/php/php-fpm.sock. Блок подходит сайту с front controller index.php, если это предусмотрено его документацией:
server {
listen 443 ssl;
server_name example.com;
root /var/www/example/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
}
Замените socket и root фактическими значениями. try_files в PHP-location запрещает отправлять несуществующий путь интерпретатору. SCRIPT_FILENAME формирует абсолютный путь. Файл fastcgi_params и содержимое пакетных snippets различаются, поэтому проверьте, не задаётся ли параметр уже и что именно подключается.
Правило location / показано для приложения с front controller. Статический сайт или другой фреймворк требует иного fallback. Не направляйте неизвестные пути в index.php, если приложение этого не ожидает.
Ограничьте область выполнения
Каталог пользовательских загрузок не должен исполнять PHP. Если uploads находится внутри document root, добавьте более приоритетный запрет, соответствующий его точному пути:
location ^~ /uploads/ {
try_files $uri =404;
}
Ещё лучше хранить загружаемые файлы вне каталога кода и отдавать их по отдельной проверенной схеме. Не используйте широкие regex, если не понимаете порядок выбора location; сначала изучите root, alias и try_files.
Ограничьте доступ к скрытым и служебным файлам отдельно. Конкретный список зависит от приложения: универсальный запрет может случайно скрыть ACME challenge или нужный ресурс.
Unix socket или TCP
Unix socket удобен, когда Nginx и FPM находятся на одном узле. TCP нужен между контейнерами или хостами, но адрес нельзя без необходимости слушать на публичном интерфейсе:
fastcgi_pass 127.0.0.1:9000;
Факт открытого порта проверьте ss -ltnp. Для удалённого FPM потребуется отдельная защищённая сеть и модель доверия; FastCGI не следует публиковать в интернет.
Проверка
sudo nginx -t
sudo systemctl reload nginx
systemctl is-active php-fpm
curl -I https://example.com/
Имя службы подставьте реальное. Для теста можно временно создать простой PHP-файл, возвращающий фиксированный текст, но не phpinfo() на публичном сайте: он раскрывает конфигурацию и окружение. Удалите тест сразу после проверки.
Одновременно наблюдайте журналы:
sudo journalctl -u nginx -u php-fpm --since "10 minutes ago"
sudo tail -n 50 /var/log/nginx/error.log
Разбор ошибок
502 Bad Gateway
Сначала проверьте активность FPM, фактический socket/порт и права. Сообщение No such file or directory обычно указывает на неверный путь или остановленную службу; Permission denied — на владельца, группу или контекст безопасности. Не исправляйте последнее chmod 777.
File not found или Primary script unknown
Сравните root, запрошенный URI, SCRIPT_FILENAME и путь внутри контейнера. Nginx и FPM могут видеть разные файловые системы. Логируйте точные пути только в защищённый журнал и не показывайте их посетителю.
PHP скачивается или виден как текст
Запрос не попал в FastCGI-location либо конфигурация не активна. Это критично: временно уберите сайт из доступа, исправьте выбор виртуального хоста и проверьте, что исходный код и секреты не были выданы.
404 на front controller
Проверьте существование index.php, root и fallback. Не убирайте try_files вслепую: оно может предотвращать выполнение несуществующих или загруженных путей.
Откат
Держите предыдущий конфиг рядом вне публичного каталога. При ошибке верните его, выполните nginx -t и reload. Изменения pool PHP-FPM откатывайте отдельно и проверяйте синтаксис средствами установленной версии PHP. Общая схема reverse proxy описана в руководстве по проксированию.
Эксплуатационный минимум
После запуска контролируйте очередь и предел workers FPM, время PHP-запросов и память процессов. Когда пул исчерпан, увеличение timeout Nginx лишь удлиняет очередь. Настройте slow log и status FPM только по документации установленной версии, ограничьте их локальной сетью и не публикуйте диагностические страницы.
Обновление PHP выполняйте как отдельный релиз: новый socket часто получает другое имя. Сначала поднимите новый pool, проверьте совместимость приложения, переключите Nginx и сохраните возможность вернуть прежний upstream.
Первоисточники
- Nginx: ngx_http_fastcgi_module — FastCGI-параметры, буферы и fastcgi_pass.
- Nginx: request processing — выбор server/location и официальный PHP-пример.
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Почему Nginx возвращает 502 Bad Gateway при работе с PHP-FPM?
Обычно Nginx не может подключиться к указанному socket или TCP-порту: служба остановлена, путь не совпадает с версией пула либо права socket не позволяют подключение. Проверяйте оба журнала и фактический listen.
Зачем ставить try_files $uri =404 перед fastcgi_pass?
Проверка не позволяет передавать PHP-FPM произвольный несуществующий путь. Это делает границу выполнения явной и уменьшает риск неверной обработки PATH_INFO или чужих загрузок.
Можно ли направить все запросы сайта прямо в PHP-FPM?
Front controller допустим для фреймворка, но правило должно соответствовать его документации. Статические файлы обычно отдаёт Nginx, а выполнение PHP ограничивается ожидаемой точкой входа и реальными файлами.


