Skip to main content

웹 서비스의 성능과 보안은 서버 설정 하나로 크게 달라집니다. Nginx는 세계에서 가장 널리 쓰이는 웹 서버이자 리버스 프록시지만, 기본 설정만으로는 그 잠재력의 절반도 발휘하지 못합니다. 이 글에서는 실제 프로덕션 환경에서 검증된 Nginx 최적화 설정 — gzip 압축, 정적파일 캐싱, SSL/TLS 보안 헤더 — 을 코드와 함께 상세히 설명합니다.

Nginx 설정 최적화 — gzip, 캐싱, SSL 보안 헤더

1. gzip 압축 설정으로 전송량 줄이기

gzip 압축은 HTML, CSS, JavaScript 파일의 크기를 60~80%까지 줄여줍니다. 특히 텍스트 기반 리소스에 효과적이며, 서버 CPU 부하는 약간 증가하지만 네트워크 대역폭 절감 효과가 훨씬 큽니다. 아래는 실무에서 검증된 gzip 설정입니다.

# /etc/nginx/nginx.conf 또는 /etc/nginx/conf.d/gzip.conf

http {
    # gzip 기본 활성화
    gzip on;
    gzip_vary on;

    # 최소 응답 크기 (1KB 이하는 압축 비효율)
    gzip_min_length 1024;

    # 압축 레벨: 1(빠름/낮은압축) ~ 9(느림/높은압축), 5~6이 최적
    gzip_comp_level 6;

    # 프록시 요청에도 압축 적용
    gzip_proxied any;

    # 압축할 MIME 타입 명시
    gzip_types
        text/plain
        text/css
        text/javascript
        application/javascript
        application/json
        application/xml
        application/rss+xml
        image/svg+xml
        font/ttf
        font/woff
        font/woff2
        application/font-woff2;

    # HTTP/1.0 클라이언트에는 gzip 비적용 (기본값 유지)
    gzip_http_version 1.1;

    # IE6 버그 우회 (레거시 대응)
    gzip_disable "msie6";
}

설정 후 nginx -t && systemctl reload nginx로 적용하고, curl -I -H "Accept-Encoding: gzip" https://yourdomain.com으로 응답 헤더에 Content-Encoding: gzip이 있는지 확인하세요.

2. 정적 파일 캐싱으로 반복 요청 차단

CSS, JS, 이미지, 폰트 같은 정적 파일은 자주 변경되지 않습니다. 브라우저 캐싱을 활성화하면 재방문 사용자는 이 파일들을 서버에서 다시 받지 않아도 됩니다. 적절한 Cache-Control 헤더와 Expires를 설정해 성능을 극대화할 수 있습니다.

# /etc/nginx/sites-available/yourdomain.conf

server {
    listen 443 ssl;
    server_name yourdomain.com;

    root /var/www/html;
    index index.html;

    # HTML은 캐시 안 함 (항상 최신 버전 확인)
    location ~* \.html$ {
        add_header Cache-Control "no-cache, must-revalidate";
        add_header Pragma "no-cache";
        expires 0;
    }

    # CSS, JS: 1년 캐싱 (파일명에 해시 포함 권장)
    location ~* \.(css|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Vary "Accept-Encoding";
        access_log off;
    }

    # 이미지, 폰트: 6개월 캐싱
    location ~* \.(jpg|jpeg|png|gif|ico|webp|svg|woff|woff2|ttf|eot)$ {
        expires 6M;
        add_header Cache-Control "public, max-age=15552000";
        add_header Vary "Accept-Encoding";
        access_log off;
    }

    # FastAPI / Node.js 리버스 프록시
    location /api/ {
        proxy_pass http://127.0.0.1:8000;
        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;

        # 프록시 캐시 비적용 (API는 항상 동적)
        add_header Cache-Control "no-store, no-cache";
    }
}

SvelteKit이나 Next.js를 빌드하면 JS/CSS 파일명에 해시가 자동으로 붙습니다(_app-a1b2c3d4.js). 파일 내용이 바뀌면 해시도 바뀌므로, immutable 캐싱을 적용해도 최신 파일을 항상 받을 수 있습니다.

3. SSL/TLS 보안 강화 설정

HTTPS만 켜는 것으로 충분하지 않습니다. 오래된 TLS 버전 허용, 약한 암호화 스위트 사용, 보안 헤더 미설정은 실제 보안 취약점이 됩니다. 아래 설정은 SSL Labs A+ 등급을 목표로 합니다.

# SSL 기본 설정 (별도 파일로 분리 권장)
# /etc/nginx/snippets/ssl-params.conf

# TLS 1.2 이상만 허용 (1.0, 1.1은 폐기됨)
ssl_protocols TLSv1.2 TLSv1.3;

# 강력한 암호화 스위트만 사용
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:DHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;

# HSTS (1년간 HTTPS 강제)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# 클릭재킹 방지
add_header X-Frame-Options "SAMEORIGIN" always;

