Nginx 리버스 프록시란?
Nginx 리버스 프록시는 클라이언트 요청을 받아 백엔드 애플리케이션 서버로 전달하고, 응답을 다시 클라이언트에 반환하는 중간 서버입니다. SSL 종료, 로드 밸런싱, 정적 파일 캐싱, 보안 헤더 주입을 한 곳에서 처리할 수 있어 운영 환경의 표준 구성으로 자리잡았습니다.
이 글에서는 Nginx 리버스 프록시의 핵심 설정, SSL 인증서 적용(Let’s Encrypt), 로드 밸런싱 전략, 보안 헤더 설정, 그리고 운영에서 자주 발생하는 문제와 해결법을 정리합니다.
왜 리버스 프록시가 필요한가
| 역할 | 직접 노출 시 문제 | 리버스 프록시로 해결 |
|---|---|---|
| SSL 종료 | 각 앱 서버마다 인증서 관리 | Nginx에서 한 번만 설정, 백엔드는 HTTP 통신 |
| 로드 밸런싱 | 단일 서버 장애 시 서비스 중단 | upstream 블록으로 다수 백엔드 분산 |
| 정적 파일 서빙 | 앱 서버가 정적 파일까지 처리해 성능 저하 | Nginx가 정적 파일을 직접 서빙 |
| 보안 | 백엔드 포트·기술 스택 노출 | 백엔드를 내부 네트워크에 숨기고 보안 헤더 추가 |
| 캐싱 | 동일 요청이 반복되어 백엔드 부하 증가 | proxy_cache로 응답 캐싱 |
기본 리버스 프록시 설정
가장 기본적인 리버스 프록시 설정은 다음과 같습니다. 클라이언트의 요청을 로컬 3000번 포트에서 동작하는 Node.js 앱으로 전달합니다.
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
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는 백엔드가 클라이언트의 실제 IP와 프로토콜을 인식할 수 있도록 원본 요청 정보를 전달합니다. 이 헤더가 없으면 백엔드 로그에 모든 요청이 127.0.0.1에서 온 것으로 기록됩니다.
Let’s Encrypt SSL 인증서 적용
Certbot을 사용하면 무료 SSL 인증서를 자동으로 발급받고 갱신할 수 있습니다.
# Certbot 설치 (Ubuntu/Debian)
sudo apt install certbot python3-certbot-nginx
# 인증서 발급 + Nginx 설정 자동 수정
sudo certbot --nginx -d example.com -d www.example.com
# 자동 갱신 테스트
sudo certbot renew --dry-run
Certbot이 자동으로 생성하는 SSL 설정은 다음과 같은 구조입니다.
server {
listen 443 ssl http2;
server_name example.com;
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 ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
upstream을 활용한 로드 밸런싱
여러 백엔드 서버가 있을 때 upstream 블록으로 트래픽을 분산할 수 있습니다.
upstream app_servers {
least_conn; # 연결 수가 적은 서버에 우선 배분
server 127.0.0.1:3001 weight=3;
server 127.0.0.1:3002 weight=2;
server 127.0.0.1:3003 backup; # 다른 서버 모두 다운 시에만 사용
}
server {
listen 443 ssl http2;
server_name example.com;
location / {
proxy_pass http://app_servers;
proxy_next_upstream error timeout http_502 http_503;
proxy_next_upstream_tries 2;
}
}
로드 밸런싱 알고리즘 비교
| 알고리즘 | 설정 | 적합한 상황 |
|---|---|---|
| Round Robin | 기본값 (별도 설정 불필요) | 백엔드 서버 스펙이 동일할 때 |
| Least Connections | least_conn |
요청 처리 시간이 불균일할 때 |
| IP Hash | ip_hash |
세션 고정(sticky session)이 필요할 때 |
| Weighted | weight=N |
서버 스펙이 다를 때 |
보안 헤더 설정
리버스 프록시에서 보안 헤더를 일괄 추가하면 백엔드 애플리케이션 코드를 수정하지 않고도 보안 수준을 높일 수 있습니다.
# 보안 헤더 (server 또는 location 블록에 추가)
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;
# 백엔드 정보 숨기기
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
WebSocket 프록시 설정
실시간 통신이 필요한 애플리케이션(채팅, 대시보드 등)에서는 WebSocket 업그레이드를 처리해야 합니다.
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s; # WebSocket 연결 유지 시간
}
프록시 캐싱으로 백엔드 부하 줄이기
자주 변하지 않는 API 응답이나 페이지를 Nginx에서 캐싱하면 백엔드 요청 수를 줄일 수 있습니다.
# http 블록에 캐시 경로 정의
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m
max_size=1g inactive=60m use_temp_path=off;
# location 블록에서 캐시 적용
location /api/ {
proxy_pass http://app_servers;
proxy_cache api_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$request_method$host$request_uri";
add_header X-Cache-Status $upstream_cache_status;
}
운영에서 자주 발생하는 문제와 해결법
| 문제 | 증상 | 해결법 |
|---|---|---|
| 502 Bad Gateway | 백엔드 서버 미응답 | 백엔드 프로세스 상태 확인, proxy_connect_timeout 조정 |
| 504 Gateway Timeout | 백엔드 응답 시간 초과 | proxy_read_timeout 값 증가 (기본 60초) |
| 클라이언트 IP가 127.0.0.1로 기록 | X-Real-IP 헤더 누락 |
proxy_set_header X-Real-IP $remote_addr 추가 |
| 큰 파일 업로드 실패 | 413 Request Entity Too Large | client_max_body_size 100m 설정 |
| HTTPS 리다이렉트 무한 루프 | ERR_TOO_MANY_REDIRECTS | X-Forwarded-Proto 헤더 확인, 앱의 프록시 신뢰 설정 |
실전 체크리스트
proxy_set_header로 Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto 4개 헤더를 반드시 설정- SSL 인증서 자동 갱신 cron이 동작하는지
certbot renew --dry-run으로 검증 nginx -t로 설정 문법 검사 후nginx -s reload로 무중단 반영- 보안 헤더(HSTS, X-Frame-Options, CSP)가 응답에 포함되는지
curl -I로 확인 - upstream 서버 장애 시
proxy_next_upstream으로 자동 페일오버 설정 - access_log, error_log 경로와 로테이션(logrotate) 설정 확인
관련 글
- Docker Multi-Stage Build 실전 가이드 — Nginx 뒤에서 동작하는 컨테이너 이미지를 경량화하는 방법을 확인하세요.
- Spring Boot + Flyway 심화: 운영 DB 마이그레이션 관리 — Nginx 리버스 프록시 뒤에서 무중단 배포와 DB 마이그레이션을 안전하게 수행하는 방법을 함께 참고하세요.
Nginx 리버스 프록시 설정에 대해 궁금한 점이 있거나, 현재 인프라에 맞는 구성이 필요하시면 문의 페이지를 통해 연락해 주세요.