PHP-FPM (FastCGI Process Manager) ist der Standard für PHP-Ausführung auf Webservern. Die richtige Konfiguration ist entscheidend für Performance und Stabilität.

PHP-FPM Architektur

Prozessmodell

Master-Prozess
    │
    ├── Worker-Prozess 1
    ├── Worker-Prozess 2
    ├── Worker-Prozess 3
    └── Worker-Prozess N

Pool-Konzept

PHP-FPM Master
    │
    ├── Pool: www (default)
    │   └── Worker für allgemeine Websites
    │
    ├── Pool: wordpress
    │   └── Worker speziell für WordPress
    │
    └── Pool: api
        └── Worker für API-Anwendungen

Installation

Debian/Ubuntu

apt install php8.2-fpm

systemctl enable php8.2-fpm
systemctl start php8.2-fpm

Status prüfen

systemctl status php8.2-fpm
php-fpm8.2 -t  # Konfiguration testen

Pool-Konfiguration

Haupt-Pool

; /etc/php/8.2/fpm/pool.d/www.conf

[www]
user = www-data
group = www-data

listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; Process Manager
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500

; Status
pm.status_path = /status
ping.path = /ping
ping.response = pong

; Logging
access.log = /var/log/php8.2-fpm/access.log
slowlog = /var/log/php8.2-fpm/slow.log
request_slowlog_timeout = 5s

; PHP-Einstellungen
php_admin_value[error_log] = /var/log/php8.2-fpm/error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 50M
php_admin_value[post_max_size] = 50M
php_admin_value[max_execution_time] = 60

Process Manager Modi

Dynamic (Empfohlen)

pm = dynamic
pm.max_children = 50      ; Maximale Worker
pm.start_servers = 5      ; Beim Start
pm.min_spare_servers = 5  ; Minimum Idle
pm.max_spare_servers = 35 ; Maximum Idle

Static (Hochlast)

pm = static
pm.max_children = 50      ; Feste Anzahl Worker

Ondemand (Wenig Traffic)

pm = ondemand
pm.max_children = 50
pm.process_idle_timeout = 10s ; Worker beenden nach Idle

Vergleich

| Modus | Vorteile | Nachteile | |-------|----------|-----------| | dynamic | Flexibel, ressourcenschonend | Spawn-Overhead | | static | Keine Spawn-Verzögerung | Mehr RAM | | ondemand | Minimaler RAM-Verbrauch | Spawn bei jedem Request |

Worker-Berechnung

Formel

max_children = (Verfügbarer RAM - Anderer RAM-Bedarf) / Durchschnittlicher PHP-Prozess-RAM

Beispiel:
- Server: 4 GB RAM
- OS + Dienste: 1 GB
- Verfügbar für PHP: 3 GB
- PHP-Prozess: ~50 MB

max_children = 3000 / 50 = 60

RAM pro Prozess ermitteln

# Durchschnittlichen RAM pro Worker
ps aux | grep php-fpm | awk '{sum += $6} END {print sum/NR/1024 " MB"}'

# Detailliert
ps -eo pid,rss,cmd | grep php-fpm | sort -k2 -n

Separate Pools

WordPress-Pool

; /etc/php/8.2/fpm/pool.d/wordpress.conf

[wordpress]
user = www-data
group = www-data

listen = /run/php/php8.2-fpm-wordpress.sock
listen.owner = www-data
listen.group = www-data

pm = dynamic
pm.max_children = 30
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 20
pm.max_requests = 500

php_admin_value[memory_limit] = 512M
php_admin_value[upload_max_filesize] = 100M
php_admin_value[post_max_size] = 100M
php_admin_value[max_execution_time] = 300

; OPcache-Einstellungen
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.max_accelerated_files] = 20000

API-Pool

; /etc/php/8.2/fpm/pool.d/api.conf

[api]
user = www-data
group = www-data

listen = /run/php/php8.2-fpm-api.sock

pm = static
pm.max_children = 20
pm.max_requests = 1000

php_admin_value[memory_limit] = 128M
php_admin_value[max_execution_time] = 30

Nginx-Konfiguration

# WordPress
server {
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm-wordpress.sock;
        include fastcgi_params;
    }
}

# API
server {
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm-api.sock;
        include fastcgi_params;
    }
}

OPcache-Optimierung

Konfiguration

; /etc/php/8.2/fpm/conf.d/10-opcache.ini

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0       ; In Production
opcache.save_comments=1
opcache.enable_file_override=1
opcache.jit_buffer_size=100M
opcache.jit=1255                    ; PHP 8+