# MIME 타입 스니핑 방지
add_header X-Content-Type-Options "nosniff" always;

# XSS 보호 (구형 브라우저 대상)
add_header X-XSS-Protection "1; mode=block" always;

# Referrer 정책
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Content Security Policy (도메인에 맞게 조정 필요)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.yourdomain.com;" always;

# OCSP Stapling (인증서 검증 속도 개선)
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# DH 파라미터 (Forward Secrecy 강화)
# 생성: openssl dhparam -out /etc/nginx/dhparam.pem 4096
ssl_dhparam /etc/nginx/dhparam.pem;

# 세션 재사용 (핸드셰이크 오버헤드 감소)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

4. HTTP → HTTPS 리다이렉트 & HTTP/2 활성화

HTTP/2는 멀티플렉싱, 헤더 압축, 서버 푸시를 지원해 동일한 연결에서 여러 요청을 병렬 처리합니다. HTTP/1.1 대비 페이지 로딩 속도가 평균 20~50% 향상됩니다. Let’s Encrypt와 함께 아래 설정을 사용하세요.

# /etc/nginx/sites-available/yourdomain.conf (전체 예시)

# HTTP → HTTPS 리다이렉트
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;

    # Let's Encrypt 인증 경로는 예외
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPS 메인 서버
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;  # Nginx 1.25.1+ 문법 (이전: listen 443 ssl http2;)

    server_name yourdomain.com www.yourdomain.com;

    # Let's Encrypt 인증서
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;

    # 보안 설정 include
    include /etc/nginx/snippets/ssl-params.conf;

    # 루트 경로
    root /var/www/html;
    index index.html;

    # 에러 로그
    error_log /var/log/nginx/yourdomain.error.log warn;
    access_log /var/log/nginx/yourdomain.access.log combined buffer=16k flush=5m;

    # gzip 설정 (http 블록에 global 설정 권장)
    gzip on;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/javascript application/json image/svg+xml;

    # 정적 파일
    location ~* \.(css|js|woff2|webp|png|jpg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # FastAPI 리버스 프록시
    location /api/ {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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_read_timeout 60s;
        proxy_connect_timeout 10s;
    }

    # SPA fallback (React/SvelteKit CSR)
    location / {
        try_files $uri $uri/ /index.html;
    }
}

5. 설정 검증 & 성능 측정

설정을 완료했다면 실제로 효과가 있는지 확인해야 합니다. Nginx 문법 검사부터 SSL 등급 확인, 실제 압축 효율 측정까지 순서대로 진행하세요.

# 1. Nginx 설정 문법 검사
nginx -t

# 2. 설정 적용 (서비스 중단 없이)
systemctl reload nginx

# 3. gzip 압축 확인
curl -s -I -H "Accept-Encoding: gzip" https://yourdomain.com | grep -i "content-encoding"
# 예상 출력: content-encoding: gzip

# 4. 보안 헤더 확인
curl -s -I https://yourdomain.com | grep -i -E "strict-transport|x-frame|content-security"

# 5. HTTP/2 확인 (curl 7.33+)
curl -sI --http2 https://yourdomain.com | head -1
# 예상 출력: HTTP/2 200

# 6. 캐시 헤더 확인 (CSS 파일)
curl -sI https://yourdomain.com/assets/main.css | grep -i "cache-control"
# 예상 출력: cache-control: public, immutable, max-age=31536000

# 7. SSL Labs 자동 체크 (API)
curl "https://api.ssllabs.com/api/v3/analyze?host=yourdomain.com&startNew=on" | python3 -m json.tool

6. 추가 성능 튜닝 팁

위 설정 외에도 다음 항목들을 확인하면 추가 성능 향상을 얻을 수 있습니다.

  • worker_processes auto; — CPU 코어 수에 맞게 워커 프로세스 자동 설정
  • worker_connections 1024; — 워커당 최대 동시 연결 수 (ulimit -n 확인 후 조정)
  • keepalive_timeout 65; — Keep-Alive 연결 유지 시간
  • client_max_body_size 10M; — 파일 업로드 크기 제한 (기본 1MB)
  • sendfile on; tcp_nopush on; — 파일 전송 최적화 (커널 레벨)
  • open_file_cache — 자주 열리는 파일 FD 캐싱으로 디스크 I/O 감소

코드벤터는 FastAPI, SvelteKit, Nginx 기반의 고성능 웹 서비스 구축 경험을 바탕으로, 글로벌 협력 네트워크를 통해 다양한 규모의 프로젝트에서 이 같은 인프라 최적화 노하우를 적용해 왔습니다. 서버 설정 하나하나가 사용자 경험과 직결됩니다 — 오늘 소개한 Nginx 최적화를 적용해 더 빠르고 안전한 서비스를 만들어 보세요.

코드픽 - 외주 전문 AI 바이브 코딩 글로벌 진출

댓글 남기기