왜 Nginx를 선택했는가
우리 서비스는 단일 진입점에서 SSL/TLS 종료, 리버스 프록시, SSE 스트리밍 중계를 처리하고
필요 시 로드밸런싱과 정적 파일 서빙까지 아우를 수 있어야 했습니다.
이러한 요구사항에 가장 잘 맞는 선택지가 이벤트 기반 논블로킹 아키텍처의 Nginx였습니다.
Nginx는 경량 코어와 모듈식 설계로 동시성 트래픽을 효율적으로 처리하며
리버스 프록시와 TLS 종료 역할을 수행해줍니다.
특히 SSE처럼 지속 연결을 오래 유지해야 하는 워크로드에서
Nginx는 버퍼링 제어와 타임아웃 제어가 직관적이어서 선택하게되었습니다.
Nginx vs Apache
| 구분 | Nginx | Apache |
| 처리 모델 | 이벤트 기반, 비동기/논블로킹 | MPM(멀티프로세싱 모듈): prefork(프로세스), worker/event(스레드 기반) 선택형 |
| 리버스 프록시 | proxy_pass 기반 표준 기능, 헤더·버퍼·타임아웃 세밀 제어 | 모듈로 가능하나 설정이 상대적으로 복잡해질 수 있음 |
| HTTPS/TLS 종료 | ssl_certificate, ssl_certificate_key로 TLS 종단, HTTP/2/3 지원 | 모듈 구성으로 가능(HTTP/2는 별도 모듈) |
| 정적 파일 서빙 | 커널 sendfile/버퍼 튜닝으로 고성능 | 모듈 구성 및 MPM 선택에 영향 |
| .htaccess | 없음(중앙집중 설정) → 성능·일관성 | .htaccess 지원(디렉터리 단위 유연성, 대신 런타임 비용) |
| 장기 연결(SSE 등) | proxy_buffering off, X-Accel-Buffering 지원 | 모듈·버퍼 정책에 따라 설정 난이도 차이 |
결론적으로 우리 프로젝트에 구현하려는 기능(리버스 프록시 + TLS 종료 + SSE 스트리밍)을 위해서는
Nginx의 이벤트 기반 모델과 섬세한 프록시/버퍼 제어가 개발과 운영 단순성과 성능 면에서 유리하다고 판단했습니다.
Nginx가 맡는 7가지 핵심 역할
Nginx에 제가 말씀드린 기능 외에도 다양한 기능이 존재합니다.
아래는 Nginx의 7가지 핵심 기능입니다.
- 리버스 프록시: 외부 요청을 받아 내부 Spring Boot로 전달하며, 내부 포트를 외부에 노출하지 않습니다.
- SSL/TLS 종료: ssl_certificate와 ssl_certificate_key로 HTTPS를 복호화/재암호화합니다.
- 로드밸런싱(확장 시): 여러 앱 인스턴스에 트래픽을 분산합니다.
- 정적 파일 서빙: HTML/CSS/JS를 직접 서빙해 앱 부하를 줄일 수 있습니다.
- 캐싱/압축: 응답 캐싱 및 gzip으로 대역폭 절감.
- 프로토콜 업그레이드: HTTP/2/3 지원으로 지연과 헤더 오버헤드를 줄입니다.
- 실시간 스트림 중계: SSE 시 proxy_buffering off 및 타임아웃 튜닝으로 지연 없이 흘려보냅니다.
HTTPS란 무엇이며, 왜 필요한가
SSL 설정을 하기위해 이론적인 내용을 먼저 학습하고자 HTTPS의 필요성을 찾아보고
Nginx에서 SSL 인증서를 어떻게 관리할지 정리해보았습니다.
HTTPS는 HTTP 위에 TLS(Transport Layer Security) 를 얹은 보안 통신 방식입니다.
TLS는 SSL과 동일어이며 용어가 변경되었지만 여전히 SSL인증서라고 많이 불리는 것 같습니다.
이는 기밀성(암호화), 무결성, 서버 인증을 제공해줍니다.
브라우저는 이러한 서버 인증서를 확인해 진짜 서버인지 검증한 뒤
대칭키를 수립하고 이후 모든 트래픽이 암호화되어 전송됩니다.
다른 서비스 사례를 보아도 Let’s Encrypt + Certbot으로
인증서를 자동 발급하고 갱신한 케이스가 많아 저희도 이 방식을 도입했습니다.
Let’s Encrypt는 ACME 프로토콜 기반으로 CA가
HTTP-01(=/.well-known/acme-challenge/…) 같은 도메인 소유 검증을 수행하고
검증 후 신뢰된 인증서를 발급해줍니다.
우리 서비스에서의 요청 흐름
HTTPS 요청/응답 흐름
클라이언트(브라우저)
↓
HTTPS (443) Nginx (SSL 복호화, TLS 종료)
↓
평문 HTTP Spring Boot (8080)
↓
PostgreSQL (5432)
↓
Spring Boot (응답 생성)
↓
Nginx (재암호화)
↓
HTTPS 클라이언트로 응답
그리고 내부로는 평문 HTTP로 프록시하므로 애플리케이션 서버는 TLS 부담 없이 비즈니스 로직에 집중할 수 있습니다.
전체 요청 흐름 (시퀀스 다이어그램)
전체 요청 흐름을 시퀀스 다이어그램으로 작성해보면 아래와 같습니다.
sequenceDiagram
participant C as Client (Extension/웹)
participant N as Nginx (443/80)
participant S as Spring Boot (8080)
participant D as Postgres (5432)
Note over C: 일반 요청(GET/POST)
C->>N: HTTPS 요청 /api/tests/{id}
N->>S: 프록시 전송 (HTTP/1.1)
S->>D: 쿼리/저장
D-->>S: 결과
S-->>N: JSON 응답
N-->>C: HTTPS 응답
Note over C: 실시간(SSE)
C->>N: GET /api/tests/{id}/events (text/event-stream)
N->>S: 프록시 + 버퍼링 off
S-->>C: event: ping/data:… (연결 유지)
S->>D: (중간/최종 결과 저장)
S-->>N: SSE 이벤트(증분/최종)
N-->>C: 브라우저로 즉시 푸시
alt 연결 끊김
C->>N: 재연결(+Last-Event-ID)
N->>S: 전달
S->>D: (필요 시 미수신분 조회)
S-->>C: 누락분 재전송/최신 스냅샷
end
SSE 경로는 버퍼링을 끄고(proxy_buffering off) 헤더로 X-Accel-Buffering: no 를 추가해
즉시 전송이 이루어지게 합니다.
또한 proxy_read_timeout 으로 장기 연결이 중간에서 끊기지 않게 조정했습니다.
운영 관점 체크리스트
- TLS 종료 위치: Nginx(443)에서 종료하고 내부는 HTTP로 프록시합니다.
- HTTP/2/3 활성화: listen 443 ssl http2;(+ HTTP/3 환경이면 v3 모듈/설정)로 지연·헤더 오버헤드 감소를 노립니다.
- SSE 안정화: proxy_buffering off, add_header X-Accel-Buffering no;, 적절한 proxy_read_timeout(LB idle 고려)
- 도메인 인증/갱신 자동화: Let’s Encrypt ACME 챌린지 경로 노출 및 주기적 갱신(Certbot)을 합니다.
- 보안 헤더: X-Content-Type-Options, X-Frame-Options, Cache-Control 등 프록시 레벨에서 강화해줍니다.
- 접속 로그/에러 로그: 접근 패턴·지연·SSE 끊김 원인 분석에 유용합니다.
마무리
Nginx는 경량·이벤트 기반 구조 위에 리버스 프록시, TLS 종료, HTTP/2/3, 스트리밍 중계 등
웹 게이트웨이의 필수 역할을 표준적으로 제공합니다.
우리 서비스는 여러 기능 중 보안(HTTPS), 성능(프록시·압축), 실시간성(SSE) 을
Nginx라는 관문에서 일관되게 다루도록 설계했습니다.
2편에서는 위 개념을 실제 설정 코드로 연결한 내용으로 찾아오겠습니다.
'프로젝트 > 웹 성능 테스트' 카테고리의 다른 글
| 비동기 통신 방식 비교와 A/B 테스트 설계 (0) | 2025.11.09 |
|---|---|
| Nginx 도입 2편: 적용 (0) | 2025.11.09 |
| Server Sent Events(SSE): 구현 (0) | 2025.11.02 |
| Server Sent Events(SSE): 설계 (0) | 2025.11.02 |
| upsert 적용 (0) | 2025.10.29 |