
그림: 504는 단순히 제한 시간을 늘리기보다 어느 구간에서 응답이 멈췄는지 찾는 것이 우선입니다.
Nginx의 504 Gateway Timeout은 프록시가 뒤쪽 서버(upstream)의 응답을 기다리다 제한 시간에 도달했을 때 나타납니다. 설정값만 크게 늘리면 느린 DB 쿼리, 외부 API 대기, 컨테이너 과부하가 가려질 수 있습니다. 아래 순서대로 시간이 어디서 소모되는지 확인하면 수정 범위를 좁힐 수 있습니다.
1. 502와 504를 먼저 구분한다
502는 프록시가 upstream과 연결하거나 유효한 응답을 받는 과정에서 문제가 생길 때 흔합니다. 504는 연결 또는 응답 대기 중 제한 시간 초과가 핵심입니다. 다만 에러 코드만으로 원인을 단정하지 말고 Nginx error log의 문구를 확인해야 합니다. 예를 들어 upstream timed out ... while reading response header from upstream는 응답 헤더를 기다리던 상황을 알려줍니다.
2. 로그의 시각과 URL을 앱 로그에 맞춘다
sudo nginx -t
sudo tail -n 100 /var/log/nginx/error.log
sudo tail -n 100 /var/log/nginx/access.log
docker compose ps
docker compose logs --since 10m app
위 명령의 app은 실제 Compose 서비스명으로 바꾸세요. Nginx가 컨테이너 안에서 실행된다면 로그 경로 대신 해당 컨테이너의 stdout을 볼 수도 있습니다. 오류 시각, 요청 경로, upstream 주소를 기록하고 앱 로그에서 같은 시각의 DB 쿼리·외부 API 호출·작업 큐 지연을 찾습니다. 로그에 토큰이나 개인정보가 있다면 외부에 공유하기 전에 제거하세요.
3. 직접 호출과 프록시 호출의 시간을 비교한다
Nginx가 접근하는 네트워크 위치에서 upstream을 직접 호출해야 비교가 의미 있습니다. Docker Compose라면 같은 네트워크의 진단 컨테이너나 Nginx 컨테이너 안에서 서비스 이름과 포트로 호출하세요. 로컬 호스트의 localhost는 컨테이너 안의 localhost와 다릅니다.
curl -sS -o /dev/null -w 'connect=%{time_connect} total=%{time_total}\n' http://app:8080/health
curl -sS -o /dev/null -w 'connect=%{time_connect} total=%{time_total}\n' https://example.com/slow-path
헬스체크가 빠르더라도 실제 느린 경로의 DB와 외부 API가 병목일 수 있습니다. 읽기 전용이거나 테스트 가능한 요청으로 재현하고, 본문에 비밀값을 넣지 마세요.
| 관찰 결과 | 우선 의심할 구간 | 다음 점검 |
| 직접 호출도 느림 | 앱·DB·외부 API | 앱 타이밍, DB 쿼리, 작업 큐 |
| 연결 자체가 늦음 | 네트워크·DNS·포트·과부하 | Compose 네트워크, 연결 수, CPU·메모리 |
| 첫 바이트가 늦음 | 앱 처리·응답 헤더 생성 | 요청 핸들러와 의존 서비스 |
| 일부 큰 응답만 실패 | 응답 간 읽기 지연 | 스트리밍 방식과 timeout 설정 |
4. proxy_read_timeout의 뜻을 정확히 이해한다
Nginx 공식 문서에서 proxy_read_timeout은 upstream 응답을 읽는 두 연속 읽기 작업 사이의 제한 시간입니다. 전체 응답을 완성해야 하는 총 시간 제한과 같지 않습니다. 기본값은 공식 문서 기준 60초지만 배포판·설정 파일·상위 블록의 값이 실제 적용값을 결정합니다. 실제 설정은 nginx -T로 확인하세요. 연결 단계의 proxy_connect_timeout, 요청 전송 단계의 proxy_send_timeout과 혼동하지 않아야 합니다.
location /api/ {
proxy_pass http://app:8080;
proxy_connect_timeout 5s;
proxy_read_timeout 90s;
}
이 설정은 예시입니다. 장시간 작업이 정상 요구사항이라면 제한 시간을 조정할 수 있지만, 요청을 비동기 작업으로 분리하고 상태 조회 URL을 제공하는 편이 더 안정적인 경우도 있습니다. 변경 전후 응답 시간과 동시 요청 수를 측정하세요.
5. Docker 운영에서 함께 확인할 항목
- 컨테이너가 실행 중이고 재시작 루프가 없는지 확인합니다.
- upstream 서비스명·포트·네트워크가 실제 설정과 일치하는지 봅니다.
- CPU·메모리 제한과 OOM 기록을 확인합니다.
- DB 연결 풀과 외부 API 제한 시간에 대기 요청이 쌓이는지 측정합니다.
- 설정 변경 후 nginx -t가 통과할 때만 reload합니다.
- 정상 요청과 느린 요청을 모두 재시험합니다.
연결 실패 문구가 나온다면 Nginx 502와 Docker upstream 점검 가이드를, 컨테이너가 계속 재시작된다면 Docker Restarting 루프 점검을 참고하세요.
6. 자주 묻는 질문
Q. proxy_read_timeout을 300초로 늘리면 해결되나요?
정상적인 장시간 요청에는 필요할 수 있지만 병목 자체를 해결하지는 않습니다. 앱 처리 시간과 리소스 사용량부터 측정하세요.
Q. 헬스체크가 정상인데 왜 504가 나나요?
헬스체크는 보통 짧은 경로만 검사합니다. 특정 API의 DB 쿼리나 외부 호출이 느릴 수 있습니다.
Q. Nginx를 reload해도 바로 나아지지 않으면?
앱 자체가 느리거나 프록시 앞에 또 다른 로드밸런서의 제한 시간이 있을 수 있습니다. 요청 경로의 각 계층을 비교하세요.
공식 자료: Nginx proxy 모듈 지시어 · Docker Compose 네트워크 (확인일: 2026-09-24)
'소프트웨어개발' 카테고리의 다른 글
| AWS S3 403 AccessDenied 해결 순서: IAM·버킷 정책·KMS·공개 차단 점검 (0) | 2026.09.24 |
|---|---|
| 기업용 로그 관리 솔루션 선택법: 수집·보존·검색·마스킹 비용 체크리스트 (0) | 2026.09.24 |
| 기업용 비밀번호 관리자 선택 기준: SSO·SCIM·MFA·감사 로그까지 확인하기 (0) | 2026.09.24 |