Nginx-Tomcat Reverse Proxy 연동

Nginx가 앞단에서 요청을 받고 Tomcat HTTP Connector로 전달하는 reverse proxy 구성과 장애 점검 포인트를 정리한다.


proxy_pass 요청 경로

Client
  -> Nginx
  -> proxy_pass
  -> Tomcat HTTP Connector

Nginx-Tomcat 연동은 Nginx가 외부 요청을 받고 Tomcat의 HTTP Connector로 전달하는 구조다.

연동 방식 요약

Nginx의 proxy_pass는 요청을 뒤쪽 Tomcat으로 전달하고, proxy_set_header는 원래 요청 정보를 Tomcat과 애플리케이션에 전달한다.

기본 구성

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

Tomcat은 127.0.0.1:8080에서 내부 요청만 받게 두고, 외부에는 Nginx만 노출하는 방식이 흔하다.

proxy_pass 경로 주의

location /app/ {
    proxy_pass http://127.0.0.1:8080/app/;
}

locationproxy_pass의 끝 슬래시 여부는 backend로 전달되는 URI에 영향을 준다. 404가 나면 먼저 Nginx가 Tomcat에 어떤 URI로 요청을 넘겼는지 access log와 Tomcat access log를 비교한다.

upstream 구성

upstream tomcat_backend {
    server 127.0.0.1:8080 max_fails=3 fail_timeout=10s;
    server 127.0.0.1:8081 max_fails=3 fail_timeout=10s;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://tomcat_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

upstream은 여러 Tomcat을 하나의 backend 이름으로 묶는다. 세션을 서버 메모리에만 저장하는 애플리케이션이면 sticky session이 필요한지 별도로 판단한다.

HTTPS 앞단 구성

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/nginx/tls/example.crt;
    ssl_certificate_key /etc/nginx/tls/example.key;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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 https;
    }
}

TLS가 Nginx에서 종료되면 Tomcat은 HTTP 요청을 받는다. 애플리케이션이 HTTPS redirect나 secure cookie를 사용한다면 X-Forwarded-Proto와 애플리케이션 proxy 설정을 같이 확인한다.

timeout과 body 크기

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    client_max_body_size 50m;
}

업로드나 긴 요청이 있다면 timeout과 body 크기를 확인한다. Nginx timeout이 먼저 터지면 사용자는 504를 볼 수 있고, Tomcat이나 애플리케이션에서는 요청 처리 중이었을 수 있다.

장애별 확인

증상확인 지점
502Tomcat 기동 여부, 포트, proxy_pass 주소, firewall
504proxy_read_timeout, Tomcat thread, DB 지연
404location, proxy_pass URI 변환, Tomcat Context
업로드 실패client_max_body_size, WAS upload limit
실제 IP 누락X-Forwarded-For, Tomcat access log pattern
HTTPS loopX-Forwarded-Proto, 애플리케이션 proxy 설정

점검 명령

nginx -t
nginx -T | grep -n "proxy_pass"
curl -I http://127.0.0.1:8080/
curl -I http://example.com/
tail -f /var/log/nginx/error.log
tail -f $CATALINA_BASE/logs/localhost_access_log.*.txt

핵심은 Nginx를 거치지 않은 Tomcat 응답과 Nginx를 거친 응답을 비교하는 것이다.

관련 문서

관련 블로그 기록

공식 문서

닫기 전 질문

  • Nginx는 Tomcat에 어떤 URI와 Host로 요청을 넘기는가?
  • Tomcat은 Nginx 없이 직접 접근했을 때 정상 응답하는가?
  • HTTPS 종료 위치와 X-Forwarded-Proto 값은 일치하는가?
  • 502와 504 중 어느 상태 코드이며, 어느 계층의 timeout인가?