이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Nginx reverse proxy와 upstream은 Spring 백엔드 앞에서 어떤 책임을 가지는가?
- 502, 504, 499가 Spring 장애와 어떻게 다르게 해석되는가?
- proxy header와 upstream 설정을 변경할 때 무엇을 검증해야 하는가?
개요
Reverse proxy는 client와 Spring 애플리케이션 사이의 HTTP 경계다.
사용자는 Nginx의 public endpoint로 요청하고, Nginx는 내부 upstream으로 요청을 전달한다.
이 구조는 public port, TLS, header, timeout, log를 Spring 프로세스와 분리한다.
백엔드 개발자는 Nginx를 단순 전달기로 보지 말고, 요청이 Spring에 도달하기 전 어디서 실패하는지 구분할 수 있어야 한다.
요청 흐름
client
-> Nginx server block
-> location rule
-> upstream spring_api
-> Spring application
-> DB or RedisNginx access log에 기록이 있는데 Spring log에 요청이 없다면 경계는 Nginx와 upstream 사이일 가능성이 크다.
Spring log에는 요청이 있고 500이 났다면 애플리케이션 내부 오류를 먼저 봐야 한다.
이 구분이 되지 않으면 timeout, retry, scale 조치를 잘못 선택하게 된다.
기본 설정 예시
upstream spring_api {
server 127.0.0.1:8080 max_fails=3 fail_timeout=10s;
keepalive 32;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://spring_api;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Request-ID $request_id;
}
}upstream spring_api는 Nginx가 요청을 보낼 내부 목적지다.
같은 서버에서 Spring이 8080으로 실행 중이면 127.0.0.1:8080이 될 수 있다.
Docker network 안이라면 api:8080처럼 service name을 쓸 수 있다.
중요한 것은 Nginx가 보는 주소와 Spring이 실제 listen하는 주소가 일치해야 한다는 점이다.
Header 전달
Reverse proxy 뒤의 Spring은 원래 client 정보를 직접 알지 못한다.
그래서 Nginx가 header로 원래 정보를 전달한다.
Host는 원래 도메인을 보존한다.
X-Forwarded-For는 client IP 추적에 쓰인다.
X-Forwarded-Proto는 원래 요청이 HTTP인지 HTTPS인지 알려 준다.
이 값이 없거나 Spring이 신뢰하지 않으면 HTTPS redirect, secure cookie, absolute URL 생성이 틀어질 수 있다.
Status Code 해석
502는 Nginx가 upstream과 정상 통신하지 못했다는 신호다.
Spring process가 내려갔거나 port가 틀렸거나 upstream connection이 거부될 때 나타난다.
504는 upstream이 제한 시간 안에 응답하지 못했다는 신호다.
Spring이 느리거나 DB 대기로 막혀 있을 수 있다.
499는 client가 응답을 기다리지 않고 연결을 끊었음을 뜻한다.
사용자 timeout, mobile network, frontend abort, 너무 긴 API 응답이 원인일 수 있다.
변경 전 검증
nginx -t
curl -I http://api.example.com/actuator/health
tail -n 100 /var/log/nginx/api.access.log
tail -n 100 /var/log/nginx/error.lognginx -t는 문법 검증일 뿐 실제 upstream 연결 성공을 보장하지 않는다.
변경 후에는 Nginx reload, health endpoint, access log, Spring log를 같은 시간대로 확인해야 한다.
운영 체크리스트
- Nginx upstream 주소와 Spring listen 주소가 일치하는가?
Host,X-Forwarded-For,X-Forwarded-Proto를 전달하는가?- Spring이 forwarded header를 처리하도록 설정되어 있는가?
- 502, 504, 499를 구분해 볼 수 있는 access log 필드가 있는가?
nginx -t와 reload 절차가 문서화되어 있는가?- upstream 변경 후 health endpoint와 핵심 API를 확인하는가?
- 설정 rollback 파일이나 이전 배포 artifact가 남아 있는가?
장애 신호
- access log에는 502가 늘지만 Spring log에는 요청이 없다.
- error log에
connect() failed또는connection refused가 반복된다. - 504가 늘고 Spring에서는 DB query 또는 외부 API 대기 시간이 길다.
- 499가 급증하고 frontend timeout 또는 mobile client 취소가 함께 보인다.
- HTTPS redirect URL이 HTTP로 생성된다.
- client IP가 모두 Nginx 서버 IP로 기록된다.
안전한 완화 조치
upstream 장애가 의심되면 먼저 Spring process와 listen port를 확인한다.
ss -lntp | grep ':8080'
curl -fsS http://127.0.0.1:8080/actuator/healthport가 맞는데도 502라면 Nginx가 실행되는 위치에서 같은 주소로 접근 가능한지 확인한다.
504라면 timeout을 바로 크게 늘리지 말고 Spring 처리 시간과 DB 대기 상태를 같이 본다.
Header 문제는 Nginx 설정과 Spring forwarded header 설정을 함께 고쳐야 한다.
여러 설정을 동시에 바꾸면 어떤 변경이 장애를 완화했는지 알기 어렵다.
인프라 담당자와 공유할 자료
증상: api.example.com 요청 502 증가
기간: 2026-07-01 14:05~14:18 KST
Nginx upstream: 127.0.0.1:8080
Spring health: 127.0.0.1:8080 connection refused
최근 변경: systemd service 배포 후 Spring listen port 8081로 변경
필요 조치: upstream port 수정 또는 Spring listen port rollback장애 공유에는 status code만 쓰지 말고 Nginx가 본 upstream 주소, Spring health, 변경 시간을 함께 넣는다.
실전 팁
- 502는 Nginx와 Spring 사이의 연결 문제부터 본다.
- 504는 timeout 값보다 upstream 처리 지연 원인을 먼저 본다.
- 499는 사용자 취소와 서버 지연을 같이 의심한다.
- Header 변경은 인증, redirect, cookie 동작과 같이 검증한다.
- Nginx reload는
nginx -t성공 후에만 수행한다.
위험 신호!
- Spring 500과 Nginx 502를 같은 문제로 취급한다.
- upstream 주소를 바꾸고 health 확인 없이 reload한다.
- client IP를 잃었는데 보안 로그와 rate limit이 정상이라고 가정한다.
- 504가 난다고 timeout만 크게 늘린다.
- 장애 중 Nginx 설정과 Spring 설정을 동시에 여러 개 바꾼다.
확인 질문
확인 질문
- 502와 Spring 500의 차이는 무엇인가?
- 502는 Nginx가 upstream과 정상 통신하지 못한 것이고, Spring 500은 upstream인 Spring이 요청을 받아 내부 오류로 응답한 것이다.
X-Forwarded-Proto가 중요한 이유는 무엇인가?
- TLS가 Nginx에서 끝난 뒤에도 Spring이 원래 요청 scheme을 알아야 redirect, secure cookie, absolute URL을 올바르게 처리할 수 있기 때문이다.
- upstream 변경 후 최소 검증은 무엇인가?
nginx -t, reload 결과, health endpoint, access log status, Spring log 수신 여부를 같은 시간대로 확인하는 것이다.