🎥 AI 시대 옵저버빌리티 전략 웨비나 | 무료 다시보기 (~4/9)
Top
도입문의
테크
2026-09-09

502 Bad Gateway 원인과 nginx 에러 로그 구분법

502 Bad Gateway는 nginx 같은 게이트웨이가 요청을 전달한 서버에서 정상적인 HTTP 응답을 받지 못했을 때 반환하는 상태 코드입니다. nginx가 클라이언트 요청을 뒤쪽 서버로 전달하고, 그 서버의 응답을 받아 클라이언트에게 돌려주는 구성을 다룹니다. nginx는 요청을 전달할 서버를 선택하는 단계, 해당 서버와 연결하는 단계, 받은 응답을 해석하는 단계에서 각각 실패할 수 있습니다.

여기서 업스트림(upstream)은 nginx가 요청을 전달하는 다음 서버를 뜻합니다. 업스트림이 다시 다른 서버에 요청을 전달하는 구성도 있습니다. 이런 구조에서는 nginx가 직접 502를 만들기도 하고, 업스트림이 반환한 502를 nginx가 그대로 전달하기도 합니다.

502는 업스트림 프로세스가 종료됐을 때만 발생하는 오류도 아닙니다. 프로세스가 실행 중이어도 워커가 갑자기 종료되거나 응답 헤더가 너무 크거나 통신 프로토콜이 맞지 않으면 502가 발생할 수 있습니다. 원인에 따라 nginx 에러 로그에 남는 문구도 달라집니다.

이 글에서는 세 단계로 원인을 좁힙니다. 먼저 502를 nginx가 만들었는지, 업스트림이 반환했는지 구분합니다. 다음으로 에러 로그 문구를 보고 실패가 발생한 단계를 찾습니다. 마지막으로 대부분의 요청이 실패했는지 일부 요청만 실패했는지 확인합니다.

빠르게 확인할 error.log 문구

장애가 진행 중이라면 아래 표에서 에러 로그 문구를 찾아 조사할 곳부터 빠르게 좁힐 수 있습니다. 본문에서는 502를 반환한 위치, 실패가 발생한 단계, 영향을 받은 요청 범위를 차례로 확인합니다.

error.log 문구 먼저 확인할 곳
no live upstreams 업스트림 그룹 구성과 제한 설정
connect() failed 연결 대상 주소·포트·소켓 경로
upstream prematurely closed connection 워커 종료 여부와 배포 이력
recv() failed 백엔드 로그와 중간 네트워크 장비
upstream sent too big header 응답 헤더 크기와 버퍼 설정
일치하는 문구 없음 다른 오류 문구와 로그 수집 상태를 확인한 뒤 액세스 로그와 대조

표에 나온 문구는 502가 발생할 때 자주 확인되는 사례입니다. 일치하는 문구가 없다면 같은 시간대의 에러 로그 전체를 살펴보고, 다른 연결 오류나 TLS 오류가 기록됐는지 확인합니다. 에러 로그에도 관련 기록이 없다면 업스트림이 반환한 502를 nginx가 그대로 전달했을 가능성도 확인해야 합니다.

502를 반환한 위치 확인하기

클라이언트에서 502가 보인다고 해서 nginx가 직접 만든 오류라고 단정할 수는 없습니다. 업스트림이 반환한 502를 nginx가 그대로 전달했을 수도 있습니다. 두 경우는 조사할 곳이 완전히 다르므로 먼저 가려야 합니다.

기준은 에러 로그와 액세스 로그를 함께 보는 것입니다. 에러 로그에는 nginx가 업스트림과 통신하다 실패한 내용이 남고, 액세스 로그에는 어느 업스트림으로 요청을 보냈고 그 업스트림이 어떤 상태 코드를 반환했는지 남길 수 있습니다.

로그를 맞춰 볼 때 시각만으로 판단하면 안 됩니다. 트래픽이 많은 환경에서는 같은 시각에 여러 요청이 실패합니다. 오류가 난 시각과 함께 요청 경로, 업스트림 주소, 기록된 요청 식별자를 대조해 같은 요청의 로그인지 확인합니다.

