MAATRIX / Блог / Nginx и PHP на РЕД ОС: собираем веб-стек без сюрпризов

Nginx и PHP на РЕД ОС: собираем веб-стек без сюрпризов

MAATRIX

Инструкций «поставь nginx и PHP» в интернете тысячи, но почти все написаны под Ubuntu или Debian — а РЕД ОС из другой семьи, RPM-based и близкой к RHEL, и часть привычных команд там просто не работает. Администратор либо гуглит на ходу методом проб и ошибок, либо переносит чужой мануал один в один и потом полдня разбирается, почему сайт не открывается, хотя все команды вроде бы прошли без ошибок. Разберём сборку связки nginx + PHP-FPM на РЕД ОС так, чтобы репозитории, мандатный контроль доступа и firewalld были предсказуемы заранее, а не всплывали по одному.

Чем РЕД ОС отличается как база для веб-стека

РЕД ОС — российский дистрибутив компании «РЕД СОФТ», построенный на RPM-пакетах и наследующий архитектуру RHEL-семейства: пакетный менеджер dnf, systemd, штатный фаервол firewalld вместо ufw и голого iptables, и подсистема мандатного контроля доступа поверх обычных unix-прав — в родословной RHEL это SELinux. Для Debian-администратора это не косметика, а три места, где типовой Ubuntu-мануал промахивается: другие имена пакетов, другой синтаксис управления портами и дополнительный слой проверки доступа, о котором Debian-администратор часто вовсе не знает.

Второе: РЕД ОС часто выбирают не из личных предпочтений, а потому что дистрибутив входит в реестр отечественного ПО и имеет сертификаты соответствия требованиям регуляторов — критично для госсектора и регулируемых отраслей. Это рамка, в которой принимаются решения: вопрос «поставить ли PHP из стороннего репозитория ради свежей версии» здесь не только про удобство, но и про то, остаётся ли система в границах сертифицированной конфигурации. Похожий принцип — что меняется, когда хостинг-провайдер сам находится в реестре — работает и на уровне отдельного сервера.

Прежде чем ставить пакеты, проверьте, с чем имеете дело — версии и профили установки РЕД ОС отличаются:

cat /etc/os-release
getenforce
firewall-cmd --state

Первая команда покажет версию релиза, вторая и третья — включены ли прямо сейчас мандатный контроль и фаервол. Не полагайтесь на «обычно так»: на защищённых редакциях состояние этих подсистем задаёт политика безопасности организации ещё при установке образа, и оно может отличаться от того, что вы видели на других серверах.

Репозитории: штатные пакеты против сторонних сборок PHP

Первое решение определяет всё остальное — откуда брать пакеты. Посмотреть, что подключено и доступно:

dnf repolist
dnf module list php
dnf info nginx php-fpm

Штатный репозиторий даёт пакеты, собранные и протестированные под вашу версию дистрибутива, в рамках сертифицированной поставщиком конфигурации. Версия nginx и PHP там зафиксирована на момент выхода релиза и обновляется медленно — осознанный компромисс в пользу стабильности. Если dnf module list php показывает несколько потоков с разными версиями PHP — переключайтесь командой dnf module switch-to php:8.х (подставив реально доступный поток из вывода); если модулей нет, доступна ровно одна версия из базового набора.

Сторонний репозиторий вроде тех, что в RHEL-семье традиционно используют ради более свежего PHP, собирается под RHEL, CentOS, AlmaLinux, Rocky Linux — формальной поддержки именно РЕД ОС там обычно нет. Технически пакеты часто ставятся благодаря RPM-совместимости, но это неофициальный путь: разработчик репозитория не тестировал его на вашей системе, и совместимость при следующем обновлении дистрибутива не гарантирована. На сертифицированной инсталляции это может быть вообще неприемлемо — вы выходите за границы аттестованной конфигурации.

Практический вывод: на проде, тем более в организации с требованиями по защите информации, начинайте со штатного репозитория и модульных потоков. К стороннему обращайтесь только когда версии PHP в штатных пакетах физически не хватает — и осознанно, понимая цену. Когда апгрейд версии всё же неизбежен, безопасную методику мы разбирали в статье про переход на новую версию PHP без падения сайта.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Устанавливаем и проверяем Nginx

dnf install -y nginx
systemctl enable --now nginx
systemctl status nginx

