/인프라/nginx 504 Gateway Timeout 해결: proxy_read_timeout과 업스트림 타임아웃
인프라nginx504 gateway timeout

nginx 504 Gateway Timeout 해결: proxy_read_timeout과 업스트림 타임아웃

nginx 504 Gateway Timeout을 발생 위치별 진단 순서로 특정하고 proxy_read_timeout, gunicorn·php-fpm 업스트림 타임아웃, ALB 다단 프록시 정렬까지 복붙 예제로 해결하는 실전 가이드.

nginx 504 Gateway Timeout 해결: proxy_read_timeout과 업스트림 타임아웃

nginx 504 Gateway Timeout 해결 가이드: proxy_read_timeout부터 업스트림 타임아웃까지

배포는 잘 됐는데 무거운 리포트 API나 LLM 응답 호출만 들어가면 정확히 30초, 60초쯤에 504 Gateway Timeout이 뜬다. 익숙하시죠? 504는 "nginx가 업스트림(WAS)에게 요청은 잘 넘겼는데, 정해진 시간 안에 응답이 안 와서 끊었다"는 신호입니다. 즉 연결 실패가 아니라 타임아웃 문제라는 게 핵심입니다.

이 글은 504가 "어디서" 발생했는지 진단 순서로 좁히고, 타임아웃 지시어를 정확한 위치에 복붙해 해결하며, ALB·nginx·gunicorn 같은 다단 구성에서 타임아웃을 정렬하는 실무 노하우까지 한 번에 정리합니다.

504 vs 502부터 정확히 구분하자

504와 502는 증상이 비슷해 보이지만 원인이 완전히 다릅니다. 한 줄 요약: 504 = 업스트림이 살아있지만 제때 응답을 못 함, 502 = 업스트림이 죽었거나 응답이 깨짐.

구분504 Gateway Timeout502 Bad Gateway
의미타임아웃 (응답 지연)연결 실패 / 응답 깨짐
발생 시점요청 후 일정 시간 경과(30s·60s)즉시 또는 처리 중
대표 로그upstream timed out (110: Connection timed out)connect() failed (111: Connection refused)
첫 의심 대상느린 쿼리·외부 API, proxy_read_timeoutWAS 다운, 워커 크래시

502가 의심된다면 원인이 다르니 [nginx 502 Bad Gateway 해결 가이드]를 참고하세요. 이 글은 타임아웃에 집중합니다.

발생 위치별 진단 순서: 클라이언트 → nginx → 업스트림

무작정 proxy_read_timeout부터 늘리지 마세요. 어디서 끊겼는지부터 확인하는 게 순서입니다.

1단계 — 클라이언트에서 대기 시간 측정

Bash
curl -w "@-" -o /dev/null -s https://example.com/slow-api <<'EOF'
  time_connect:  %{time_connect}s
  time_starttransfer:  %{time_starttransfer}s
  time_total:  %{time_total}s
EOF

time_total이 정확히 60초(또는 30초)에서 끊긴다면 타임아웃이 거의 확실합니다.

2단계 — nginx error.log 확인

Bash
tail -f /var/log/nginx/error.log

upstream timed out ... while reading response header from upstream이 보이면 nginx의 읽기 타임아웃에 걸린 겁니다.

3단계 — 업스트림을 직접 호출

Bash
curl -w "%{time_total}\n" -o /dev/null -s http://localhost:8000/slow-api

여기서도 느리거나 끊긴다면 범인은 nginx가 아니라 **업스트림(WAS)**입니다. 이 경우 nginx 타임아웃만 늘려도 소용없습니다.

nginx 타임아웃 지시어 복붙 예제

504의 주범은 대부분 proxy_read_timeout입니다(기본 60s). server 또는 location 블록에 넣고 리로드하세요.

Nginx
location /api/ {
    proxy_pass http://backend;

    proxy_connect_timeout 5s;    # 업스트림 TCP 연결 대기 (보통 짧게)
    proxy_send_timeout    60s;   # nginx → 업스트림 요청 전송 대기
    proxy_read_timeout    300s;  # 업스트림 응답 대기 (504의 주범!)
}

PHP-FPM 같은 FastCGI 환경이라면 지시어가 다릅니다.

Nginx
location ~ \.php$ {
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_connect_timeout 5s;
    fastcgi_send_timeout    60s;
    fastcgi_read_timeout    300s;  # FastCGI의 504 주범
}

설정 후 반드시 문법 검사와 리로드를 합니다.

Bash
nginx -t && nginx -s reload

