웹 서비스를 운영하다가 갑자기 브라우저 화면에 502 Bad Gateway 경고가 뜨는 난감한 상황을 경험해봤을까? 당황해서 일단 Nginx나 PHP 프로세스를 무작정 재시작하여 임시로 넘어가는 경우가 많다. 다만 원인을 정확히 찾지 못하면 트래픽이 몰리거나 서버가 재부팅될 때마다 동일한 장애가 계속 반복된다.
이번에는 Nginx 502 Bad Gateway 에러가 정확히 왜 발생하는지, 로그를 통한 정확한 원인 진단부터 php-fpm 유닉스 소켓 권한 설정 및 프로세스 최적화 방법까지 완벽하게 정리해서 소개하겠다.
502 Bad Gateway 에러는 게이트웨이나 프록시 역할을 하는 웹서버(Nginx)가 뒤단에 위치한 애플리케이션 서버(php-fpm, Node.js, Python Gunicorn 등)로부터 유효하지 않은 응답을 받았을 때 발생한다. 웹서버 자체가 죽은 것이 아니라, 웹서버가 요청을 전달할 업스트림(Upstream) 백엔드 프로세스와 통신하지 못했음을 의미한다.
웹 브라우저가 HTTP 요청을 보내면 Nginx는 해당 요청을 받아 Unix Domain Socket이나 TCP 포트를 통해 php-fpm으로 전달한다. 이때 php-fpm이 꺼져 있거나, 소켓 파일 읽기 권한이 없거나, 응답 시간이 초과되면 Nginx는 클라이언트에게 502 Bad Gateway 응답을 즉시 반환한다.
502 에러가 발생했을 때 가장 먼저 해야 할 일은 추측으로 설정을 바꾸는 것이 아니라 Nginx 에러 로그를 확인하는 것이다. 리눅스 터미널에서 다음 명령어로 실시간 에러 로그를 확인한다.
sudo tail -f /var/log/nginx/error.log로그에 찍히는 대표적인 에러 메시지 3가지와 원인은 다음과 같다.
1. connect() to unix:/var/run/php/php8.2-fpm.sock failed (13: Permission denied): Nginx 프로세스 계정이 php-fpm 유닉스 소켓 파일에 접근할 권한이 없을 때 발생한다.
2. connect() to unix:/var/run/php/php8.2-fpm.sock failed (2: No such file or directory): php-fpm 서비스가 정지되어 있거나 소켓 경로가 잘못 지정되었을 때 발생한다.
3. recv() failed (104: Connection reset by peer): php-fpm 프로세스가 메모리 초과(OOM)나 Fatal Error로 인해 응답 도중 갑자기 강제 종료되었을 때 발생한다.
Nginx는 보통 www-data 또는 nginx 계정으로 실행된다. 반면 php-fpm 소켓이 root나 root 그룹 소유로 생성되면 Nginx가 소켓 파일에 접근할 수 없다.
✗ 잘못된 php-fpm pool 설정 (/etc/php/8.2/fpm/pool.d/www.conf)
; 소켓 소유자 및 권한 설정이 주석 처리되어 있거나 잘못됨
listen = /var/run/php/php8.2-fpm.sock
;listen.owner = www-data
;listen.group = www-data
listen.mode = 0600위와 같이 listen.mode가 0600(소유자만 읽기/쓰기 가능)으로 설정되어 있고 listen.owner가 설정되어 있지 않으면 php-fpm을 실행한 소유자 외에는 Nginx조차 소켓에 접속할 수 없다.
✓ 올바른 php-fpm pool 설정 (/etc/php/8.2/fpm/pool.d/www.conf)
listen = /var/run/php/php8.2-fpm.sock
; Nginx 실행 계정과 동일하게 설정
listen.owner = www-data
listen.group = www-data
listen.mode = 0660설정을 변경한 후에는 반드시 php-fpm 서비스를 재시작해야 소켓 파일의 권한이 갱신된다.
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx
PHP 애플리케이션이 반환하는 응답 헤더나 쿠키 데이터가 지나치게 크면 Nginx의 기본 FastCGI 버퍼 용량을 초과하여 502 에러가 발생한다.
✗ 잘못된 Nginx FastCGI 설정 (/etc/nginx/sites-available/default)
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
# FastCGI 버퍼 관련 설정이 없어 기본값(4k/8k) 사용 시 대용량 헤더 수신 불가
}✓ 올바른 Nginx FastCGI 설정 (/etc/nginx/sites-available/default)
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
# FastCGI 버퍼 크기 확장
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}버퍼 크기를 현실적인 수준으로 확장해주면 대용량 쿠키나 프레임워크 응답 헤더 처리가 정상화된다.
| 구분 | Unix Domain Socket (unix:) | TCP/IP Socket (127.0.0.1:9000) |
|---|---|---|
| 통신 방식 | 커널 내부 파일 시스템 소켓 사용 | 루프백 네트워크 프로토콜(TCP) 사용 |
| 성능 및 오버헤드 | 네트워크 스택을 거치지 않아 빠름 (권장) | TCP 패킷 캡슐화로 인한 소폭 오버헤드 발생 |
| 주요 에러 원인 | 소켓 파일 권한(Permission denied) 오류 | 포트 충돌, 사용 가능한 포트/포트 고갈 문제 |
| 사용 환경 | Nginx와 php-fpm이 동일한 서버에 있을 때 | Nginx와 php-fpm이 서로 다른 서버에 있을 때 |
✗ 권한 에러(Permission denied)가 발생했을 때 임시방편으로 chmod 777 /var/run/php/php8.2-fpm.sock 명령을 실행하는 실수다. 일시적으로는 동작하지만 서버나 php-fpm 서비스가 재시작되면 소켓 파일이 새로 생성되면서 777 권한이 초기화되고 다시 502 에러가 터진다.
✓ 임시 명령어가 아닌 www.conf 파일 안의 listen.owner, listen.group, listen.mode 옵션을 올바르게 수정하는 정석 방법을 사용해야 서비스 재시작 후에도 권한이 유지된다.
✗ php-fpm 프로세스 수(pm.max_children) 설정이 너무 적어서 동시 요청을 모두 처리하지 못하고 큐가 넘쳐 502 에러가 나는 경우도 많다. 서버의 RAM 용량에 맞추어 pm.max_children 수치를 적절히 늘려주어야 한다.
Nginx 502 Bad Gateway 에러 해결은 웹 애플리케이션의 안정적인 서비스 운영을 위한 기초이자 핵심이다. 임시방편적인 서버 재시작 대신 에러 로그를 정확히 분석하고 계정 권한과 소켓 설정을 교정하는 작은 습관이 서비스 가동률을 극대화한다는 점을 잊지 말자. 이 글에서 다룬 php-fpm 소켓 권한 설정과 FastCGI 버퍼 조절을 참고해 서버 환경을 재점검하면, 갑작스러운 장애 없는 쾌적한 웹 서비스를 유지할 수 있을 것이다.