Running Nginx and PHP-FPM in separate Docker containers is common, but misconfiguration can produce annoying random 502 errors.
Typical symptoms
- Nginx error log shows
upstream prematurely closed connection. - 502s appear under load or when logging a lot.
- Containers look healthy, but the app responds with 502 sporadically.
We’ll look at the usual suspects: Nginx buffers, PHP-FPM logging, and FPM pool limits.
Example docker-compose setup
docker-compose.yml:
services:
nginx:
image: nginx:1.27-alpine
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./:/var/www/html
ports:
- "80:80"
depends_on:
- php
php:
image: php:8.3-fpm-alpine
volumes:
- ./:/var/www/htmlNginx config nginx.conf:
server {
listen 80;
server_name _;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
}Fix 1: Tune Nginx buffer sizes
If your app returns large headers or cookies, default buffers are too small. Add:
http {
sendfile on;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 64k;
client_max_body_size 10m;
}In a single‑file config, wrap your server block in an http block with these settings.
Fix 2: PHP-FPM log_limit and stderr
Older Docker PHP images used a non‑default log_limit which, combined with FPM stderr, triggered issues with Nginx.
In your PHP-FPM config (e.g. /usr/local/etc/php-fpm.d/zz-docker.conf):
[global]
log_limit = 1024
error_log = /proc/self/fd/2
[www]
catch_workers_output = yesIf you see 502s correlated with bursts of PHP notices/warnings, lowering log_limit back to defaults (or at least not setting it excessively high) avoids FPM trying to push huge log chunks over stderr.
Fix 3: FPM pool max_children and timeouts
Open www.conf in the container:
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4
request_terminate_timeout = 60Then rebuild your PHP image with that config.
If pm.max_children is too low, FPM can’t keep up; if it’s too high, memory exhaustion kills workers and causes 502s.
Fix 4: Health checks and slowlog
Add a health endpoint to check PHP-FPM responsiveness:
// public/health.php
http_response_code(200);
echo 'OK';In Nginx:
location = /health {
fastcgi_pass php:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
}Configure an FPM slowly:
[www]
request_slowlog_timeout = 5s
slowlog = /proc/self/fd/2Slowlog entries help you find code paths that consistently break under load.
Common mistakes and fixes
Tuning these three areas removes the majority of “random” 502s in containerized PHP stacks.
Leave a Reply