액세스 로그에 업스트림 변수 남기기

기본 액세스 로그에는 클라이언트에게 반환한 상태 코드만 남습니다. $upstream_addr$upstream_status를 log_format 지시어로 형식에 추가하고, 그 형식 이름을 access_log 지시어에 지정해야 요청을 보낸 업스트림과 그 응답 코드가 함께 기록됩니다. 어떤 요청의 로그인지 대조하려면 $request_id$request_uri도 같이 넣습니다.

두 가지를 미리 알아 두면 값을 잘못 읽지 않습니다. 첫째, 설정을 추가해도 이미 지나간 요청의 정보는 복원되지 않습니다. 지금 넣어 두면 다음 발생 때부터 보입니다. 둘째, 재시도가 일어나면 한 요청에 여러 주소와 상태 코드가 쉼표로 이어져 기록됩니다.

$upstream_addr에는 nginx가 선택한 업스트림의 주소와 포트가 남습니다. Unix 소켓 구성에서는 주소와 포트 대신 소켓 경로가 남고, 보낼 서버를 고르지 못한 경우에는 업스트림 그룹 이름이 남습니다.

$upstream_status에는 업스트림이 반환한 상태 코드가 기록됩니다. 다만 nginx가 요청을 보낼 서버를 선택하지 못한 경우에도 502가 기록되므로, 이 값만으로는 502가 발생한 위치를 구분할 수 없습니다.

값 조합으로 판단할 수 있는 것

두 로그를 함께 보면 다음 세 가지로 갈립니다.

확인한 내용 판단할 수 있는 범위 이어서 필요한 확인
$upstream_addr에 그룹 이름 + 관련 에러 로그 그 시도에서 보낼 대상을 고르지 못함 업스트림 그룹 구성과 서버 선택 조건
구체적인 주소 + 연결이나 응답 처리 오류 고른 대상과 통신하는 과정에서 실패 해당 대상의 로그와 프로세스 상태
구체적인 주소 + 관련 에러 로그 없음 nginx 로그만으로는 발생 위치를 확정하기 어려움 로그 수집 상태, 그 요청에 대한 업스트림의 응답 기록
nginx가 업스트림을 선택하지 못한 경우, 선택한 업스트림과 통신하는 중 실패한 경우, 업스트림이 직접 502를 반환한 경우를 액세스 로그 변수와 에러 로그 유무로 나눠 보는 도식
`$upstream_addr` 값으로 서버 선택 여부와 조사할 대상을 확인합니다.

세 번째 경우가 가장 헷갈립니다. 구체적인 주소가 남았는데 nginx의 error.log에 관련 기록이 없다면, 해당 업스트림이 직접 502를 반환했을 가능성이 큽니다. 이때는 해당 업스트림의 로그에서 같은 요청에 무엇을 반환했는지 확인해야 합니다.

여러 서비스가 연결된 환경에서는 이 확인이 한 번으로 끝나지 않습니다. nginx가 요청을 인증 서비스로 전달하고, 인증 서비스가 다시 결제 서비스를 호출하는 구성을 생각해 보겠습니다. 결제 서비스가 응답하지 못해 인증 서비스가 502를 반환하면, nginx는 이 502를 클라이언트에게 그대로 전달합니다. 이 경우 nginx의 error.log에는 관련 기록이 남지 않을 수 있습니다. nginx와 업스트림 사이의 통신에서 발생한 오류가 아니기 때문입니다.

이런 구성에서는 요청 ID나 트레이스 ID를 각 서비스가 기록하고 다음 서비스로 넘기도록 구성해 두어야 추적이 가능합니다. 식별자가 있으면 요청이 거쳐 간 서비스를 순서대로 따라가 502가 처음 만들어진 지점을 찾을 수 있습니다. 구간별로 응답 시간을 나눠 보는 순서는 API 응답 시간이 느린 이유 7가지와 진단 순서에 정리돼 있습니다.

nginx 502 에러 로그 문구별 원인 5가지

