HTTP 프록시 연동 — proxy_pass 완전 정복
Nginx에서 proxy_pass로 Tomcat을 연동하는 것은 가장 표준적인 방법입니다. 헤더 전달, 실제 IP 전달, 업스트림 정의까지 실무에서 반드시 알아야 할 설정을 다룹니다.
기본 proxy_pass 설정
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
이것만으로도 Nginx가 Tomcat에 요청을 전달합니다. 하지만 실무에서는 헤더 전달, 타임아웃, 버퍼 등 추가 설정이 필요합니다.
upstream 블록으로 백엔드 정의
upstream 블록으로 Tomcat을 명시적으로 정의하면 가독성이 높아지고 여러 인스턴스로 확장하기 쉽습니다.
# /etc/nginx/conf.d/upstream.conf
upstream tomcat_backend {
server 127.0.0.1:8080;
keepalive 32; # 업스트림 keep-alive 연결 유지 수
}
# /etc/nginx/sites-available/myapp.conf
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://tomcat_backend;
}
}
필수 프록시 헤더 설정
# /etc/nginx/snippets/proxy-headers.conf
# 이 파일을 include로 재사용
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-Forwarded-Port $server_port;
# HTTP 버전 업그레이드 (keepalive 사용 시 필수)
proxy_http_version 1.1;
proxy_set_header Connection "";
| 헤더 | 값 | Tomcat에서의 역할 |
|---|---|---|
Host | $host | 가상 호스트 매칭 |
X-Real-IP | $remote_addr | 실제 클라이언트 IP |
X-Forwarded-For | $proxy_add_x_forwarded_for | 프록시 체인 IP 목록 |
X-Forwarded-Proto | $scheme | 원래 프로토콜(http/https) |
실제 IP 전달 (RemoteIpValve)
Tomcat이 request.getRemoteAddr()에서 Nginx IP(127.0.0.1) 대신 실제 클라이언트 IP를 반환하도록 설정합니다.
Nginx 설정
# X-Forwarded-For 헤더 정리 (신뢰할 수 없는 IP 제거)
set_real_ip_from 127.0.0.1; # Nginx 자신
set_real_ip_from 10.0.0.0/8; # 내부 네트워크
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Tomcat server.xml 설정
<!-- Host 태그 안에 추가 -->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="x-forwarded-for"
protocolHeader="x-forwarded-proto"
internalProxies="127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+"/>
이렇게 하면:
request.getRemoteAddr()→ 실제 클라이언트 IP 반환request.isSecure()→ Nginx가 HTTPS로 받았다면true반환- 로그에 실제 클라이언트 IP 기록
완전한 프록시 설정 예시
upstream tomcat_backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
# SSL 설정
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 실제 IP 복원
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# 클라이언트 요청 설정
client_max_body_size 50m; # 파일 업로드 크기 제한
client_body_buffer_size 128k;
# Tomcat으로 프록시
location / {
proxy_pass http://tomcat_backend;
# 필수 헤더
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-Forwarded-Port $server_port;
# HTTP/1.1 + keepalive
proxy_http_version 1.1;
proxy_set_header Connection "";
# 타임아웃
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 버퍼
proxy_buffering on;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
}
# 에러 페이지
error_page 502 503 504 /error/5xx.html;
location = /error/5xx.html {
root /var/www/myapp;
internal;
}
# 접근 로그
access_log /var/log/nginx/myapp_access.log combined;
error_log /var/log/nginx/myapp_error.log warn;
}
proxy_pass URI 처리 주의사항
proxy_pass에 URI를 포함하느냐 여부에 따라 동작이 달라집니다.
# URI 없이 — location 경로 그대로 전달
location /app/ {
proxy_pass http://127.0.0.1:8080;
# /app/foo → http://127.0.0.1:8080/app/foo
}
# URI 포함 — location 경로를 대체
location /app/ {
proxy_pass http://127.0.0.1:8080/;
# /app/foo → http://127.0.0.1:8080/foo (경로 변환)
}
# API 경로 변환 예시
location /api/ {
proxy_pass http://127.0.0.1:8080/api/v1/;
# /api/users → http://127.0.0.1:8080/api/v1/users
}
특수 경로 처리
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; # WebSocket 연결 유지
proxy_send_timeout 3600s;
}
SSE(Server-Sent Events) 프록시
location /events/ {
proxy_pass http://tomcat_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off; # SSE는 버퍼링 비활성화 필수
proxy_cache off;
proxy_read_timeout 3600s;
}
파일 업로드 경로
location /upload/ {
proxy_pass http://tomcat_backend;
client_max_body_size 500m; # 대용량 파일 업로드
proxy_request_buffering off; # 청크 전송 지원
proxy_read_timeout 600s; # 업로드 시간 여유
}
프록시 설정 검증
# Nginx 설정 검증
sudo nginx -t
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# 리로드 (무중단)
sudo nginx -s reload
# 프록시 연결 테스트
curl -v https://example.com/api/test
# X-Forwarded-For, X-Forwarded-Proto 헤더 확인
# Tomcat에서 실제 IP 확인
curl -s https://example.com/debug/ip # 앱에서 request.getRemoteAddr() 반환
Summary
| 설정 | 내용 |
|---|---|
| 업스트림 | upstream 블록 + keepalive 32 |
| 필수 헤더 | Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto |
| HTTP 버전 | proxy_http_version 1.1 + Connection "" (keepalive 필수) |
| 실제 IP | Nginx: real_ip_header + Tomcat: RemoteIpValve |
| WebSocket | Upgrade: $http_upgrade + Connection: upgrade |
| SSE | proxy_buffering off + proxy_cache off |