Nginx 502 Bad Gateway 오류 진단 및 해결 방법
오류 로그, 업스트림 상태, 소켓 권한, 프록시 설정, 타임아웃 및 방화벽을 확인하여 Nginx 502 오류를 해결하세요.
Nginx 502 Bad Gateway 오류 진단 및 해결 방법
Nginx는 강력하고 널리 사용되는 웹 서버이자 리버스 프록시로, 정적 콘텐츠 제공, 트래픽 로드 밸런싱, PHP-FPM, Node.js, Python Gunicorn, Apache Tomcat과 같은 다양한 업스트림 애플리케이션 서버로 요청을 전달하는 데 자주 사용됩니다. Nginx가 업스트림 서버와 통신하는 중 문제가 발생하면 일반적으로 "502 Bad Gateway" 오류로 응답합니다.
Nginx 오류 로그부터 시작하여 업스트림 프로세스가 실행 중이고, 연결 가능하며, 응답할 수 있는 상태인지 확인하세요.
Nginx 502 Bad Gateway 오류 이해
502 Bad Gateway 오류는 Nginx가 리버스 프록시 역할을 하면서 업스트림 서버로부터 유효하지 않은 응답을 받았음을 나타냅니다. 즉, Nginx가 업스트림 서버에 성공적으로 연결했지만 응답이 없거나, 불완전한 응답을 받았거나, 이해할 수 없는 응답을 받았다는 의미입니다. 중요한 점은 문제가 Nginx 자체가 아니라 Nginx가 통신하려는 서비스에 있다는 것입니다.
일반적인 업스트림 서버는 다음과 같습니다:
- PHP-FPM: PHP 애플리케이션용 (예: WordPress, Laravel).
- Gunicorn/uWSGI: Python 애플리케이션용 (예: Django, Flask).
- Node.js: JavaScript 애플리케이션용.
- Apache Tomcat: Java 애플리케이션용.
- 기타 웹 서버: 특정 콘텐츠를 제공하는 Apache HTTP Server 등.
502 오류는 애플리케이션의 백엔드가 제대로 작동하지 않거나 Nginx에서 접근할 수 없음을 나타내는 중요한 지표입니다.
단계별 진단
502 오류를 해결하는 핵심은 체계적인 진단입니다. 가장 가능성이 높은 원인부터 시작하여 점차 더 깊이 조사하세요.
1. 먼저 Nginx 오류 로그 확인
Nginx 오류 로그는 주요 정보 출처입니다. Nginx가 업스트림 서버와 통신할 수 없는 이유에 대한 구체적인 세부 정보가 포함되어 있는 경우가 많습니다.
- 위치: 일반적으로
/var/log/nginx/error.log에 있습니다. - 명령어: 오류를 재현하는 동안 실시간으로 로그를 모니터링하려면
tail -f를 사용하세요.
tail -f /var/log/nginx/error.log
찾아야 할 내용:
connect() failed (111: Connection refused): 업스트림 서버가 지정된 주소/포트에서 수신 대기 중이 아니거나 방화벽이 연결을 차단하고 있음을 나타냅니다.upstream timed out: 업스트림 서버가 응답하는 데 너무 오래 걸렸습니다.upstream prematurely closed connection: 업스트림 서버가 완전한 응답을 보내기 전에 연결을 종료했습니다.no live upstreams while connecting to upstream: Nginx가 구성된 사용 가능한 업스트림 서버를 찾을 수 없습니다.
2. 업스트림 서버 상태 확인
Nginx 오류 로그에서 단서를 얻은 후 업스트림 애플리케이션 서버의 상태를 확인하세요.
PHP-FPM의 경우:
sudo systemctl status php8.2-fpmNode.js/Python/기타 사용자 정의 앱의 경우: 프로세스가 실행 중인지 확인하세요.
ps aux | grep node ps aux | grep gunicornPM2(Node.js) 또는 Supervisor(일반)와 같은 프로세스 관리자를 사용하는 경우 해당 상태를 확인하세요.
pm2 status sudo supervisorctl status
서비스가 실행 중이 아닌 경우 시작을 시도하고 자체 로그에서 오류를 확인하세요.
sudo systemctl start php8.2-fpm
3. 업스트림에 대한 네트워크 연결 확인
Nginx가 구성된 포트 또는 소켓 경로에서 업스트림 서버에 도달할 수 있는지 확인하세요.
TCP/IP 연결의 경우 (예:
127.0.0.1:8000): Nginx 서버에서telnet또는nc(netcat)를 사용하여 포트 연결을 테스트하세요.telnet 127.0.0.1 8000 nc -vz 127.0.0.1 8000성공적인 연결은
Connected to 127.0.0.1.또는succeeded!를 표시합니다. 연결이 끊기거나Connection refused가 표시되면 업스트림 서비스가 수신 대기 중이 아니거나 방화벽이 차단하고 있는 것입니다.Unix 소켓의 경우 (예:
unix:/run/php/phpX.X-fpm.sock): 소켓 파일이 존재하고 올바른 권한이 있는지 확인하세요.ls -l /run/php/phpX.X-fpm.sockNginx는 이 소켓 파일에 대한 읽기/쓰기 권한이 있어야 합니다. Nginx 사용자(예:
www-data)는 소켓을 소유한 그룹(예:www-data또는php-fpm)의 일부여야 합니다.
일반적인 원인 및 해결 방법
진단 단계를 기반으로 502 오류의 가장 빈번한 원인과 해결 방법은 다음과 같습니다.
1. 업스트림 서버가 실행 중이 아니거나 충돌함
원인: Nginx가 프록시하려는 애플리케이션(예: PHP-FPM, Gunicorn, Node.js 앱)이 실행 중이 아니거나 충돌했습니다.
해결 방법: 업스트림 서비스를 시작하거나 다시 시작하세요.
# PHP-FPM 예시
sudo systemctl start php8.2-fpm
# 이미 실행 중이고 충돌이 의심되는 경우 다시 시작:
sudo systemctl restart php8.2-fpm
# 사용자 정의 애플리케이션의 경우 특정 시작/재시작 명령어 사용
팁: 업스트림 서비스가 시스템 부팅 시 자동으로 시작되도록 구성하세요. systemd 서비스의 경우 systemctl enable phpX.X-fpm을 사용하세요.
2. 업스트림 서버 과부하 / 리소스 고갈
원인: 업스트림 서버가 과부하되어 메모리, CPU가 부족하거나 프로세스 제한에 도달하여 응답을 중단하거나 새 연결을 거부합니다.
증상: Nginx 오류 로그에 특히 부하가 걸릴 때 간헐적으로 connection refused 또는 upstream timed out이 표시될 수 있습니다. 시스템 모니터링 도구(top, htop, free -h)는 높은 리소스 사용량을 보여줍니다.
해결 방법:
PHP-FPM의 경우: 구성 파일(예:
/etc/php/X.X/fpm/pool.d/www.conf)에서 PHP-FPM 풀 설정을 조정하세요.pm.max_children: 동시에 활성화될 수 있는 최대 자식 수.pm.start_servers: 시작 시 생성되는 자식 수.pm.min_spare_servers,pm.max_spare_servers: 유지되는 유휴 자식 수를 제어합니다.
; 동적 프로세스 관리 예시 pm = dynamic pm.max_children = 50 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 20- 스크립트가 메모리를 소진하는 경우
php.ini에서memory_limit을 늘리세요.
다른 애플리케이션의 경우: 가능하면 작업자 프로세스, 스레드 수를 늘리거나 더 많은 메모리를 할당하세요. 애플리케이션의 특정 메트릭을 모니터링하세요.
Nginx 타임아웃: Nginx 구성에서
proxy_connect_timeout,proxy_send_timeout,proxy_read_timeout지시문을 늘리세요. 하지만 백엔드가 실제로 어려움을 겪고 있다면 이는 단지 오류를 지연시킬 뿐임을 이해하세요.http { ... proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; ... }
3. Nginx의 잘못된 업스트림 구성
원인: Nginx가 업스트림 서버에 대해 잘못된 IP 주소, 포트 또는 Unix 소켓 경로에 연결하도록 구성되었습니다.
증상: Nginx 오류 로그에 요청 직후 connect() failed (111: Connection refused)가 표시됩니다.
해결 방법: Nginx 서버 블록 구성(/etc/nginx/sites-available/your_site.conf)을 주의 깊게 검토하세요.
HTTP/HTTPS 업스트림의 경우:
location /app { proxy_pass http://127.0.0.1:8000; # IP와 포트가 올바른지 확인 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }Unix 소켓을 통한 PHP-FPM의 경우:
location ~ \.php$ { fastcgi_pass unix:/run/php/phpX.X-fpm.sock; # 이 경로가 PHP-FPM 구성과 정확히 일치하는지 확인 fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }TCP/IP를 통한 PHP-FPM의 경우:
location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; # IP와 포트 확인 fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }
변경 후 항상 Nginx 구성을 테스트하고 Nginx를 다시 로드/재시작하세요:
nginx -t
systemctl reload nginx # 또는 -t가 필요함을 나타내면 재시작
4. PHP-FPM request_terminate_timeout 초과
원인: PHP 스크립트 실행 시간이 PHP-FPM의 request_terminate_timeout 설정보다 오래 걸립니다. Nginx는 응답을 기다리지만 PHP-FPM이 스크립트를 종료하여 Nginx가 불완전한 응답을 받게 됩니다.
증상: Nginx 오류 로그에 upstream timed out 또는 script timed out이 표시될 수 있습니다. PHP-FPM 로그에 child XX exited on signal 9 (SIGKILL)이 표시될 수 있습니다.
해결 방법:
request_terminate_timeout증가: PHP-FPM 풀 구성(www.conf)에서 이 지시문을 찾아 조정하세요.0으로 설정하면 타임아웃이 비활성화되지만 장기 실행 스크립트가 리소스를 점유할 수 있으므로 일반적으로 권장되지 않습니다.request_terminate_timeout = 300 # 5분(300초)으로 증가Nginx에서
fastcgi_read_timeout증가: 이 Nginx 타임아웃은request_terminate_timeout보다 크거나 같아야 합니다.location ~ \.php$ { ... fastcgi_read_timeout 300s; # PHP-FPM의 request_terminate_timeout보다 크거나 같아야 함 ... }
경고: 타임아웃을 늘리면 502 오류를 해결할 수 있지만 근본적인 성능 문제를 가릴 수 있습니다. 최선의 장기적 해결책은 느린 PHP 스크립트를 최적화하는 것입니다.
5. 방화벽 문제
원인: 방화벽(Nginx 서버 또는 별도인 경우 업스트림 서버)이 업스트림 포트 또는 소켓으로의 연결을 차단하고 있습니다.
해결 방법:
방화벽 상태 확인:
sudo ufw status # UFW의 경우 (Ubuntu/Debian) sudo firewall-cmd --list-all # firewalld의 경우 (CentOS/RHEL) sudo iptables -L # iptables의 경우필요한 포트 열기: Nginx가 업스트림에 연결하는 데 사용하는 포트(예: TCP/IP를 통한 PHP-FPM의 경우 9000)가 열려 있는지 확인하세요.
sudo ufw allow from 127.0.0.1 to any port 9000 # localhost가 9000에 연결하도록 허용 sudo firewall-cmd --permanent --add-port=9000/tcp # firewalld의 경우 sudo firewall-cmd --reload통제된 환경에서 테스트 목적으로만 방화벽을 일시적으로 비활성화한 후 다시 활성화하고 적절히 구성하세요.
6. SELinux 또는 AppArmor 간섭
원인: SELinux(RHEL/CentOS) 또는 AppArmor(Ubuntu/Debian)와 같은 보안 강화 기능이 파일 권한과 방화벽이 올바르게 구성되었음에도 Nginx가 업스트림 소켓에 액세스하거나 네트워크 연결을 설정하지 못하도록 차단할 수 있습니다.
증상: 로그에 특히 /var/log/audit/audit.log(SELinux의 경우)에서 permission denied 또는 유사한 메시지가 표시될 수 있습니다.
해결 방법:
audit.log확인:sudo grep nginx /var/log/audit/audit.logSELinux를 일시적으로 허용 모드로 설정:
sudo setenforce 0. 오류가 해결되면 SELinux가 원인입니다. 그런 다음 적절한 SELinux 정책(예:audit2allow)을 생성하고 적용해야 합니다. 다시 강제 모드로 설정하는 것을 잊지 마세요(sudo setenforce 1).AppArmor 상태 확인:
sudo aa-status. AppArmor가 활성화된 경우 Nginx 프로필을 조정해야 할 수 있습니다.
7. 대용량 요청/응답 본문 (프록시 버퍼링)
원인: Nginx의 기본 프록시 버퍼링 설정이 매우 큰 요청 또는 응답 본문에 비해 너무 작아 조기 연결 종료로 이어질 수 있습니다.
증상: Nginx 오류 로그에 upstream prematurely closed connection while reading response header from upstream 또는 upstream prematurely closed connection while reading response body from upstream이 표시될 수 있습니다.
해결 방법: http, server 또는 location 블록에서 Nginx 프록시 버퍼링 지시문을 조정하세요.
http {
...
proxy_buffer_size 128k; # 응답의 첫 번째 부분에 대한 버퍼 크기
proxy_buffers 4 256k; # 나머지 응답에 대한 버퍼 수 및 크기
proxy_busy_buffers_size 256k; # 최대 사용 중 버퍼 크기
proxy_temp_file_write_size 256k; # 버퍼링이 오버플로우될 경우 임시 파일 쓰기 크기
...
}
참고: 이러한 설정은 더 많은 메모리를 소비합니다. 서버 리소스와 애플리케이션 응답의 일반적인 크기에 따라 신중하게 조정하세요.
일반적인 문제 해결 팁
- 모든 관련 로그 검토: Nginx 오류 로그 외에도 Nginx 액세스 로그, 업스트림 애플리케이션 로그(PHP-FPM, Gunicorn, Node.js 앱 로그) 및 시스템 로그(
/var/log/syslog,dmesg)를 확인하세요. - Nginx 다시 시작: 구성 변경 후에는 항상 Nginx를 다시 시작하여 변경 사항이 적용되도록 하세요:
systemctl restart nginx. - Nginx 구성 테스트: 다시 시작하기 전에 Nginx 구성 구문의 유효성을 검사하세요:
nginx -t. - 문제 격리: Nginx를 우회하여 업스트림 애플리케이션에 직접 액세스해 보세요. 예를 들어 Node.js 앱이
localhost:3000에 있는 경우 서버의 명령줄에서curl http://localhost:3000을 사용하세요. 이것도 실패하면 문제는 확실히 Nginx가 아닌 애플리케이션에 있는 것입니다. - 디스크 공간 확인: 디스크가 가득 차면 애플리케이션이 임시 파일이나 로그를 쓰지 못해 충돌이나 오류가 발생할 수 있습니다.
df -h를 사용하여 디스크 사용량을 확인하세요.
핵심 요약
/var/log/nginx/error.log에서 시작하여 업스트림이 실행 중이고 Nginx 호스트에서 연결 가능한지 확인하세요. 연결 거부, 타임아웃, 권한 거부 또는 조기 종료 중 어떤 실패인지 알게 되면 일반적으로 업스트림 서비스, 소켓 권한, 타임아웃 설정 또는 방화벽 규칙에서 수정 사항을 찾을 수 있습니다.