업스트림과 리버스 프록시 기초
Nginx의 리버스 프록시 기능은 클라이언트 요청을 백엔드 서버(Tomcat 등)로 전달하는 핵심 역할을 합니다. proxy_pass, 헤더 전달, 버퍼 설정, 타임아웃을 올바르게 구성해야 프록시 구성이 안정적으로 동작합니다.
리버스 프록시 개념
리버스 프록시(Reverse Proxy) 는 클라이언트와 백엔드 서버 사이에서 요청을 중계하는 서버입니다. 클라이언트는 Nginx에만 연결하고, 백엔드 서버(Tomcat 등)의 존재를 모릅니다.
[클라이언트]
│ GET /api/products HTTP/1.1
│ Host: example.com
▼
[Nginx: 리버스 프록시]
│ GET /api/products HTTP/1.1
│ Host: example.com
│ X-Real-IP: 클라이언트 IP
▼
[Tomcat: 백엔드 서버]
│
└─ 응답 → Nginx → 클라이언트
proxy_pass 기본 설정
server {
listen 80;
server_name example.com;
# /api/ 하위 요청을 Tomcat으로 전달
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
}
proxy_pass에서 URI 처리 차이
proxy_pass 뒤에 URI를 포함하느냐에 따라 전달되는 경로가 달라집니다.
# 케이스 1: URI 없음 — location의 경로가 그대로 전달됨
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
# GET /api/users → 백엔드: GET /api/users
# 케이스 2: URI 있음 (/로만 끝남) — location 경로가 /로 교체됨
location /api/ {
proxy_pass http://127.0.0.1:8080/;
}
# GET /api/users → 백엔드: GET /users (/api/가 /로 교체)
# 케이스 3: URI 있음 (경로 포함) — location 경로가 해당 경로로 교체됨
location /api/ {
proxy_pass http://127.0.0.1:8080/app/;
}
# GET /api/users → 백엔드: GET /app/users (/api/가 /app/로 교체)
헤더 전달 설정
Nginx가 백엔드에 요청을 전달할 때 기본적으로 일부 헤더는 제거됩니다. 클라이언트의 실제 IP, 원본 도메인 등을 백엔드에서 알 수 있도록 헤더를 추가해야 합니다.
location / {
proxy_pass http://127.0.0.1:8080;
# 원본 Host 헤더 전달 (Tomcat이 server_name을 알 수 있도록)
proxy_set_header Host $host;
# 클라이언트 실제 IP 전달
proxy_set_header X-Real-IP $remote_addr;
# 프록시 체인의 모든 IP 목록 (기존 X-Forwarded-For에 추가)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 원본 프로토콜 전달 (http 또는 https)
proxy_set_header X-Forwarded-Proto $scheme;
# 프록시 연결임을 나타내는 헤더 (일부 앱에서 사용)
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
Spring Boot에서 X-Forwarded-For 활용
Spring Boot 앱에서 실제 클라이언트 IP를 얻으려면:
// application.yml
server:
forward-headers-strategy: native
// 또는 Spring Security와 함께
// WebMvcConfigurer에서 RemoteIpFilter 등록
upstream 블록 — 백엔드 서버 그룹 정의
여러 백엔드 서버를 관리하거나, 이름으로 참조하고 싶을 때 upstream 블록을 사용합니다.
http {
# 백엔드 서버 그룹 정의
upstream tomcat_backend {
server 127.0.0.1:8080;
}
server {
location /api/ {
proxy_pass http://tomcat_backend;
}
}
}
upstream 공통 설정 분리
반복되는 proxy 설정은 별도 파일로 분리하는 것이 좋습니다.
# /etc/nginx/conf.d/proxy-params.conf
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_http_version 1.1;
proxy_set_header Connection "";
# 사용 시
location / {
proxy_pass http://tomcat_backend;
include /etc/nginx/conf.d/proxy-params.conf;
}
버퍼 설정
Nginx는 백엔드에서 받은 응답을 버퍼에 담았다가 클라이언트에 전달합니다. 버퍼 설정이 적절하지 않으면 메모리 낭비나 성능 저하가 발생합니다.
location / {
proxy_pass http://tomcat_backend;
# 응답 버퍼링 활성화 (기본: on)
# off면 백엔드 응답을 버퍼 없이 즉시 클라이언트에 전달
proxy_buffering on;
# 응답 헤더 읽기용 버퍼 크기 (기본: 1 4k|8k)
proxy_buffer_size 4k;
# 응답 본문 버퍼 (개수 × 크기)
proxy_buffers 8 16k;
# 클라이언트에 전달 전 버퍼링 최대 크기
proxy_busy_buffers_size 32k;
# 임시 파일로 스필할 최대 크기 (버퍼 초과 시)
proxy_max_temp_file_size 1024m;
}
스트리밍 응답 (SSE, WebSocket)
스트리밍 또는 실시간 응답의 경우 버퍼링을 비활성화해야 즉각 전달됩니다.
# Server-Sent Events (SSE)
location /api/stream {
proxy_pass http://tomcat_backend;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s; # 1시간 (SSE 연결 유지)
add_header X-Accel-Buffering no;
}
# WebSocket
location /ws/ {
proxy_pass http://tomcat_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
타임아웃 설정
location / {
proxy_pass http://tomcat_backend;
# Nginx가 백엔드에 TCP 연결을 맺는 최대 대기 시간
proxy_connect_timeout 10s;
# Nginx가 백엔드에 요청 전송 완료까지 최대 대기 시간
proxy_send_timeout 60s;
# Nginx가 백엔드 응답 읽기 완료까지 최대 대기 시간
# 이 시간 내 응답이 없으면 504 Gateway Timeout 반환
proxy_read_timeout 60s;
}
| 타임아웃 | 기본값 | 설명 |
|---|---|---|
proxy_connect_timeout | 60s | 백엔드 TCP 연결 대기 |
proxy_send_timeout | 60s | 요청 전송 대기 |
proxy_read_timeout | 60s | 응답 수신 대기 |
HTTP 버전과 Keep-Alive
Nginx와 백엔드 사이에 HTTP/1.1 Keep-Alive를 유지하면 TCP 연결을 재사용하여 성능이 향상됩니다.
upstream tomcat_backend {
server 127.0.0.1:8080;
keepalive 32; # 유휴 Keep-Alive 연결 최대 32개 유지
}
location /api/ {
proxy_pass http://tomcat_backend;
proxy_http_version 1.1; # HTTP/1.1 사용 (Keep-Alive 필요)
proxy_set_header Connection ""; # Connection: close 헤더 제거
}
에러 처리 및 백업 서버
upstream tomcat_backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081 backup; # 메인 서버 다운 시 사용
# 3번 실패하면 30초간 비활성화
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
}
server {
location / {
proxy_pass http://tomcat_backend;
proxy_next_upstream error timeout http_502 http_503;
proxy_intercept_errors on;
error_page 502 503 504 /maintenance.html;
}
}
정리
| 설정 항목 | 지시어 | 핵심 포인트 |
|---|---|---|
| 요청 전달 | proxy_pass | URI 포함 여부에 따라 경로 처리 다름 |
| 헤더 전달 | proxy_set_header | Host, X-Real-IP, X-Forwarded-For 필수 |
| 버퍼링 | proxy_buffering | 스트리밍은 off, 일반 응답은 on |
| 타임아웃 | proxy_read_timeout | 느린 API에 맞게 조정 |
| Keep-Alive | keepalive + HTTP/1.1 | TCP 재사용으로 성능 향상 |