502가 떴다 — HTTP 상태 코드로 장애 원인 읽는 법
상태 코드는 외우는 게 아니라 읽는 겁니다. 같은 “서버 에러”도 502, 503, 504는 원인과 대응이 전혀 다릅니다.
“502 떴어요. 서버 죽은 건가요?”
운영팀에서 가장 많이 듣는 질문입니다. 그런데 502는 “서버가 죽었다”는 뜻이 아닙니다. 프록시가 백엔드한테 물어봤는데 이상한 답을 받았다는 뜻입니다. 서버가 죽었으면 503이고, 답이 늦으면 504입니다. 이 차이를 모르면 장애 대응 시간이 두 배로 늘어납니다.
HTTP 상태 코드는 서버가 클라이언트에게 보내는
3자리 숫자 응답입니다.
1xx부터 5xx까지 다섯 종류인데,
실무에서 진짜 중요한 건 그중 일부입니다.
전체를 외울 필요 없이,
장애 상황에서 “이 코드가 뜨면 어디를 봐야 하는가”를 아는 게 핵심입니다.
1xx — 아직 처리 중
실무에서 직접 만날 일은 거의 없습니다. 브라우저와 서버 사이에서 자동으로 처리되기 때문입니다.
유일하게 기억할 것: WebSocket 연결이 안 될 때 101이 오는지 확인하세요. 101이 안 오면 프록시가 Upgrade 헤더를 먹고 있을 가능성이 높습니다.
2xx — 성공
요청이 정상 처리되었다는 뜻입니다. 대부분 200만 쓰지만, API를 설계한다면 구분해서 써야 합니다.
흔한 실수: 200으로 에러를 보내는 API
상태 코드는 200인데 바디에 { "success": false, "error": "..." }를 보내는 패턴. 모니터링 도구가 에러를 잡지 못하고, 프록시 캐시가 에러 응답을 캐싱하는 사고가 발생합니다. 에러는 4xx/5xx로 보내세요.
3xx — 리다이렉트
요청한 리소스가 다른 곳에 있다는 뜻입니다. SEO와 직접 연결되기 때문에 웹 서비스라면 정확히 구분해야 합니다.
301 vs 308, 302 vs 307 — 핵심 차이
301/302는 리다이렉트 시 POST를 GET으로 바꿀 수 있습니다(브라우저 구현에 따라 다름). 308/307은 원래 메서드를 반드시 유지합니다. 웹 페이지 리다이렉트는 301/302, API 리다이렉트는 308/307이 안전합니다.
4xx — 클라이언트 잘못
요청 자체에 문제가 있다는 뜻입니다. 서버는 정상인데 클라이언트가 잘못 보냈을 때 뜹니다. 가장 혼동이 많은 구간입니다.
401 vs 403 — 면접에서도 자주 나오는 질문
401은 “너 누구야?”(인증 실패), 403은 “너인 건 알겠는데 안 돼”(인가 실패). 이름이 Unauthorized라서 헷갈리지만, 401은 Authentication, 403은 Authorization입니다. 로그인 안 한 사용자 → 401, 일반 유저가 관리자 페이지 접근 → 403.
5xx — 서버/인프라 장애
이 글의 핵심입니다. 5xx가 뜨면 “서버 에러”로 뭉뚱그리지 말고, 코드별로 봐야 할 곳이 다릅니다.
500 Internal Server Error — 코드 버그
가장 일반적인 서버 에러입니다.
서버 애플리케이션 내부에서 예외가 발생했다는 뜻입니다.
NullPointerException, unhandled promise rejection, 잘못된 SQL 쿼리 등.
답은 항상 애플리케이션 로그에 있습니다.
500이 간헐적으로 뜬다면
특정 입력 조건에서만 터지는 엣지 케이스일 가능성이 높습니다.
재현 조건을 찾는 게 핵심입니다.
502 Bad Gateway — 프록시가 이상한 응답을 받음
Nginx나 로드밸런서 같은 리버스 프록시가
백엔드 서버에 요청을 전달했는데,
백엔드가 비정상적인 응답을 돌려줬거나
연결 자체가 끊겼을 때 발생합니다.
# 가장 먼저 볼 곳 tail -f /var/log/nginx/error.log | grep upstream # 자주 보이는 패턴 upstream prematurely closed connection → 백엔드가 응답 도중 연결을 끊음 connect() failed (111: Connection refused) → 백엔드 프로세스가 안 떠 있음 no live upstreams → upstream 그룹의 모든 서버가 다운
502의 대부분은 백엔드 프로세스가 죽었거나, 배포 중에 잠깐 내려간 경우입니다. 프로세스 매니저(PM2, systemd)로 백엔드 상태를 확인하세요.
503 Service Unavailable — 지금은 안 됨
서버가 일시적으로 요청을 처리할 수 없는 상태입니다.
서버가 살아 있긴 한데 과부하이거나,
의도적으로 요청을 거부하는 것입니다.
503이 뜨는 일반적인 상황은 세 가지입니다.
첫째, 롤링 배포 중에 인스턴스가 준비 안 된 경우.
둘째, DB 커넥션 풀이 가득 찬 경우.
셋째, 서킷 브레이커가 열린 경우.
Retry-After 헤더가 있다면
그 시간만큼 기다린 후 재시도하면 됩니다.
504 Gateway Timeout — 백엔드가 시간 안에 응답 안 함
프록시가 백엔드에 요청을 보냈는데, 설정된 시간 내에 응답이 오지 않은 경우입니다. 502와 달리 연결은 됐지만 응답이 너무 느린 것입니다.
# /etc/nginx/nginx.conf 또는 site config proxy_connect_timeout 5s; # 백엔드 연결 타임아웃 proxy_send_timeout 30s; # 요청 전송 타임아웃 proxy_read_timeout 60s; # 응답 대기 타임아웃 ← 504의 직접 원인 # 504가 자주 뜬다면 # 1. slow query가 있는지 DB 로그 확인 # 2. 외부 API 호출이 있는지 확인 # 3. proxy_read_timeout을 무작정 늘리지 말고 원인을 찾을 것
리버스 프록시 뒤에서의 상태 코드
대부분의 프로덕션 환경은
클라이언트 → 프록시(Nginx, HAProxy, ALB) → 백엔드 구조입니다.
이 구조에서는 같은 상태 코드라도
어디서 생성되었느냐에 따라 의미가 달라집니다.
백엔드가 보낸 4xx/5xx
프록시는 백엔드의 응답을 그대로 전달합니다. Nginx 액세스 로그에 상태 코드가 찍히고, 에러 로그에는 아무것도 없습니다.
프록시가 생성한 502/503/504
프록시 자체가 만든 에러입니다. Nginx 에러 로그에 upstream 관련 메시지가 찍힙니다. 백엔드 로그에는 아무것도 없을 수 있습니다.
로드밸런서(ALB/NLB)가 생성한 5xx
AWS ALB의 경우 502/503/504를 자체 생성합니다. CloudWatch의 ELB 5XX Count와 Target 5XX Count를 분리해서 봐야 합니다. ELB 5XX는 로드밸런서 문제, Target 5XX는 백엔드 문제.
장애 대응 첫 30초의 판단
5xx가 뜨면 가장 먼저 “프록시가 생성한 건지, 백엔드가 보낸 건지”를 확인하세요. Nginx라면 error.log에 upstream 키워드가 있는지, AWS라면 ELB 5XX vs Target 5XX를 봅니다. 이 한 가지 판단이 이후 조치의 방향을 결정합니다.
API 설계할 때 자주 틀리는 것들
1. 모든 응답을 200으로 보내기
에러도 200에 담아 보내면 모니터링 도구가 에러를 감지하지 못합니다. CDN이나 프록시가 에러 응답을 캐싱하는 사고도 발생합니다. HTTP 상태 코드는 기계가 읽는 것이고, 바디의 메시지는 사람이 읽는 것입니다. 둘 다 정확해야 합니다.
2. DELETE 성공 시 200 + 빈 바디
삭제 성공이면 204 No Content가 적절합니다. 200에 빈 바디를 보내면 클라이언트가 JSON 파싱을 시도하다 에러가 날 수 있습니다. 삭제된 리소스 정보를 돌려주고 싶다면 200 + 바디, 아니면 204.
3. 인증/인가를 구분 안 하고 모두 401
토큰이 없으면 401, 토큰은 있지만 권한이 부족하면 403. 프론트엔드에서 401이면 로그인 페이지로, 403이면 권한 안내 페이지로 보내야 합니다. 둘 다 401로 보내면 UX가 깨집니다.
4. 404를 남용하기
존재하지 않는 리소스에 404를 보내는 건 맞지만, 보안상 리소스 존재 여부를 숨기고 싶다면(예: 다른 사용자의 비공개 게시글) 403 대신 의도적으로 404를 보내기도 합니다. GitHub이 이 패턴을 씁니다. 다만 API 문서에 명시해야 디버깅할 때 혼동이 없습니다.
장애 대응 빠른 참조표
| 코드 | 뜻 | 첫 번째로 볼 곳 |
|---|---|---|
| 400 | 요청 형식 오류 | 요청 바디/파라미터 |
| 401 | 인증 실패 | 토큰 만료/누락 |
| 403 | 권한 없음 | RBAC/ACL 설정 |
| 404 | 리소스 없음 | URL 경로, 라우팅 설정 |
| 429 | 요청 과다 | Rate Limit 정책, Retry-After |
| 500 | 서버 내부 에러 | 애플리케이션 에러 로그 |
| 502 | 백엔드 비정상 응답 | 프록시 error.log, 백엔드 프로세스 |
| 503 | 서비스 불가 | CPU/메모리, 커넥션 풀, 배포 상태 |
| 504 | 응답 지연 | proxy_read_timeout, slow query |
HTTP 상태 코드는 서버가 보내는 진단서입니다.
코드를 정확히 읽을 수 있으면
장애의 원인이 클라이언트인지, 애플리케이션인지,
프록시인지, 인프라인지를 30초 안에 판단할 수 있습니다.
외우지 마세요.
이 글을 북마크하고 장애가 터졌을 때 꺼내 보세요.
본 글은 리원에이스 기술개발본부가 작성한 기술 콘텐츠입니다. 외부 공유 시 출처를 명시해 주세요.
2026년 8월 19일
리원에이스 기술개발본부