nginx + PHP-FPM Production Config
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). The listed tools nginxconfig.io and mozilla-ssl-config can audit some configuration patterns, but the critical misconfigurations — pm.max_children set too high, missing fastcgi_read_timeout, missing pm.max_requests — are not flagged by syntax checkers or default linters. RAM exhaustion and worker swapping only manifest under real production load, making these largely invisible until users hit timeouts or slowdowns.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix shows a single-line fastcgi_pass and SCRIPT_FILENAME fix, but correct remediation spans nginx server blocks, PHP-FPM pool configuration files (pm.max_children, pm.max_requests), php.ini overrides, and timeout settings across both nginx and PHP-FPM. This is multi-file coordination within one component tier, not a one-liner swap.
Closest to 'persistent productivity tax' (b5). The configuration applies only to web PHP contexts but is foundational to the entire web stack's performance behaviour. Any future changes to application load, adding virtual hosts, or scaling workers must revisit these settings. It's a persistent operational tax that shapes capacity planning and incident response, though it doesn't redefine the whole system architecture.
Closest to 'serious trap' (t7). The canonical misconception — 'more PHP-FPM workers always means better performance' — directly contradicts the intuition that more concurrency capacity equals better throughput. This is a documented gotcha that contradicts how horizontal scaling works in other contexts (threads, processes) where adding more workers typically helps. Developers coming from other stacks will reliably guess wrong, setting pm.max_children too high and causing swap-induced collapse under load.
Also Known As
TL;DR
Explanation
nginx as a reverse proxy in front of PHP-FPM provides: serving static files directly (no PHP overhead), buffering slow client uploads before passing to FPM (protecting worker count), SSL termination, gzip compression, and security headers. PHP-FPM pool configuration controls worker count, memory limits, and request timeouts. Key settings: pm.max_children (max concurrent PHP processes), pm.max_requests (restart workers after N requests to prevent memory leaks), fastcgi_read_timeout (PHP execution time limit in nginx).
Common Misconception
Why It Matters
Common Mistakes
- pm.max_children set too high — workers exceed available RAM, causing swap and severe slowdowns.
- No fastcgi_read_timeout — nginx kills long-running PHP processes before they complete.
- Not setting PHP-FPM pm.max_requests — workers accumulate memory leaks without restarts.
- Missing fastcgi_param PHP_VALUE to override php.ini per virtual host.
Code Examples
# Minimal nginx config — missing critical settings:
server {
listen 80;
root /var/www/html;
index index.php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# No timeout, no buffering, no security headers
}
}
; php-fpm.conf — no limits:
pm = dynamic
pm.max_children = 50 ; May exceed available RAM
# Production nginx config:
server {
listen 443 ssl http2;
root /var/www/html/public;
# Serve static files directly:
location ~* \.(css|js|png|jpg|woff2)$ {
expires 1y; add_header Cache-Control 'public, immutable';
}
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_read_timeout 30;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
}
}
; php-fpm pool.conf:
pm = dynamic
pm.max_children = 20 ; RAM / ~50MB per worker
pm.max_requests = 500 ; Restart after 500 requests
Tags
Edits history 1 edit
- bad_code PF Media Bot Claude Opus 4.5 · 28 Apr 2026