Nginx 웹 서버와 PHP-FPM을 연동해 서비스를 운영하다 보면 어느 날 갑자기 브라우저에 502 Bad Gateway 에러가 발생하는 상황을 한 번쯤 경험해봤을 것이다.
다만 서버가 그냥 다운된 것인지, Nginx 설정 문제인지, 아니면 PHP 프로세스 메모리 초과 때문인지 정확한 원인이나 해결책을 모른 채 Nginx나 PHP 서비스만 무작정 재시작하는 경우가 많다.
이번에는 Nginx와 PHP-FPM 간에 502 에러가 발생하는 정확한 원인이 무엇인지, 왜 설정 최적화가 필요한지, 그리고 실무에서 해결하는 구체적인 설정 방법을 완벽하게 정리해서 소개하겠다.
502 Bad Gateway 에러는 게이트웨이 또는 프록시 역할을 하는 웹 서버(Nginx)가 상류(Upstream) 서버인 FastCGI 프로세스(PHP-FPM)로부터 유효하지 않은 응답을 받았을 때 발생하는 HTTP 상태 코드다.
즉, Nginx 자체는 정상적으로 요청을 받았으나 뒤에서 PHP 코드를 실행하여 결과를 전달해 주어야 하는 PHP-FPM 프로세스가 응답을 거부하거나 도중에 꺼져버린 경우다.
| 원인 유형 | 발생 상황 | Nginx 에러 로그 메시지 특징 |
|---|---|---|
| 프로세스 미동작/소켓 미연결 | PHP-FPM 서비스가 중단되었거나 소켓 경로 불일치 | connect() to unix:/var/run/php-fpm.sock failed (2: No such file or directory) |
| 타임아웃(Timeout) 발생 | 복잡한 쿼리나 대용량 작업으로 execution time 초과 | upstream timed out (110: Connection timed out) while reading response header |
| 자원 부족 및 OOM Kill | 메모리 부족으로 PHP-FPM 자식 프로세스가 강제 종료됨 | recv() failed (104: Connection reset by peer) while reading response header |
| 버퍼 크기 초과 | PHP 응답 헤더나 바디 크기가 Nginx fastcgi buffer 초과 | upstream sent too big header / response while reading response header |
502 에러를 해결하기 위해서는 가장 먼저 Nginx 에러 로그(/var/log/nginx/error.log)와 PHP-FPM 로그(/var/log/php-fpm/www-error.log)를 확인하여 정확한 원인을 파악해야 한다.
Nginx와 PHP-FPM이 Unix Socket 방식으로 통신할 때, 소켓 파일의 생성 위치나 파일 읽기/쓰기 권한이 맞지 않으면 502 에러가 발생한다.
PHP 작업이 오랫동안 실행될 때 Nginx가 설정된 시간 동안 응답을 기다리지 못하고 먼저 연결을 끊어버리는 경우다. Nginx의 fastcgi_read_timeout과 PHP의 max_execution_time을 맞춰주어야 한다.
동시 접속자가 갑자기 몰릴 때 사용 가능한 PHP-FPM 워커 프로세스가 부족하면 요청이 대기열에 쌓이다가 502 에러로 떨어진다. 서버 메모리 용량에 맞춰 적절한 프로세스 개수를 할당해야 한다.
실무 환경에서 흔히 발생하는 502 에러를 방지하기 위한 Nginx VirtualHost 설정과 PHP-FPM 풀(pool) 설정 방법이다.
1) Nginx vhost 설정 (nginx.conf 또는 conf.d/site.conf)
✗ 잘못된 설정 (기본 타임아웃과 버퍼 설정 미비로 고용량/장시간 처리 시 502 발생)
location ~ .php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
# 타임아웃 및 버퍼 설정이 없어 기본값(60초) 적용 및 대형 헤더 전송 시 502 발생
}✓ 올바른 설정 (타임아웃과 FastCGI 버퍼를 최적화하여 502 방지)
location ~ .php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 타임아웃 증대 (60초 -> 300초)
fastcgi_read_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_connect_timeout 60s;
# 버퍼 사이즈 확장 (대용량 응답 헤더 처리)
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}2) PHP-FPM Pool 설정 (/etc/php-fpm.d/www.conf)
✗ 잘못된 설정 (메모리에 대한 고려 없이 static 모드로 너무 적거나 과도한 프로세스 지정)
pm = static
pm.max_children = 5
; 동시 요청이 5개를 초과하면 나머지 요청은 대기하다 502 에러 발생
listen.owner = nobody
listen.group = nobody
; 권한 설정 미비로 nginx 사용자가 소켓에 접근 불가
✓ 올바른 설정 (dynamic 모드 적용 및 권한 명시)
; Nginx 실행 계정과 동일하게 맞춰 소켓 접근 권한 부여
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
; 자원 사용량에 따라 프로세스를 가변적으로 관리
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
; max_requests 설정을 통해 주기적으로 워커를 재시작하여 메모리 누수 방지3) 설정 적용 후 검증 명령
# Nginx 문법 검사 및 재시작
$ sudo nginx -t
$ sudo systemctl restart nginx
# PHP-FPM 문법 검사 및 재시작
$ sudo php-fpm -t
$ sudo systemctl restart php-fpm출력 결과 예시:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
NOTICE: configuration file /etc/php-fpm.conf test is successful
✗ Nginx 타임아웃만 늘리고 php.ini 설정을 그대로 두는 실수
Nginx의 fastcgi_read_timeout을 300초로 늘렸더라도, php.ini의 max_execution_time이 30초로 되어 있다면 PHP 프로세스가 30초 만에 종료되어 502 에러가 발생한다. 두 설정값의 균형을 맞춰야 한다.
✓ PHP-FPM 메모리 누수 방지를 위한 pm.max_requests 설정
PHP 애플리케이션 내에서 메모리 누수(Memory Leak)가 발생하는 경우 워커 프로세스가 점차 많은 메모리를 차지하다가 OS의 OOM Killer에 의해 강제 종료된다. pm.max_requests = 500 정도로 설정하면 워커 프로세스가 500번의 요청을 처리한 후 자동으로 재시작되어 메모리가 깔끔하게 비워진다.
PHP-FPM 502 Bad Gateway 에러 해결은 웹 서버와 백엔드 프로세스 간의 통신 안정성을 확보하는 핵심 작업이다. 프로세스 개수와 타임아웃을 튜닝하는 작은 최적화와 습관이 모여서 고부하 상황에서도 무중단 서비스를 유지하는 큰 효과를 만든다는 점을 잊지 말자. 이 글의 Nginx FastCGI 버퍼 설정과 PHP-FPM pm.max_children 튜닝 부분을 참고해 서버 설정을 재점검하면, 502 에러 없는 안정적인 웹 서비스를 구축할 수 있을 것이다.