nginx가 직접 만든 502로 확인됐다면 다음은 어느 단계에서 실패했는지 좁힙니다. nginx는 요청을 전달할 업스트림을 선택하고, 그 서버와 연결을 맺고, 받은 데이터를 HTTP 응답으로 해석합니다. 에러 로그 문구는 이 셋 중 어디서 멈췄는지를 알려줍니다.

에러 로그 문구 업스트림 상태 먼저 확인할 곳
no live upstreams while connecting to upstream 그 시도에서 보낼 수 있는 업스트림이 없음 그룹 구성, nginx가 요청 대상에서 제외한 서버, 연결 수 제한
connect() failed (111: Connection refused) 대상 주소와 포트가 연결을 받지 않음 프로세스 상태, 포트·바인딩 주소·소켓 상태
upstream prematurely closed connection 응답을 받는 도중 업스트림이 연결을 종료함 업스트림 애플리케이션의 워커 종료, 메모리 부족, 배포 중 종료
recv() failed (104: Connection reset by peer) 업스트림이나 중간 네트워크 장비가 연결을 강제로 끊음 백엔드 로그, 워커 상태, 자체 타임아웃, 중간 장비
upstream sent too big header 업스트림의 응답 헤더가 버퍼를 넘음 Set-Cookie 등 응답 헤더 크기, 버퍼 설정

no live upstreamsconnect() failed는 응답을 받기 전, 즉 대상을 고르거나 연결하는 단계에서 실패했다는 뜻입니다. 연결 종료·리셋·헤더 크기 초과 문구는 연결이 맺어진 뒤 응답을 받는 과정에서 문제가 생겼다는 뜻입니다.

nginx가 요청을 넘기는 업스트림 선택, 연결 수립, 응답 수신·해석 세 단계에 no live upstreams, connect() failed, upstream prematurely closed connection, recv() failed, upstream sent too big header 문구를 각각 매핑한 도식
연결 전 실패인지, 연결 후 응답 처리 실패인지를 먼저 구분합니다.

no live upstreams while connecting to upstream

그 시도에서 요청을 보낼 수 있는 업스트림이 하나도 없었다는 뜻입니다. 그룹의 모든 서버가 nginx에 의해 요청 대상에서 일시적으로 제외된 경우가 가장 흔하지만, 동적으로 구성한 그룹이 비어 있거나 모든 서버가 연결 수 제한에 도달했을 때도 나옵니다. 그래서 개별 서버 상태만 보지 말고 그룹 구성과 제한 설정을 함께 확인합니다.

nginx는 fail_timeout 기간 안에 통신 실패가 max_fails 횟수만큼 쌓인 서버를 사용 불가로 표시하고, 이후 fail_timeout 동안 요청 대상에서 제외합니다. 다만 업스트림 그룹에 서버가 하나뿐이면 이 두 설정을 무시하고 제외하지 않습니다. 따라서 단일 서버 구성에서 백엔드 프로세스가 종료되면 보통 no live upstreams가 아니라 connect() failed가 남습니다.

이 예외는 max_fails·fail_timeout으로 실패를 셀 때만 적용됩니다. 서버를 down으로 지정했거나 동적 그룹이 비어 있으면 단일 서버 구성에서도 no live upstreams가 나타납니다.

실패한 요청을 다른 업스트림으로 다시 보낼지는 proxy_next_upstream 설정이 정합니다. 연결 오류나 타임아웃, 잘못된 응답이 발생했을 때 같은 요청을 다른 업스트림으로 재시도하도록 지정할 수 있습니다. 다만 POST나 PATCH처럼 같은 요청을 반복했을 때 결과가 달라질 수 있는 요청은 재시도 조건을 신중하게 설정해야 합니다.

connect() failed (111: Connection refused)

nginx가 보낼 업스트림은 골랐지만 그 주소와 포트에 연결하지 못했다는 뜻입니다. 프로세스가 종료된 경우가 대표적이지만, 포트 설정이나 바인딩 주소가 잘못됐을 때도 같은 문구가 나옵니다. 이때는 재시작해도 해결되지 않습니다.