실무 팁: 전체 사이트에 300초를 거는 건 위험합니다. 느린 엔드포인트만 별도 location으로 분리해 길게 주고, 나머지는 기본값을 유지하세요. 대용량 업로드 때문에 끊긴다면 타임아웃이 아니라 요청 크기 제한일 수 있으니 [nginx 413 해결 가이드]도 확인하세요.

업스트림이 진짜 범인일 때

가장 흔한 실수가 nginx 타임아웃만 늘리고 업스트림은 그대로 둬서 여전히 504가 나는 것입니다. WAS 자체 타임아웃도 같이 올려야 합니다.

WAS지시어기본값비고
gunicorn--timeout30s504 단골 원인, 워커가 응답 못 하면 강제 종료
php-fpmrequest_terminate_timeout0(무제한)pm.max_children 부족 시 워커 대기 → 504
uWSGIharakiri없음초과 시 워커 강제 kill

예를 들어 gunicorn은 이렇게 올립니다.

Bash
gunicorn app:app --workers 4 --timeout 300

php-fpm에서 워커 수가 모자라면 요청이 큐에 쌓이며 504가 납니다. pm.max_children을 트래픽에 맞게 늘리세요.

다단 프록시 타임아웃 정렬 원칙

마이크로서비스·컨테이너 환경에서 ALB → nginx-ingress → nginx → gunicorn 식 다단 구성이 늘면서, 타임아웃 정렬 이슈가 정말 빈번해졌습니다. 원칙은 단순합니다. 바깥쪽이 더 길어야 한다.

CODE
ALB idle timeout (60s+) ≥ nginx proxy_read_timeout ≥ gunicorn --timeout

이 순서가 어긋나면, 예를 들어 ALB idle timeout(60s)이 nginx(300s)보다 짧으면 nginx가 응답을 기다리는 중에 ALB가 먼저 연결을 끊어 504가 발생합니다. 최근 LLM API를 프록시하는 스트리밍 응답 백엔드에서 이 문제로 504가 급증하는 사례가 많습니다. 응답이 길수록 가장 바깥 LB의 idle timeout부터 점검하세요.

로그 문구별 원인 매핑

로그 메시지원인손볼 곳
upstream timed out ... while reading response header응답이 너무 느림proxy_read_timeout + 업스트림 처리 속도
upstream timed out ... while connecting to upstream연결 자체 지연/업스트림 과부하proxy_connect_timeout, 워커 수
nginx 로그에 아무것도 없음nginx보다 앞단(LB)에서 끊김ALB/ELB idle timeout

30초 체크리스트

  1. curl -w로 몇 초에서 끊기는지 확인 (30/60/300?)
  2. error.log에서 timed out 문구 위치 확인 (reading vs connecting)
  3. curl localhost:8000으로 업스트림 직접 호출해 진짜 범인 특정
  4. 느린 엔드포인트만 location 분리 후 proxy_read_timeout 조정
  5. gunicorn --timeout 등 업스트림 타임아웃도 함께 상향
  6. ALB ≥ nginx ≥ WAS 순서로 정렬 확인
  7. nginx -t && nginx -s reload

자주 묻는 질문 (FAQ)

Q. 타임아웃을 무한정 늘려도 되나요? A. 안 됩니다. 타임아웃을 늘리는 건 응급처치일 뿐, 근본 원인은 느린 DB 쿼리나 외부 API 지연인 경우가 대부분입니다. 길게 잡으면 그만큼 nginx 커넥션이 점유되어 동시 처리량이 떨어집니다. 쿼리 인덱스, 캐싱, 비동기 처리로 응답 속도 자체를 줄이세요.

Q. 504인데 nginx 로그에 아무것도 안 찍혀요. A. nginx보다 앞단(ALB/ELB, CDN)에서 끊겼을 가능성이 높습니다. LB의 idle timeout이 nginx보다 짧은지 먼저 확인하세요.

Q. WebSocket/SSE에서 504가 나요. A. 스트리밍·롱폴링 연결은 응답 헤더 이후에도 데이터가 계속 오므로 proxy_read_timeout을 충분히 길게(혹은 SSE는 매우 길게) 설정하고, WebSocket이라면 proxy_http_version 1.1Upgrade/Connection 헤더 전달도 함께 확인해야 합니다.

Q. 502 글과 뭐가 다른가요? A. 504는 업스트림이 살아있지만 느린 타임아웃 문제, 502는 업스트림이 죽었거나 응답이 깨진 연결 문제입니다. 502라면 [nginx 502 Bad Gateway 해결 가이드]를 참고하세요.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.

작성 · Content Reviewer·검토 · 사람 편집자·발행 · 2026년 6월 12일

댓글

불러오는 중...