Держать несколько версий PHP на одном сервере сегодня просто. Каждая версия ставится отдельным пакетом и запускает свой сервис PHP-FPM со своим сокетом. Веб-сервер для каждого сайта передаёт PHP-запросы в нужный сокет. Так один сайт работает на PHP 8.4, а старый движок рядом живёт на 8.2, и они друг другу не мешают.
Самый частый рецепт такой. На Debian подключаем репозиторий Ондржея Сури (packages.sury.org), на Ubuntu — его PPA ppa:ondrej/php, на AlmaLinux и Rocky Linux — репозиторий Remi. Ставим пакеты php8.x-fpm (или php84-php-fpm на AlmaLinux), создаём для сайта отдельный пул от отдельного пользователя и прописываем путь к сокету в Nginx (fastcgi_pass) или в Apache (SetHandler "proxy:unix:...").
Статья заменяет две старые заметки 2012–2017 годов: про установку PHP 5.4 на CentOS 5/6 из Remi и Atomic и про запуск PHP через mod_fcgid. Те инструкции больше не работают, а сами версии давно без поддержки. Ниже — как то же самое делается на Debian 12 и 13, Ubuntu 24.04 и AlmaLinux / Rocky Linux 9 и 10.
Какие версии PHP есть в дистрибутивах
У каждой системы своя версия PHP «из коробки». Если она подходит всем сайтам, сторонний репозиторий не нужен. Он нужен, когда одному сайту требуется версия новее, а другому — старше системной.
| Система | PHP из основного репозитория | Откуда брать другие версии | Имя сервиса FPM |
|---|---|---|---|
| Debian 12 (bookworm) | 8.2 | packages.sury.org/php | php8.2-fpm, php8.4-fpm и т. д. |
| Debian 13 (trixie) | 8.4 | packages.sury.org/php | php8.4-fpm и т. д. |
| Ubuntu 24.04 LTS | 8.3 | ppa:ondrej/php | php8.3-fpm и т. д. |
| AlmaLinux / Rocky 9 | 8.0, новее — потоки модуля php в AppStream | Remi (rpms.remirepo.net) | php-fpm (системная), php84-php-fpm (параллельная) |
| AlmaLinux / Rocky 10 | 8.3 | Remi | php-fpm, php84-php-fpm |
Поддерживаемые ветки PHP на октябрь 2026 года: 8.2 (только исправления безопасности до конца 2026), 8.3, 8.4 и 8.5. Всё, что старше 8.2, уже не получает исправлений. Актуальные сроки смотрите на странице php.net/supported-versions. Старую версию держите только как временную меру, пока сайт не обновят.
Почему PHP-FPM, а не mod_php и не старый FastCGI
В старой статье PHP подключали к Apache через mod_fcgid, а ещё раньше — модулем mod_php. Сейчас стандарт — PHP-FPM. Причины практические:
- Несколько версий. mod_php загружает в Apache одну версию PHP на весь сервер. С FPM каждая версия — отдельный сервис.
- Разные пользователи. С mod_php все сайты выполняются от пользователя Apache (
www-dataилиapache). Взлом одного сайта даёт доступ к файлам остальных. В FPM у каждого пула свой пользователь. - MPM event. mod_php требует MPM prefork: один процесс Apache на соединение, и в каждом процессе висит PHP. С FPM Apache работает в режиме event и отдаёт статику, не тратя память на PHP.
- Управление процессами. FPM сам держит пул воркеров, перезапускает их после
pm.max_requests, пишет slow-log и статус. mod_fcgid тоже работает, но процессы им запускает Apache, и настройки пулов там беднее. Модуль mod_fastcgi давно заброшен.
Совет из старой статьи закомментировать session.save_path в php.ini больше не нужен. С FPM путь к сессиям задаётся в настройках пула, отдельно для каждого сайта (см. ниже).
Debian 12 и 13: репозиторий Sury
Ондржей Сури — сопровождающий пакетов PHP в Debian. Его репозиторий собран так же, как штатные пакеты, и содержит все поддерживаемые ветки PHP. Подключаем его по инструкции из README репозитория:
apt update
apt install -y lsb-release ca-certificates curl
curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
dpkg -i /tmp/debsuryorg-archive-keyring.deb
echo "deb [signed-by=/usr/share/keyrings/debsuryorg-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
apt update
Ставим нужные версии. Расширения у каждой версии свои, их нужно ставить для каждой версии отдельно:
apt install php8.4-fpm php8.4-cli php8.4-mysql php8.4-curl php8.4-gd php8.4-mbstring php8.4-xml php8.4-zip php8.4-intl
apt install php8.2-fpm php8.2-cli php8.2-mysql php8.2-curl php8.2-gd php8.2-mbstring php8.2-xml php8.2-zip php8.2-intl
Не ставьте пакеты без номера версии вроде php-redis или php-mysql, если версий несколько. Это метапакеты: они тянут расширение только для версии по умолчанию. Нужно php8.2-redis, php8.4-redis и так далее.
Где что лежит у версии 8.4 (для других версий меняется только номер):
| Что | Путь |
|---|---|
| php.ini для FPM | /etc/php/8.4/fpm/php.ini |
| php.ini для консоли | /etc/php/8.4/cli/php.ini |
| Пулы | /etc/php/8.4/fpm/pool.d/*.conf |
| Сокет пула www | /run/php/php8.4-fpm.sock |
| Ini-файлы расширений | /etc/php/8.4/mods-available/, включаются через phpenmod |
| Сервис | php8.4-fpm.service |
Ubuntu 24.04: PPA ondrej/php
Для Ubuntu тот же автор ведёт PPA. Он поддерживает только LTS-выпуски, 24.04 в их числе:
apt install -y software-properties-common
add-apt-repository ppa:ondrej/php
apt update
apt install php8.4-fpm php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml
Пути и имена сервисов те же, что в Debian. Системная версия на 24.04 — 8.3. После подключения PPA она тоже начнёт обновляться из PPA, это нормально.
AlmaLinux и Rocky Linux 9 и 10: репозиторий Remi
Remi Collet сопровождает PHP в Fedora и RHEL. Его репозиторий — то, что в старой статье подключали по адресу rpms.famillecollet.com. Подробно про EPEL и Remi — в статье Репозитории EPEL и Remi для AlmaLinux и Rocky Linux. Коротко для AlmaLinux 9:
dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
crb install
Для версии 10 замените в обеих ссылках 9 на 10. Команда crb install появляется вместе с пакетом epel-release и включает репозиторий CRB.
Дальше есть два пути. Remi предлагает их в мастере настройки.
Одна версия вместо системной
Если на сервере нужна одна версия, но новее штатной, переключаем модуль php на поток Remi. Пакеты сохраняют обычные имена и пути:
dnf module switch-to php:remi-8.4/common
dnf install php-fpm php-cli php-mysqlnd php-mbstring php-xml php-intl
systemctl enable --now php-fpm
Конфиги: /etc/php.ini, /etc/php.d/, пулы в /etc/php-fpm.d/, сокет пула www — /run/php-fpm/www.sock.
Несколько версий параллельно
Для параллельной установки Remi собирает версии как Software Collections: у пакетов префикс php82-, php84- и так далее. Они лежат в репозитории remi-safe, который включён сразу после установки remi-release. Системный PHP при этом не трогается.
dnf install php84 php84-php-fpm php84-php-mysqlnd php84-php-mbstring php84-php-xml
dnf install php82 php82-php-fpm php82-php-mysqlnd php82-php-mbstring php82-php-xml
systemctl enable --now php84-php-fpm php82-php-fpm
| Что | Путь для php84 |
|---|---|
| php.ini | /etc/opt/remi/php84/php.ini |
| Ini-файлы расширений | /etc/opt/remi/php84/php.d/ |
| Пулы | /etc/opt/remi/php84/php-fpm.d/*.conf |
| Сокет пула www | /var/opt/remi/php84/run/php-fpm/www.sock |
| Консольный PHP | /usr/bin/php84 |
| Сервис | php84-php-fpm.service |
На AlmaLinux включён SELinux, и выключать его не нужно. Сокеты в штатных каталогах уже имеют правильный контекст. Если веб-сервер не может подключиться к сокету или прочитать файлы сайта, смотрите отказы командой ausearch -m avc -ts recent и правьте контекст через semanage fcontext и restorecon. Типичный случай — сайт в /home или /srv без контекста httpd_sys_content_t.
Пулы PHP-FPM: отдельный пользователь на каждый сайт
Пул — группа процессов FPM со своими настройками: пользователь, сокет, лимиты, значения php.ini. Один сайт — один пул. Тогда сайт работает от своего пользователя, а его падение или зависание не трогает соседей.
Создаём пользователя без входа в систему и каталог сайта:
useradd --system --home-dir /var/www/site1 --shell /usr/sbin/nologin site1
mkdir -p /var/www/site1/public /var/www/site1/tmp /var/www/site1/sessions
chown -R site1:site1 /var/www/site1
Файл пула на Debian и Ubuntu — /etc/php/8.4/fpm/pool.d/site1.conf:
[site1]
user = site1
group = site1
listen = /run/php/php8.4-fpm-site1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
pm.max_requests = 500
php_admin_value[open_basedir] = /var/www/site1:/usr/share/php
php_admin_value[upload_tmp_dir] = /var/www/site1/tmp
php_admin_value[sys_temp_dir] = /var/www/site1/tmp
php_admin_value[session.save_path] = /var/www/site1/sessions
php_admin_value[error_log] = /var/www/site1/php-error.log
php_admin_flag[log_errors] = on
Что здесь важно:
userиgroup— от кого выполняется PHP-код сайта.listen.owner,listen.group,listen.mode— кто может писать в сокет. Веб-сервер должен иметь доступ, остальные — нет. Для Nginx на Debian это тожеwww-data.pm = ondemandподходит для небольших сайтов: процессы стартуют по запросу и гаснут при простое. Для нагруженного сайта беритеpm = dynamicи подбирайтеpm.max_childrenпо памяти: средний размер процесса PHP, умноженный на число процессов, должен помещаться в RAM с запасом.php_admin_valueзадаёт значения, которые сайт не может переопределить черезini_set().
На AlmaLinux пул кладут в /etc/php-fpm.d/site1.conf (системный PHP) или в /etc/opt/remi/php84/php-fpm.d/site1.conf (параллельная версия). Вместо listen.owner там принято использовать ACL: в штатном www.conf стоит listen.acl_users = apache,nginx. Скопируйте эту строку в свой пул, а сокет разместите рядом со штатным, например /run/php-fpm/site1.sock.
Штатный пул www можно оставить или удалить. FPM не запустится, если в каталоге пулов не останется ни одного пула.
Проверяем конфиг и перезапускаем:
php-fpm8.4 -t
systemctl restart php8.4-fpm
ls -l /run/php/
На AlmaLinux проверка — php-fpm -t для системной версии. Для php84 проще перезапустить сервис и посмотреть systemctl status php84-php-fpm: при ошибке в конфиге там будет строка с номером.
Nginx: выбор версии PHP для сайта
Версию определяет путь к сокету в fastcgi_pass. На Debian и Ubuntu есть готовый сниппет snippets/fastcgi-php.conf:
server {
listen 80;
server_name site1.example.ru;
root /var/www/site1/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm-site1.sock;
}
}
Второй сайт на PHP 8.2 отличается только сокетом: unix:/run/php/php8.2-fpm-site2.sock. Чтобы перевести сайт на другую версию, создайте пул в каталоге новой версии, поменяйте fastcgi_pass и перезагрузите Nginx.
На AlmaLinux сниппета нет. Пишем блок вручную:
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/opt/remi/php84/run/php-fpm/site1.sock;
}
Пакет php-fpm на AlmaLinux добавляет в Nginx файлы /etc/nginx/conf.d/php-fpm.conf и /etc/nginx/default.d/php.conf. Они направляют PHP сайта по умолчанию в системный сокет. Для своих виртуальных хостов они не мешают, но помните о них, если PHP вдруг выполняется не той версией. Подробности директив — в документации модуля ngx_http_fastcgi_module.
nginx -t && systemctl reload nginx
Apache 2.4: связка через proxy_fcgi
Apache передаёт запросы в FPM модулем mod_proxy_fcgi. Отдельные модули вроде mod_fcgid для этого не нужны.
Debian и Ubuntu
Если раньше стоял mod_php, отключаем его и prefork, включаем event и proxy_fcgi:
a2dismod php8.2 mpm_prefork
a2enmod mpm_event proxy_fcgi setenvif
a2enconf php8.4-fpm
apachectl configtest && systemctl restart apache2
Команда a2enconf php8.4-fpm включает файл из пакета FPM. Он направляет все .php в сокет пула www этой версии — это версия по умолчанию для сервера. Сайту с другой версией или своим пулом указываем сокет в виртуальном хосте:
<VirtualHost *:80>
ServerName site2.example.ru
DocumentRoot /var/www/site2/public
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php/php8.2-fpm-site2.sock|fcgi://localhost"
</FilesMatch>
<Directory /var/www/site2/public>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Блок FilesMatch внутри виртуального хоста перекрывает глобальный. Файлы .htaccess продолжают работать: их читает Apache. А вот директивы php_value в .htaccess с FPM не работают и вызывают ошибку 500. Переносите их в пул (php_admin_value) или в файл .user.ini в корне сайта.
AlmaLinux и Rocky Linux
Здесь Apache уже по умолчанию работает в режиме event и отдаёт PHP в FPM. Это задаёт файл /etc/httpd/conf.d/php.conf из пакета php: в нём SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost". Для сайта на версии Remi указываем её сокет в виртуальном хосте так же, как выше:
<FilesMatch "\.php$">
SetHandler "proxy:unix:/var/opt/remi/php82/run/php-fpm/site2.sock|fcgi://localhost"
</FilesMatch>
apachectl configtest && systemctl reload httpd
Версия PHP в консоли: update-alternatives и cron
Веб-версию выбирает сокет, а консольную — команда php. На Debian и Ubuntu это ссылка через систему alternatives. Посмотреть и переключить:
update-alternatives --display php
update-alternatives --set php /usr/bin/php8.4
php -v
Интерактивно то же делает update-alternatives --config php. Если ставите пакеты для сборки расширений, переключите заодно phpize и php-config.
Есть подвох. В автоматическом режиме alternatives выбирает самую новую версию. Поставили php8.5 для теста — и все cron-задачи с php внезапно пошли на 8.5. Команда --set переводит ссылку в ручной режим, и такого не случится. Ещё надёжнее — писать в задачах полный путь к нужной версии. Пример файла /etc/cron.d/site1 (в этом формате есть поле с именем пользователя):
*/5 * * * * site1 /usr/bin/php8.4 /var/www/site1/public/wp-cron.php > /dev/null 2>&1
На AlmaLinux команда php — это системная версия (или выбранный поток модуля). Параллельные версии вызываются как php82, php84. Для Composer и WP-CLI запускайте их нужной версией явно: php84 /usr/local/bin/composer install.
Проверка результата
- Сервисы запущены:
systemctl status php8.4-fpm php8.2-fpm(на AlmaLinux —php84-php-fpm). - Сокеты на месте и с нужными правами:
ls -l /run/php/. Примерно так:srw-rw---- 1 www-data www-data 0 ... php8.4-fpm-site1.sock. - Процессы работают от пользователя сайта:
ps -eo user,args | grep "[p]ool site1". Должны быть строки видаsite1 php-fpm: pool site1. - Сайт отвечает нужной версией. Создайте временный файл и сразу удалите после проверки:
echo '<?php echo PHP_VERSION, " ", get_current_user(), "\n";' > /var/www/site1/public/v.php
curl -s http://site1.example.ru/v.php
rm /var/www/site1/public/v.php
Ответ примерно такой: 8.4.x site1. Не оставляйте на сайте phpinfo(): он раскрывает пути, версии и переменные окружения.
Типичные проблемы
| Симптом | Причина | Решение |
|---|---|---|
Nginx: 502 Bad Gateway, в логе connect() to unix:... failed (2: No such file or directory) | Пул не запущен или путь к сокету с опечаткой | systemctl status php8.x-fpm, сверить listen в пуле и fastcgi_pass |
Nginx: 502, в логе (13: Permission denied) | У веб-сервера нет прав на сокет | Поправить listen.owner/listen.group или listen.acl_users; на AlmaLinux проверить SELinux |
Apache: 503 Service Unavailable, в логе attempt to connect to Unix domain socket ... failed | То же: сокета нет или нет прав | Как выше; проверить путь в SetHandler |
Primary script unknown / «File not found.» | Неверный SCRIPT_FILENAME или root; пользователь пула не может прочитать файлы; open_basedir | Проверить root и права на каталог сайта для пользователя пула |
| Сайт показывает не ту версию PHP | Срабатывает глобальный обработчик (a2enconf, default.d/php.conf), а не блок виртуального хоста | Проверить, какой SetHandler или location применяется к сайту |
Ошибки сессий: Permission denied в session_start() | Пул от нового пользователя пишет в общий каталог сессий | Задать session.save_path в пуле на каталог сайта |
| Ошибка 500 после перехода с mod_php | php_value или php_flag в .htaccess | Перенести настройки в пул или .user.ini |
PHP Startup: Unable to load dynamic library | Расширение не поставлено для этой версии или ini ссылается на чужой модуль | См. статью PHP Startup: Unable to load dynamic library — как найти и исправить |
Как убрать старую версию
Когда последний сайт переехал на новую версию, старую лучше удалить: она перестаёт получать исправления безопасности. Сначала убедитесь, что её сокеты никто не использует:
grep -rn "php8.2" /etc/nginx /etc/apache2 /etc/cron* /var/spool/cron 2>/dev/null
apt purge 'php8.2-*'
apt autoremove
На AlmaLinux — dnf remove 'php82-*'. Перед удалением сохраните свои пулы и правки php.ini: при purge каталог /etc/php/8.2 удаляется вместе с ними.
Если сервер готовите под WordPress, дальнейшую настройку (кэш, OPcache, базу) смотрите в статье Настройка VPS для быстрой работы сайта WordPress.
Частые вопросы
Безопасно ли подключать репозиторий Sury или Remi на рабочий сервер?
Оба репозитория ведут люди, которые сопровождают PHP в самих дистрибутивах: Ондржей Сури — в Debian, Remi Collet — в Fedora и RHEL. Пакеты подписаны, обновления выходят быстро. Но это всё же сторонний источник: вы доверяете его ключу. Подключайте только официальные адреса packages.sury.org, ppa:ondrej/php и rpms.remirepo.net, не берите копии с зеркал и сайтов-инструкций.
Сколько версий PHP можно держать одновременно?
Технических ограничений нет: каждая версия — отдельный сервис. Ограничивает память. Каждый запущенный пул держит процессы, поэтому для редко используемых сайтов ставьте pm = ondemand. На практике хватает двух версий: текущей для всех сайтов и предыдущей для тех, что ещё не обновили.
Можно ли переключить версию PHP для сайта без простоя?
Да. Создайте пул сайта в каталоге новой версии, запустите или перезагрузите её FPM, проверьте, что сокет появился. Затем поменяйте сокет в конфиге сайта и выполните systemctl reload nginx или systemctl reload apache2. Перезагрузка конфигурации не обрывает текущие соединения. Если что-то пошло не так, верните старый сокет так же быстро.
Почему php -v показывает одну версию, а сайт работает на другой?
Это нормально. Консольный PHP выбирается ссылкой /usr/bin/php через update-alternatives, а сайт — сокетом в конфиге веб-сервера. Они не связаны. Для задач cron и консольных утилит сайта указывайте полный путь к нужной версии, например /usr/bin/php8.2 или php82 на AlmaLinux.
Нужен ли mod_fcgid или suPHP, чтобы сайты работали от разных пользователей?
Нет. В PHP-FPM это делает параметр user в пуле. suPHP давно не развивается, mod_fcgid можно встретить на старых серверах, но новые установки делают на FPM. Если на сервере ещё работает mod_fcgid, переводите сайты на пулы FPM по одному и затем отключайте модуль.
Как узнать, какие расширения стоят у каждой версии?
Выполните php8.2 -m и php8.4 -m на Debian и Ubuntu или php82 -m и php84 -m на AlmaLinux. Сравните списки перед переездом сайта на новую версию. Учтите, что у консоли и FPM могут быть разные ini-файлы, поэтому окончательную проверку делайте временным скриптом через сайт.