TCP 연결이 거부되면 connect() failed (111: Connection refused)가 남습니다. Unix 소켓을 찾지 못한 경우에는 connect() to unix:/run/php-fpm.sock failed처럼 다른 형태로 기록될 수 있습니다. connect() failed만 검색하면 Unix 소켓 오류를 놓칠 수 있으므로 connect() 또는 while connecting to upstream도 함께 확인합니다.

먼저 연결 대상과 설정이 올바른지 확인하고, Unix 소켓 구성이라면 소켓 파일의 경로와 권한도 함께 봅니다. 프로세스가 실제로 종료됐거나 요청을 받을 수 없는 상태일 때 재시작을 검토합니다.

upstream prematurely closed connection

업스트림이 응답 헤더를 다 보내기 전에 연결을 끊었다는 뜻입니다.

2026/08/25 09:14:02 [error] 2411#0: *17233 upstream prematurely closed connectionwhile reading response header from upstream, client: 10.0.2.31,upstream: "http://10.0.5.12:8080/api/orders", host: "shop.example.com"

while reading response header from upstream이 범위를 알려줍니다. nginx가 연결을 맺고 응답 헤더를 읽던 중이었다는 뜻이고, 아직 클라이언트에게 아무것도 보내지 않은 상태이므로 502로 바꿔 응답할 수 있습니다. 같은 시각 10.0.5.12:8080에서 워커 종료나 메모리 부족, 배포가 있었는지 확인합니다.

헤더를 이미 받아 클라이언트에게 응답을 보내기 시작한 뒤에 연결이 끊기면 결과가 다릅니다. 그 시점에는 상태 코드를 502로 바꿀 수 없어서 응답이 중간에 끊긴 형태로 클라이언트에 전달됩니다. 502로 나타나는 것은 헤더를 받는 단계에서 끊긴 경우입니다.

recv() failed (104: Connection reset by peer)

연결이 맺어진 뒤 상대가 연결을 강제로 끊었다는 뜻입니다. 업스트림 프로세스가 종료된 경우 외에도 중간의 로드 밸런서나 방화벽이 유휴 연결을 정리하면서 리셋을 보내는 경우가 있어, 업스트림 로그만으로 원인이 나오지 않으면 중간 구간도 함께 확인합니다.

같은 문구가 클라이언트 쪽에서도 나옵니다. while reading client request headers가 붙은 것은 클라이언트와의 연결에서 난 오류라 502와 무관합니다. 문구 뒤에 from upstream이 붙어 있는지 확인해야 합니다.

upstream sent too big header

업스트림이 보낸 응답 헤더가 nginx가 잡아둔 버퍼를 넘었다는 뜻입니다. 응답 내용 자체는 정상이어도 헤더 크기 때문에 502가 됩니다. proxy_pass로 넘기는 구성에서는 proxy_buffer_size, FastCGI로 넘기는 구성에서는 fastcgi_buffer_size가 이 크기를 정합니다.

버퍼를 늘리기 전에 어떤 헤더가 커졌는지 먼저 확인합니다. 업스트림이 반환한 Set-Cookie나 인증 관련 헤더가 원인이라면 헤더 자체를 줄이는 편이 나은 경우도 있습니다. 클라이언트가 nginx에 보내는 Cookie는 요청 헤더라 이 오류와 관계가 없습니다.

502와 504는 어떻게 다른가

RFC 9110은 502를 게이트웨이나 프록시가 요청을 전달한 서버에서 유효하지 않은 응답을 받은 상태로, 504를 필요한 응답을 제때 받지 못한 상태로 구분해 정의합니다.

nginx도 이 구분을 따릅니다. 위 다섯 문구처럼 연결이나 응답 해석이 실패한 경우는 502이고, 업스트림에 연결하거나 응답을 기다리다 설정된 제한 시간을 넘긴 경우는 504입니다. 대기 시간 초과를 진단하는 순서는 504 Gateway Timeout 원인과 해결 방법에 따로 정리했습니다.

일부 요청에서만 502가 발생할 때 확인할 원인 4가지

