Старт PHP-демона: systemd unit и альтернативы

Раздел: Системное администрирование -> Управление службами

Подходы к запуску PHP как системной службы

Как настроить запуск PHP-FPM через systemd для продакшен-среды?

PHP-FPM (FastCGI Process Manager) является стандартным способом запуска PHP в связке с веб-сервером nginx или apache. Для управления им используется systemd – менеджер служб в современных дистрибутивах Linux. Ниже описан процесс настройки и запуска.

Шаг 1: Установка пакета php-fpm

sudo apt update && sudo apt install php8.1-fpm

Service php start (запуск php-сервиса)

После установки создаётся юнит systemd с именем php8.1-fpm.service (версия может отличаться).

Шаг 2: Проверка статуса и запуск

sudo systemctl status php8.1-fpm
sudo systemctl start php8.1-fpm
sudo systemctl enable php8.1-fpm   # автозапуск при загрузке

Шаг 3: Конфигурация пула – файл /etc/php/8.1/fpm/pool.d/www.conf. Настройки listen, pm (менеджер процессов), max_children и т.д.

listen = /run/php/php8.1-fpm.sock
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

После изменений требуется перезагрузка:

sudo systemctl reload php8.1-fpm

Типичные проблемы:

  • Ошибка "Unit php8.1-fpm.service not found" – не установлен пакет php-fpm или версия не совпадает.
  • Права доступа на сокет – веб-сервер не может подключиться к сокету. Решение: проверить пользователя в конфиге пула (listen.owner, listen.group) и добавить пользователя веб-сервера в группу.
  • Порт уже занят – если используется TCP-порт (listen = 127.0.0.1:9000), убедиться, что порт свободен.

Как запустить встроенный PHP-сервер (php -S) в качестве службы с помощью systemd?

Встроенный сервер подходит для разработки и тестирования, но не рекомендуется для продакшена из-за однопоточности и отсутствия управления процессами.

Создаётся юнит systemd:

[Unit]
Description=PHP built-in web server for MyApp
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
ExecStart=/usr/bin/php -S 0.0.0.0:8080 -t /var/www/myapp
StandardOutput=journal
StandardError=journal
Restart=on-failure

[Install]
WantedBy=multi-user.target

Поместить в /etc/systemd/system/php-builtin.service, затем:

sudo systemctl daemon-reload
sudo systemctl start php-builtin
sudo systemctl status php-builtin

Проблемы:

  • Сервер останавливается при ошибке в приложении – помогает Restart=on-failure.
  • Не поддерживает параллельные запросы – легко приводит к зависанию.
  • Для изменения порта нужно редактировать юнит.

Как использовать init.d скрипт для управления PHP-FPM на старых системах?

В дистрибутивах без systemd (или с совместимостью) применяются скрипты /etc/init.d/. Некоторые пакеты php-fpm содержат такой скрипт.

sudo service php8.1-fpm start
sudo service php8.1-fpm stop
sudo service php8.1-fpm restart

Скрипт можно найти после установки пакета или создать вручную.

Проблемы:

  • На современных системах init.d может быть заменён на systemd-совместимый wrapper.
  • Команда service без скрипта выдаст "unrecognized service".

Как настроить Supervisor для демонизации PHP-скриптов (воркеров очередей)?

Supervisor позволяет управлять долго работающими процессами, автоматически перезапускать их и вести логи. Подходит для воркеров Laravel, Symfony, скриптов обработки данных.

Установка:

sudo apt install supervisor

Создание конфигурации /etc/supervisor/conf.d/php-worker.conf:

[program:php-worker]
command=php /var/www/app/artisan queue:work --sleep=3 --tries=3
process_name=%(program_name)s_%(process_num)02d
numprocs=2
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/php-worker.log

Обновление supervisor и запуск:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start php-worker:*

Проблемы:

  • Ошибка "FATAL Exited too quickly" – скрипт завершается сразу. Проверить команду, пути, окружение.
  • Логи не пишутся – проверить права на директорию /var/log/supervisor.

Как запустить PHP-FPM в контейнере Docker и управлять им как службой?

Использование Docker для изоляции PHP-окружения популярно в микросервисах. Можно управлять контейнером через systemd, docker-compose.

Пример docker-compose.yml:

version: '3'
services:
  php-fpm:
    image: php:8.1-fpm
    volumes:
      - ./app:/var/www/html
    ports:
      - "9000:9000"
    restart: unless-stopped

Запуск: docker-compose up -d. Для интеграции с systemd создаётся юнит, который вызывает docker-compose.

Проблемы:

  • Контейнер не видит файлы – неправильно настроен volume.
  • Порт 9000 занят другим процессом.
  • При ошибках в entrypoint контейнер постоянно перезапускается.

Расширенные примеры настройки PHP службы

Пример 1: Детальная конфигурация пула PHP-FPM

Файл /etc/php/8.1/fpm/pool.d/www.conf может содержать множество параметров для точной настройки. Ниже показаны ключевые директивы с пояснениями.

Пример
; Пример конфигурации пула для высоконагруженного сайта
[www]
user = www-data
group = www-data
listen = /run/php/php8.1-fpm.sock
; Использование сокета вместо TCP для производительности
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Динамическое управление процессами
pm = dynamic
pm.max_children = 100
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 30
; Ограничение времени выполнения запроса
request_terminate_timeout = 300
; Максимальное количество запросов до перезапуска процесса
pm.max_requests = 1000

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

Пример
sudo php-fpm8.1 -t
sudo systemctl reload php8.1-fpm

Результат проверки статуса пулов:

