프로덕션 Nginx 설정 구조
단순 리버스 프록시를 넘어, Nginx를 로드밸런서·캐시서버·WAF 전방 배치 레이어로 활용하는 패턴을 다룹니다.
1. upstream 로드밸런싱 전략
기본 구성 (Round Robin)
Nginx
http {
upstream app_servers {
least_conn; # 최소 연결 수 기준 분배 (Round Robin 대신 권장)
server 10.0.1.10:8080 weight=3; # 가중치: 트래픽 30%
server 10.0.1.11:8080 weight=2;
server 10.0.1.12:8080 weight=1;
server 10.0.1.13:8080 backup; # 나머지 전부 다운 시 사용
keepalive 32; # upstream keepalive 연결 풀
keepalive_timeout 60s;
}
server {
listen 443 ssl http2;
server_name api.example.com;
location / {
proxy_pass http://app_servers;
proxy_http_version 1.1;
proxy_set_header Connection ""; # keepalive 유지
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;
}
}
}세션 지속성 (Sticky Session)
Nginx
upstream app_servers {
ip_hash; # 동일 클라이언트 IP는 항상 같은 서버로
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}헬스체크 (Nginx Plus 없이 수동 구현)
Nginx
upstream app_servers {
server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
}
# max_fails: 30초 내 3번 실패 시 해당 서버 일시 제외2. proxy_cache — 콘텐츠 캐싱
Nginx
http {
# 캐시 저장소 정의 (nginx.conf 최상단 http 블록)
proxy_cache_path /var/cache/nginx
levels=1:2 # 디렉터리 계층 구조
keys_zone=app_cache:50m # 메모리 내 키 저장소 50MB
max_size=10g # 최대 디스크 사용량
inactive=60m # 60분간 미접근 시 삭제
use_temp_path=off;
server {
location / {
proxy_pass http://app_servers;
proxy_cache app_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 10m; # 200/302 응답 10분 캐시
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
proxy_cache_lock on; # 동일 키 중복 요청 방지 (thundering herd)
proxy_cache_lock_timeout 5s;
# 캐시 상태 헤더 노출 (디버깅용)
add_header X-Cache-Status $upstream_cache_status;
}
# 캐시 우회: 특정 조건에서
location /api/user {
proxy_pass http://app_servers;
proxy_cache_bypass $cookie_session; # 세션 쿠키 있으면 캐시 건너뜀
proxy_no_cache $cookie_session;
}
# 캐시 퍼지 (내부에서만 허용)
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge app_cache "$scheme$request_method$host$1";
}
}
}Bash
# 캐시 상태 확인
curl -I https://example.com/static/logo.png | grep X-Cache-Status
# HIT / MISS / BYPASS / UPDATING
# 캐시 디렉터리 크기 확인
du -sh /var/cache/nginx
# 캐시 전체 초기화
sudo rm -rf /var/cache/nginx/*
sudo nginx -s reload3. Rate Limiting — DDoS / 무차별 대입 방어
Nginx
http {
# 요청 속도 제한 존 정의
limit_req_zone $binary_remote_addr zone=api_limit:20m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=3r/m;
limit_req_zone $http_x_api_key zone=key_limit:10m rate=100r/s;
# 연결 수 제한 존
limit_conn_zone $binary_remote_addr zone=conn_limit:20m;
server {
# API 엔드포인트: 초당 10req, 버스트 20개 허용
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 20;
limit_req_status 429;
proxy_pass http://app_servers;
}
# 로그인: 분당 3회, 초과 시 큐잉 (nodelay 없음)
location /auth/login {
limit_req zone=login_limit burst=5;
limit_req_status 429;
proxy_pass http://app_servers;
}
# Rate Limit 초과 응답 커스터마이징
error_page 429 /rate_limit.json;
location = /rate_limit.json {
internal;
default_type application/json;
return 429 '{"error":"Too Many Requests","retry_after":60}';
}
}
}4. 보안 헤더 및 SSL 강화
Nginx
http {
# TLS 설정
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
# HSTS (Strict-Transport-Security)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# DH 파라미터 생성 및 적용
ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
server {
# 보안 헤더 일괄 설정
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 Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com; img-src 'self' data: cdn.example.com; style-src 'self' 'unsafe-inline';" always;
# 서버 정보 숨기기
server_tokens off;
# HTTP → HTTPS 리다이렉트
if ($scheme = http) {
return 301 https://$host$request_uri;
}
}
}5. 성능 튜닝 — worker 및 커넥션 최적화
Nginx
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto; # CPU 코어 수에 맞게 자동 설정
worker_rlimit_nofile 65535; # 파일 디스크립터 한도
events {
worker_connections 4096; # worker당 최대 연결 수
use epoll; # Linux 최적화 이벤트 방식
multi_accept on; # 한 번에 여러 연결 수락
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
# Gzip 압축
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss;
gzip_min_length 1024;
# 버퍼 튜닝
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# 타임아웃
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}Bash
# 설정 검증
sudo nginx -t
# 무중단 설정 리로드
sudo nginx -s reload
# 실시간 연결 통계
sudo nginx -V 2>&1 | grep with-http_stub_status
# status 페이지 확인
curl http://localhost/nginx_status편집 안내 · Editorial Note
이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.
질문 & 답변 (Q&A)
이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.