에러 로그 문구는 요청 처리의 어느 단계에서 실패했는지 보여줍니다. 이제 그 실패가 왜 일어났는지를 워커 상태, 응답 내용, 설정 변경, 배포 이력과 연결해 봅니다.

먼저 실패 범위를 나눠 보면 조사할 곳이 좁아집니다. 같은 시간대의 502를 API 경로와 업스트림 주소별로 나눠, 특정 경로에서 대부분 실패했는지 특정 인스턴스로 전달된 요청에서만 실패했는지 확인합니다. 사이트 전체로는 일부만 실패해도 결제 API만 보면 전부 실패했을 수 있고, 그때는 공통 설정 문제와 특정 경로 문제가 함께 성립합니다.

로그 문구와 실패 범위가 서로 다른 방향을 가리킬 때는 구체적인 오류 문구를 우선합니다. 실패 범위는 조사 대상을 좁히는 보조 기준입니다.

  • 워커 조기 종료: PHP-FPM, uWSGI, Gunicorn처럼 업스트림 애플리케이션이 여러 워커로 요청을 나눠 처리하는 환경에서는 워커 하나가 메모리 부족이나 프로그램 오류로 갑자기 종료될 수 있습니다. 이때 해당 워커가 처리하던 요청만 502로 끝나고 다른 요청은 정상 처리됩니다. 서버 전체의 평균 CPU와 메모리 사용률은 정상으로 보이므로, 같은 시각의 애플리케이션 로그와 워커별 상태를 확인합니다.
  • 응답 헤더 크기 초과: 업스트림이 반환한 Set-Cookie나 인증 관련 응답 헤더가 커지면 버퍼를 넘습니다. proxy_buffer_size 기본값은 플랫폼의 메모리 페이지 크기에 따라 일반적으로 4KB 또는 8KB입니다. 로그인 상태나 세션 정보에 따라 헤더 크기가 달라지므로 특정 사용자에게만 502가 발생하기도 합니다.
  • 프로토콜 불일치: 평문 HTTP만 받는 포트에 proxy_pass https://로 TLS를 걸면 핸드셰이크가 실패하고 502가 발생합니다. 이 경우는 앞의 다섯 문구가 아니라 SSL_do_handshake() failed로 남습니다. FastCGI 소켓에 fastcgi_pass가 아닌 proxy_pass를 쓴 경우에도 502가 나오는데, 남는 문구는 업스트림이 어떻게 반응하는지에 따라 달라지므로 실제 에러 로그와 전달 방식을 함께 대조합니다. 반대로 TLS만 받는 포트에 평문으로 요청하면 업스트림 종류에 따라 502가 아니라 400이 돌아올 수 있습니다.
  • 배포·스케일 조정 중 연결 종료: 롤링 배포나 스케일 인 과정에서 종료 대상 인스턴스가 처리 중인 연결을 먼저 끊으면 해당 요청은 502로 끝날 수 있습니다. 배포 시각과 인스턴스 종료 기록을 비교하고, 로드 밸런서에서 인스턴스를 제외한 뒤 처리 중인 요청을 마칠 시간을 충분히 주는지 확인합니다.

마치며

502가 발생하면 먼저 nginx가 직접 만든 오류인지, 업스트림이 반환한 502를 전달한 것인지 가립니다. 에러 로그에 관련 기록이 있는지, 액세스 로그의 $upstream_addr에 그룹 이름이 남았는지 구체적인 주소가 남았는지로 판단합니다. 구체적인 주소가 남았는데 에러 로그에 기록이 없다면 그 업스트림의 로그를 확인합니다.

nginx가 직접 만든 502라면 에러 로그 문구로 실패 단계를 좁힙니다. no live upstreamsconnect() failed는 대상을 고르거나 연결하는 단계에서 실패했다는 뜻이고, 연결 종료·리셋·헤더 크기 초과 문구는 연결 이후 응답을 받는 과정에서 문제가 생겼다는 뜻입니다.

그다음 같은 시간대의 502를 API 경로와 업스트림 주소별로 나눠 실패 범위를 확인합니다. 이렇게 조사 대상을 좁힌 뒤 프로세스 상태를 확인하고 재시작 여부를 결정합니다.

