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.