$ sudo systemctl status php8.1-fpm
● php8.1-fpm.service - PHP 8.1 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.1-fpm.service; enabled; vendor preset: enabled)
     Active: active (running) since ...
       Docs: man:php-fpm8.1(8)
   Main PID: 12345 (php-fpm8.1)
     Status: "Processes active: 3, idle: 7, Requests: 23456, slow: 0, Traffic: 0.00req/s"
     Tasks: 12 (limit: 2345)
     Memory: 48.3M
     CGroup: /system.slice/php8.1-fpm.service
             ├─12345 php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)
             ├─12346 php-fpm: pool www
             ├─12347 php-fpm: pool www
             └─12348 php-fpm: pool www

Пример 2: Systemd unit для встроенного сервера с PHP.ini и роутером

Для более гибкого запуска встроенного сервера можно указать путь к php.ini и файл-роутер (router.php).

Пример
[Unit]
Description=PHP Built-in Server for App
After=network.target

[Service]
Type=simple
User=deploy
ExecStart=/usr/bin/php -c /etc/php/8.1/cli/php.ini -S 0.0.0.0:8080 -t /var/www/app /var/www/app/router.php
Restart=always
RestartSec=5
StandardOutput=append:/var/log/php-builtin/access.log
StandardError=append:/var/log/php-builtin/error.log

[Install]
WantedBy=multi-user.target

Создание файла роутера router.php:

Пример
<?
$uri = $_SERVER['REQUEST_URI'];
if (file_exists(__DIR__ . $uri) && !is_dir(__DIR__ . $uri)) {
    return false; // отдавать статические файлы напрямую
}
require __DIR__ . '/index.php';

Запуск и проверка:

Пример
sudo systemctl start php-builtin
curl http://localhost:8080/
sudo systemctl status php-builtin
● php-builtin.service - PHP Built-in Server for App
     Loaded: loaded (/etc/systemd/system/php-builtin.service; enabled; vendor preset: enabled)
     Active: active (running) since ...
   Main PID: 23456 (php)
     Tasks: 1 (limit: 12345)
     Memory: 12.3M
     CGroup: /system.slice/php-builtin.service
             └─23456 /usr/bin/php -c /etc/php/8.1/cli/php.ini -S 0.0.0.0:8080 -t /var/www/app /var/www/app/router.php

Пример 3: Supervisor для нескольких воркеров Laravel с разными параметрами

В конфигурации supervisor можно задать несколько программ с различными настройками.

Пример
[program:laravel-queue-high]
command=php /var/www/app/artisan queue:work --queue=high --sleep=3 --tries=3
process_name=%(program_name)s_%(process_num)s
numprocs=2
autostart=true
autorestart=true
user=forge
stdout_logfile=/var/log/supervisor/queue-high.log

[program:laravel-queue-low]
command=php /var/www/app/artisan queue:work --queue=low --sleep=5 --tries=5
process_name=%(program_name)s_%(process_num)s
numprocs=1
autostart=true
autorestart=true
user=forge
stdout_logfile=/var/log/supervisor/queue-low.log

Перезагрузка конфигурации и проверка статуса:

Пример
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status
laravel-queue-high:laravel-queue-high_00   RUNNING   pid 34567, uptime 0:02:34
laravel-queue-high:laravel-queue-high_01   RUNNING   pid 34568, uptime 0:02:34
laravel-queue-low:laravel-queue-low_00     RUNNING   pid 34569, uptime 0:02:34

Пример 4: Docker Compose стек с PHP-FPM, Nginx, Redis

Полноценный стек для веб-приложения включает nginx как фронтенд и php-fpm для обработки скриптов, а также redis для кеширования.

Пример
version: '3.8'
services:
  php-fpm:
    build:
      context: .
      dockerfile: Dockerfile.php
    volumes:
      - ./src:/var/www/html
    environment:
      - REDIS_HOST=redis
    depends_on:
      - redis
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php-fpm
    restart: unless-stopped

  redis:
    image: redis:alpine
    restart: unless-stopped

volumes:
  src:

Dockerfile.php:

Пример
FROM php:8.1-fpm
RUN docker-php-ext-install pdo_mysql redis
WORKDIR /var/www/html

Запуск стека и проверка:

Пример
docker-compose up -d
docker-compose ps
  Name                 Command               State     Ports
--------------------------------------------------------------
app_nginx_1   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:8080->80/tcp
app_php-fpm_1  docker-php-entrypoint php ...   Up      9000/tcp
app_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp

Пример 5: Init.d скрипт для PHP-FPM (устаревший, для справки)

На старых системах (Debian 7, CentOS 6) использовались скрипты в /etc/init.d/. Ниже приведён сокращённый пример скрипта php-fpm.

Пример
#!/bin/sh
### BEGIN INIT INFO
# Provides:          php-fpm
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: PHP FastCGI Process Manager
# Description:       PHP-FPM is a PHP FastCGI implementation
### END INIT INFO

NAME=php-fpm
DAEMON=/usr/sbin/php-fpm

case "$1" in
  start)
    echo -n "Starting $NAME: "
    $DAEMON && echo "OK" || echo "FAIL"
    ;;
  stop)
    echo -n "Stopping $NAME: "
    killall $NAME && echo "OK" || echo "FAIL"
    ;;
  restart)
    $0 stop
    sleep 2
    $0 start
    ;;
  status)
    status_of_proc $DAEMON $NAME
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac
exit 0

Использование: service php-fpm start. При ошибках следует проверять наличие исполняемого файла и права на его запуск.

Запуск PHP-сервиса - comments

En
Service php start (php)