502가 몰린 시간대의 통신 구간을 나중에 확인하려면 그 시점의 네트워크 상태가 남아 있어야 합니다. 와탭 네트워크 성능 모니터링은 프로세스 사이의 통신 관계와 구간별 지연 시간, 지연 시간의 변동성, 세션 수를 시계열로 확인할 수 있도록 지원합니다. 헤더 크기나 프로토콜 설정처럼 애플리케이션 쪽 원인은 이 지표로 드러나지 않지만, 502가 특정 통신 구간에 몰렸는지 가려낼 때 도움이 됩니다.

수집 지표와 주요 특징은 네트워크 성능 모니터링 소개에서 확인할 수 있습니다.

자주 묻는 질문

502 Bad Gateway가 뜨면 서버가 다운된 건가요?

그런 경우도 있지만 항상 그렇지는 않습니다. 프로세스가 종료되면 연결이 거부되고 실제로 502가 발생하기 때문에 둘을 같은 것으로 읽는 습관이 생깁니다. 하지만 502가 발생했다고 해서 서버가 종료됐다고 단정할 수는 없습니다. 502 에러는 워커 하나가 종료됐을 때도, 응답 헤더가 버퍼를 넘었을 때도, 통신 프로토콜이 맞지 않을 때도 나옵니다.

재시작을 먼저 누르는 것도 신중해야 합니다. 재시작하면 장애 당시의 프로세스와 연결 상태가 바뀌어 원인 확인이 어려워질 수 있습니다. 해당 시간대의 error.log 구간, 대상 포트나 소켓이 열려 있었는지, 업스트림 프로세스 목록 정도는 먼저 남겨 두는 편이 낫습니다.

브라우저에서 502가 보이면 사용자가 해결할 수 있나요?

502는 일반적으로 서버 사이의 통신 과정에서 발생하므로 사용자가 직접 해결할 수 있는 부분은 거의 없습니다. 새로고침 후 정상화됐다면 일시적인 연결 종료나 배포 중 인스턴스 교체, 특정 워커 문제 등으로 일부 요청만 실패했을 가능성이 있습니다. 다만 새로고침 결과만으로 정확한 원인을 판단할 수는 없습니다.

오류가 반복된다면 잠시 후 다시 시도하고, 계속 발생할 경우 서비스 운영자에게 문의해야 합니다. 브라우저 캐시나 확장 프로그램이 502의 직접적인 원인인 경우는 드뭅니다.

502와 503은 어떻게 다른가요?

503 Service Unavailable은 서버가 과부하나 점검 등의 이유로 현재 요청을 처리할 수 없음을 알리는 상태 코드입니다. 업스트림 애플리케이션이 직접 반환할 수도 있고, nginx의 limit_req나 limit_conn 같은 요청 제한 기능에서 반환할 수도 있습니다. 요청 제한 기능은 기본적으로 503을 반환하지만 설정에 따라 다른 코드로 변경할 수 있습니다.

502는 게이트웨이가 업스트림과 통신하거나 응답을 해석하는 과정에서 실패했을 때 발생합니다. 따라서 503은 서버의 처리 용량과 점검 상태, 요청 제한 설정을 확인하고, 502는 nginx 에러 로그와 업스트림 연결·응답 상태를 확인합니다. 5xx 전체 목록과 나머지 상태 코드의 의미는 HTTP 상태 코드 총정리, 1xx~5xx에서 확인할 수 있습니다.

클라우드 로드 밸런서에서도 502가 나오나요?

나옵니다. 클라우드 로드 밸런서도 대상 서버가 연결을 먼저 끊거나 올바르지 않은 응답을 보낸 경우 등에 502를 반환할 수 있습니다. 다만 502로 분류하는 조건과 로그 항목은 제품마다 다릅니다. 해당 로드 밸런서의 액세스 로그와 오류 사유, 대상 그룹의 헬스 체크 상태, 백엔드 애플리케이션 로그를 함께 확인해야 합니다.

더 읽을거리

참고 자료

와탭 모니터링을 무료로 체험해보세요!