OPcache-Status

<?php
// opcache-status.php
print_r(opcache_get_status());
?>

Status-Seite

Aktivieren

; In Pool-Config
pm.status_path = /fpm-status
ping.path = /fpm-ping

Nginx

location = /fpm-status {
    allow 127.0.0.1;
    deny all;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

location = /fpm-ping {
    allow 127.0.0.1;
    deny all;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

Abrufen

curl http://localhost/fpm-status
curl http://localhost/fpm-status?full
curl http://localhost/fpm-status?json

Status-Ausgabe

pool:                 www
process manager:      dynamic
start time:           26/Jan/2026:10:00:00
start since:          3600
accepted conn:        12543
listen queue:         0
max listen queue:     12
listen queue len:     128
idle processes:       5
active processes:     3
total processes:      8
max active processes: 15
max children reached: 0

Slow-Log

Aktivieren

slowlog = /var/log/php8.2-fpm/slow.log
request_slowlog_timeout = 5s
request_slowlog_trace_depth = 20

Auswerten

tail -f /var/log/php8.2-fpm/slow.log

# Häufigste langsame Funktionen
grep -A5 "script_filename" /var/log/php8.2-fpm/slow.log | \
    sort | uniq -c | sort -rn

Memory-Leak-Schutz

; Worker nach X Requests recyclen
pm.max_requests = 500

; Emergency Restart bei zu viel Speicherverbrauch
emergency_restart_threshold = 10
emergency_restart_interval = 1m

; Prozess-Kontrolle
process_control_timeout = 10s

Sicherheit

Einschränkungen

; Gefährliche Funktionen deaktivieren
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen

; Open Basedir
php_admin_value[open_basedir] = /var/www/html:/tmp:/var/lib/php/sessions

; Session-Sicherheit
php_admin_value[session.cookie_secure] = 1
php_admin_value[session.cookie_httponly] = 1

Berechtigungen

# Socket-Berechtigungen
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

# Log-Verzeichnis
mkdir -p /var/log/php8.2-fpm
chown www-data:www-data /var/log/php8.2-fpm

Monitoring

Prometheus-Metriken

# php-fpm_exporter
docker run -d -p 9253:9253 \
    -e PHP_FPM_SCRAPE_URI="unix:///run/php/php-fpm.sock;/fpm-status" \
    hipages/php-fpm_exporter

Nagios/Icinga

#!/bin/bash
# check_php-fpm.sh

ACTIVE=$(curl -s http://localhost/fpm-status | grep "active processes" | awk '{print $3}')
MAX=$(curl -s http://localhost/fpm-status | grep "max active" | awk '{print $4}')

PERCENT=$((ACTIVE * 100 / MAX))

if [ $PERCENT -gt 90 ]; then
    echo "CRITICAL: PHP-FPM $PERCENT% active ($ACTIVE/$MAX)"
    exit 2
elif [ $PERCENT -gt 70 ]; then
    echo "WARNING: PHP-FPM $PERCENT% active ($ACTIVE/$MAX)"
    exit 1
else
    echo "OK: PHP-FPM $PERCENT% active ($ACTIVE/$MAX)"
    exit 0
fi

Zusammenfassung

| Parameter | Empfehlung | |-----------|------------| | pm | dynamic (Standard) | | pm.max_children | RAM / 50MB | | pm.start_servers | max_children / 10 | | pm.max_requests | 500-1000 | | memory_limit | 256M (Apps abhängig) |

| Datei | Funktion | |-------|----------| | /etc/php/8.2/fpm/php-fpm.conf | Globale Config | | /etc/php/8.2/fpm/pool.d/*.conf | Pool-Configs | | /run/php/php8.2-fpm.sock | Socket |

| Befehl | Funktion | |--------|----------| | php-fpm8.2 -t | Config testen | | systemctl reload php8.2-fpm | Reload | | curl /fpm-status | Status abfragen |

Fazit

Die richtige PHP-FPM-Konfiguration ist entscheidend für Webserver-Performance. Die Worker-Anzahl sollte an den verfügbaren RAM angepasst werden. Separate Pools für verschiedene Anwendungen ermöglichen granulare Kontrolle. OPcache beschleunigt PHP erheblich. Die Status-Seite und Slow-Logs helfen bei der Fehlersuche. Regelmäßiges Monitoring verhindert Ressourcenengpässe.