В RHEL-семействе, в отличие от Debian, службу принято явно включать в автозагрузку — флаг --now и запускает nginx, и ставит в автозагрузку. Основной конфиг — /etc/nginx/nginx.conf, конфиги сайтов кладут в /etc/nginx/conf.d/*.conf — эта директория уже подключена директивой include.

Проверьте, что сервис поднялся, локально, ещё до открытия портов снаружи:

curl -I http://127.0.0.1
ss -tlnp | grep :80

Если curl локально отдаёт 200 OK, а из браузера снаружи сайт не открывается — проблема почти наверняка не в nginx, а в firewalld (см. ниже). Синтаксис любых правок проверяйте nginx -t, конфигурацию перечитывайте systemctl reload nginx, а не restart — reload не рвёт открытые соединения.

PHP-FPM: установка и связка с Nginx

Nginx сам PHP не исполняет — он проксирует запросы отдельному процессу PHP-FPM через unix-сокет:

dnf install -y php-fpm php-mysqlnd php-mbstring php-xml
systemctl enable --now php-fpm

Набор модулей (php-mysqlnd, php-mbstring, php-gd и так далее) зависит от приложения, список доступных пакетов — dnf search php-. Пул PHP-FPM настраивается в /etc/php-fpm.d/www.conf; там же — от какого пользователя работает пул и по какому адресу слушает, директивы user, group, listen:

grep -E '^(user|group|listen) *=' /etc/php-fpm.d/www.conf

Если listen указывает на unix-сокет (обычно /run/php-fpm/www.sock), пользователь и группа пула должны совпадать с тем, от чьего имени работает nginx — либо пропишите права на сокет через listen.owner/listen.group. Несовпадение здесь — частая причина 502 Bad Gateway, которая выглядит как проблема nginx, хотя дело в правах на сокет между двумя процессами.

Серверный блок nginx — стандартный для всей RHEL-семьи, специфики РЕД ОС в нём уже нет:

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

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Проверьте синтаксис, перечитайте nginx и убедитесь, что PHP реально исполняется, а не отдаётся браузеру как текст:

nginx -t && systemctl reload nginx
echo '<?php phpinfo();' > /var/www/example.ru/public/info.php
curl -s http://127.0.0.1/info.php | head -20

Увидели HTML с версией PHP в выводе — связка работает. Файл info.php сразу удалите: он раскрывает конфигурацию сервера всем, у кого есть доступ к URL.

SELinux и мандатный контроль: почему веб-сервер «не видит» файлы и порты

Если nginx отдаёт 403 Forbidden на файлы с правильными unix-правами, или PHP-FPM не может достучаться до внешнего API — прежде чем снова проверять chmod, проверьте мандатный контроль доступа. В RHEL-совместимых системах, к которым по архитектуре относится и РЕД ОС, это SELinux, и на защищённых редакциях он часто включён в режиме enforcing — но точное состояние смотрите, а не предполагайте: getenforce.

Суть механизма: поверх обычных unix-прав ядро дополнительно сверяет метки безопасности процесса и объекта с политикой — если пара меток не разрешена, доступ блокируется, даже если владелец файла и права выглядят корректно. Механику этого решения и то, почему приложение само не может сообщить причину отказа, мы разбирали в статье как SELinux принимает решение и почему отказ не виден в логах приложения — логика оттуда без изменений применима и здесь.

Два сценария, с которыми веб-стек на РЕД ОС сталкивается почти гарантированно. Нестандартный корень сайта — файлы вне ожидаемого системой каталога (например, на отдельном примонтированном разделе) могут получить неподходящую метку, и nginx откажется их читать при формально верных unix-правах:

semanage fcontext -a -t httpd_sys_content_t "/data/www/example.ru(/.*)?"
restorecon -Rv /data/www/example.ru

Исходящие соединения от PHP-FPM или nginx — если приложение обращается к внешнему API, базе на другом сервере или Redis по сети, а политика такие соединения по умолчанию не разрешает, включите нужный булев переключатель:

setsebool -P httpd_can_network_connect 1

Флаг -P делает изменение постоянным, а не только на текущую сессию. Когда причина отказа неочевидна, смотрите журнал аудита, а не гадайте:

ausearch -m avc -ts recent
sealert -a /var/log/audit/audit.log

Соблазн решить непонятную ошибку доступа командой setenforce 0 понятен: проблема действительно исчезает. Но вместе с ней исчезает весь смысл этого слоя защиты, а на сертифицированной системе это может формально вывести конфигурацию за пределы аттестованной. Почему это плохая идея и что делать вместо — в статье про антипаттерн «отключить SELinux и забыть».

Firewalld: типичные ошибки при открытии портов

Третье место, где новичок в RHEL-семействе теряет время — фаервол. В отличие от некоторых Debian-окружений, где всё изначально открыто, firewalld в RHEL-семье, как правило, уже активен из коробки — задача не «включить защиту», а грамотно настроить разрешённые службы. Проверьте состояние прежде, чем менять:

firewall-cmd --state
firewall-cmd --list-all

Если ssh отсутствует в списке разрешённых — добавьте его в первую очередь, иначе рискуете потерять доступ следующим же действием. Для веб-стека нужны минимум http и https:

firewall-cmd --permanent --add-service=http --add-service=https
firewall-cmd --reload

Здесь и главная ошибка первой настройки: у firewalld два независимых набора правил — временный (runtime) и постоянный (permanent). Команда без --permanent действует до перезагрузки или до --reload и потом исчезает; команда с флагом сохраняется, но применяется не сразу. Забыли --permanent — правило пропадёт после перезагрузки в неподходящий момент. Забыли --reload — правило прописано, но фактически ещё не действует.

Другая типичная грабля — открыть 80-й порт и забыть про 443-й, а потом долго искать, почему HTTPS не грузится при рабочем HTTP. Проверяйте список после каждого изменения, а не полагайтесь на память:

firewall-cmd --list-services

Служебные порты — панели администрирования, базы данных — открывать всему интернету не стоит; для точечного доступа используйте богатые правила с указанием источника:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="3306" protocol="tcp" accept'
firewall-cmd --reload

Подробный разбор firewalld — зоны, службы, permanent/runtime — есть в статье про настройку фаервола с нуля в RHEL-семействе; архитектура в РЕД ОС не отличается от описанной там принципиально. А если правило применили неудачно и потеряли SSH — читайте про восстановление доступа через консоль хостинг-провайдера: она не проходит через сетевой стек ОС и работает, даже когда firewalld закрыл SSH наглухо.

Чеклист развёртывания веб-стека на РЕД ОС

ШагЧто сделатьЧем проверить
1Определить версию системы и статус защитных подсистемcat /etc/os-release, getenforce, firewall-cmd --state
2Выбрать источник пакетов: штатный репозиторий или стороннийdnf repolist, dnf module list php
3Установить и включить nginxdnf install nginx, systemctl enable --now nginx
4Проверить nginx локально, до открытия портов снаружиcurl -I http://127.0.0.1
5Установить PHP-FPM и нужные модулиdnf install php-fpm php-mysqlnd ...
6Свести пользователя пула PHP-FPM и владельца сокетаgrep listen /etc/php-fpm.d/www.conf
7Прописать серверный блок nginx с fastcgi_passnginx -t && systemctl reload nginx
8Проверить исполнение PHP тестовым файлом и удалить егоcurl .../info.php, затем rm
9Назначить корректные метки SELinux нестандартным каталогамsemanage fcontext, restorecon -Rv
10Включить нужные булевы переключатели для сетевых соединенийsetsebool -P httpd_can_network_connect 1
11Открыть в firewalld только нужные службы, с --permanent и --reloadfirewall-cmd --list-all
12Разобрать «непонятную» ошибку доступа через аудит, а не отключением защитыausearch -m avc -ts recent

Пункты 9, 10 и 11 — не разовые действия «сделал и забыл»: возвращайтесь к ним при каждом новом сайте с нестандартным расположением файлов, новом сервисе с исходящими соединениями или новом открытом порте. Стек, собранный по этому списку один раз правильно, в большинстве случаев не требует повторной раскопки причин «сайт не открывается» — вы заранее знаете три места, где обычно прячется проблема.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли ставить nginx и PHP из репозиториев, собранных под CentOS или AlmaLinux, если под РЕД ОС отдельного репозитория нет?

Технически RPM-пакеты часто ставятся благодаря архитектурной совместимости, но это неофициальный путь без гарантий на будущих обновлениях. На проде, тем более при требованиях по защите информации, начинайте со штатных пакетов и переходите на сторонний источник только по чёткой необходимости.

SELinux в РЕД ОС включён по умолчанию?

Зависит от редакции, версии и профиля установки — проверьте getenforce на конкретном сервере, не полагайтесь на предположение. Если Enforcing, любая «необъяснимая» ошибка доступа при верных unix-правах — повод сначала посмотреть ausearch -m avc, а не снова менять права файлов.

Почему сайт отдаёт 502 Bad Gateway сразу после установки PHP-FPM?

Чаще всего — несовпадение пути к сокету в fastcgi_pass и в listen пула PHP-FPM, либо разные пользователи двух процессов, из-за чего у nginx нет прав на сокет. Проверьте оба конфига и systemctl status php-fpm.

Нужно ли открывать порт PHP-FPM в firewalld?

Нет, если nginx и PHP-FPM на одном сервере общаются через unix-сокет — это внутреннее взаимодействие процессов. Порт нужен только для того, что реально принимает внешние подключения: http/https и SSH.

Что делать, если сайт всё равно недоступен снаружи, хотя изнутри всё работает?

Идите по порядку: curl -I http://127.0.0.1 на самом сервере, затем firewall-cmd --list-all, затем проверка фильтрации на уровне провайдера или облака — иногда она стоит ещё до операционной системы, на уровне гипервизора, и внутри ОС её не видно вовсе.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →