Nginx 개요
Nginx(엔진엑스)는 높은 동시 접속 처리 성능으로 알려진 웹서버이자 리버스 프록시 서버입니다. Apache가 요청마다 프로세스/스레드를 생성하는 방식인 반면, Nginx는 이벤트 기반 비동기 아키텍처로 적은 메모리로 수만 개의 동시 연결을 처리합니다.
주요 용도는 다음과 같습니다.
| 용도 | 설명 |
|---|---|
| 정적 파일 서빙 | HTML, CSS, JS, 이미지 등을 직접 제공 |
| 리버스 프록시 | 백엔드 서버(Node.js, Django 등) 앞단에서 요청 중계 |
| 로드 밸런서 | 여러 백엔드 서버에 트래픽 분산 |
| SSL 종료 | HTTPS 암호화/복호화를 Nginx에서 처리 |
| 캐싱 | 정적 자원과 프록시 응답을 캐싱하여 성능 향상 |
설치와 기본 설정
Ubuntu/Debian 기준으로 설치합니다.
# Nginx 설치
sudo apt update && sudo apt install -y nginx
# 서비스 시작 및 부팅 시 자동 시작
sudo systemctl enable --now nginx
# 설치 확인
nginx -v
# nginx version: nginx/1.24.0
# 설정 파일 문법 검사
sudo nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# 설정 적용 (무중단 리로드)
sudo nginx -s reload
Nginx의 설정 파일 구조입니다.
| 경로 | 역할 |
|---|---|
/etc/nginx/nginx.conf | 전역 설정 (워커 프로세스, 이벤트 등) |
/etc/nginx/sites-available/ | 사이트별 설정 파일 (비활성) |
/etc/nginx/sites-enabled/ | 활성화된 사이트 (심볼릭 링크) |
/etc/nginx/conf.d/ | 추가 설정 파일 (*.conf 자동 로드) |
리버스 프록시 설정
Node.js(포트 3000)나 Django(포트 8000) 같은 백엔드 서버를 Nginx 뒤에 배치하는 설정입니다.
# /etc/nginx/sites-available/my-app.conf
# Node.js 앱을 위한 리버스 프록시 설정
# 업스트림 서버 정의 (로드 밸런싱 가능)
upstream backend {
# 라운드 로빈 방식으로 분산 (기본값)
server 127.0.0.1:3000;
server 127.0.0.1:3001;
# 접속 유지 (Keep-Alive) 커넥션 수
keepalive 32;
}
server {
listen 80;
server_name example.com www.example.com;
# 접근 로그와 에러 로그 경로
access_log /var/log/nginx/my-app-access.log;
error_log /var/log/nginx/my-app-error.log;
# 클라이언트 최대 요청 크기 (파일 업로드 등)
client_max_body_size 50M;
# 정적 파일은 Nginx가 직접 서빙
location /static/ {
alias /opt/my-app/public/;
# 30일 캐싱
expires 30d;
add_header Cache-Control "public, immutable";
}
# API 및 동적 요청은 백엔드로 프록시
location / {
proxy_pass http://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_connect_timeout 60s;
proxy_read_timeout 120s;
proxy_send_timeout 60s;
# WebSocket 지원
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
사이트를 활성화하고 적용합니다.
# 사이트 활성화 (심볼릭 링크 생성)
sudo ln -s /etc/nginx/sites-available/my-app.conf /etc/nginx/sites-enabled/
# 기본 사이트 비활성화 (필요 시)
sudo rm /etc/nginx/sites-enabled/default
# 설정 검사 후 적용
sudo nginx -t && sudo nginx -s reload
proxy_set_header X-Real-IP는 백엔드에서 실제 클라이언트 IP를 확인하는 데 필수입니다. 이 헤더가 없으면 모든 요청의 IP가 127.0.0.1로 표시됩니다.
Let’s Encrypt SSL 설정
무료 SSL 인증서를 Certbot으로 발급받고 Nginx에 적용합니다.
# Certbot 설치
sudo apt install -y certbot python3-certbot-nginx
# SSL 인증서 발급 + Nginx 자동 설정
sudo certbot --nginx -d example.com -d www.example.com
# 이메일 입력 → 이용약관 동의 → HTTP→HTTPS 리다이렉트 선택
# 인증서 자동 갱신 테스트
sudo certbot renew --dry-run
# 인증서 만료일 확인
sudo certbot certificates
# Certificate Name: example.com
# Expiry Date: 2026-05-19 (VALID: 89 days)
Certbot이 Nginx 설정을 자동으로 수정하지만, 수동 설정이 필요한 경우 아래 형태입니다.
# /etc/nginx/sites-available/my-app.conf
# SSL 적용 설정
# HTTP → HTTPS 리다이렉트
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL 인증서 경로
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL 보안 설정 (Mozilla Modern 권장)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# HSTS (6개월)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
# OCSP Stapling (인증서 유효성 검증 속도 향상)
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
location / {
proxy_pass http://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;
}
}
정적 파일 캐싱과 gzip
정적 자원의 캐싱과 gzip 압축으로 응답 속도를 개선합니다.
# /etc/nginx/conf.d/optimization.conf
# 성능 최적화 설정
# gzip 압축 설정
gzip on;
gzip_vary on;
gzip_proxied any;
# 압축 레벨 (1~9, 높을수록 CPU 사용 증가)
gzip_comp_level 6;
# 1KB 미만은 압축하지 않음
gzip_min_length 1024;
# 압축 대상 MIME 타입
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
# 파일 캐싱 (확장자별)
server {
# ... 기존 설정 ...
# 이미지, 폰트 — 1년 캐싱
location ~* \.(jpg|jpeg|png|gif|ico|svg|woff2|woff|ttf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
# 접근 로그 비활성화 (정적 파일 로그가 불필요한 경우)
access_log off;
}
# CSS, JS — 30일 캐싱
location ~* \.(css|js)$ {
expires 30d;
add_header Cache-Control "public";
}
# HTML — 캐싱하지 않음 (항상 최신 버전 제공)
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
유용한 설정 패턴
Rate Limiting (요청 제한)
# 전역 설정 (/etc/nginx/nginx.conf의 http 블록)
# IP당 초당 10개 요청으로 제한 (zone 메모리 10MB)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
location /api/ {
# burst=20: 순간적으로 20개까지 허용 (큐에 대기)
# nodelay: 큐에 넣지 않고 즉시 처리
limit_req zone=api_limit burst=20 nodelay;
# 제한 초과 시 429 반환
limit_req_status 429;
proxy_pass http://backend;
}
}
보안 헤더
# 보안 관련 응답 헤더
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;
실전 팁
- 설정 변경 전 반드시
nginx -t로 문법을 검사하세요. 문법 오류가 있으면reload시 Nginx가 기존 설정으로 계속 동작하지만,restart는 서비스가 중단될 수 있습니다. - 무중단 적용:
nginx -s reload는 기존 커넥션을 유지하면서 새 설정을 적용합니다.restart와 달리 다운타임이 없습니다. - 로그 로테이션:
/etc/logrotate.d/nginx파일로 로그 로테이션이 자동 설정됩니다. 대용량 트래픽 서비스에서는 주기를 조정하세요. - 업스트림 헬스체크: 오픈소스 Nginx에서는
max_fails=3 fail_timeout=30s옵션으로 간단한 헬스체크를 구현할 수 있습니다. Nginx Plus에서는 능동적 헬스체크를 지원합니다. - 디버깅:
error_log /var/log/nginx/debug.log debug;로 디버그 레벨 로그를 활성화하면 리버스 프록시 문제를 진단할 때 유용합니다. 운영 환경에서는 반드시 비활성화하세요.