# =============================================== # Production Level Nginx Configuration (Sample Template) # 서버 사양: 쿼드코어 CPU, 4GB RAM, ~50 req/s # 백엔드: FastAPI REST API Server # =============================================== # HTTP 서버 블록 (포트 80) - HTTPS로 리다이렉트 server { listen 80; server_name domain www.domain; # 보안을 위한 호스트 검증 - 허용되지 않은 도메인 차단 # 도메인 확장자가 다르다면 추가해줘야함 if ($host !~* ^(www\.)?domain\.(com|kr|net|org)$) { return 444; } # Let's Encrypt 도메인 검증 프로그램 허용 (리다이렉트 전에 처리) # SSL 인증서 갱신을 위해 필수 location ^~ /.well-known/acme-challenge/ { allow all; root /www/certbot; try_files $uri =404; # 디렉토리 순회 공격 방지 } # HTTP를 HTTPS로 리다이렉트 (acme-challenge 제외) # return 301은 rewrite보다 효율적이며 $server_name이 $host보다 안전함 location / { return 301 https://$server_name$request_uri; } } # HTTPS 서버 블록 (포트 443) - 메인 애플리케이션 server { listen 443 ssl http2; server_name domain.com www.domain.com; # 악성 봇 차단 (nginx.conf의 http 블록에서 $bad_bot 맵 정의 필요) if ($bad_bot) { return 403; } # SSL/TLS 인증서 설정 ssl_certificate /etc/letsencrypt/live/domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem; ssl_dhparam /etc/ssl/certs/domain/dhparam.pem; # openssl dhparam -out /etc/ssl/certs/domain/dhparam.pem 2048 # 최신 SSL/TLS 설정 - SSL Labs A+ 등급 달성 가능 ssl_session_cache shared:SSL:50m; # SSL 세션 캐시 크기 증가 (트래픽 많을 시 유용) ssl_session_timeout 10m; # SSL 세션 타임아웃 ssl_session_tickets off; # 보안 향상을 위해 세션 티켓 비활성화 (nginx >= 1.5.9) ssl_protocols TLSv1.2 TLSv1.3; # 최신 TLS 프로토콜만 사용 ssl_prefer_server_ciphers off; # TLSv1.3에서는 클라이언트 선호 암호화 사용 (모범 사례) # 최신 암호화 스위트 - CHACHA20-POLY1305 포함 (모바일 최적화) 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:DHE-RSA-AES256-GCM-SHA384"; ssl_ecdh_curve secp384r1; # ECDH 곡선 설정 (nginx >= 1.1.0) # OCSP 스테이플링 - SSL 핸드셰이크 성능 향상 # 인증서에 OCSP URL이 없으면 자동으로 비활성화됨 (경고는 정상) ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/letsencrypt/live/domain/chain.pem; resolver 1.1.1.1 8.8.8.8 valid=300s; # Cloudflare와 Google DNS 사용 resolver_timeout 5s; # 보안 헤더 - 다양한 공격으로부터 보호 add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # HSTS - 다운그레이드 공격 방지 add_header X-Frame-Options "DENY" always; # 클릭재킹 방지 add_header X-Content-Type-Options "nosniff" always; # MIME 스니핑 방지 add_header X-XSS-Protection "1; mode=block" always; # 레거시 XSS 보호 add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 리퍼러 정보 제어 add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' ''; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: ws:;" always; # XSS 방지를 위한 CSP # 'unsafe-inline'은 범용 설정이 아니며, 보안상 위험한 설정입니다. CSP의 핵심 보호 기능을 무력화시키므로, 개발 환경이나 레거시 코드 마이그레이션 과정에서만 임시로 사용하고, 프로덕션 환경에서는 nonce, hash, 또는 외부 파일 분리 방식으로 대체해야 합니다. # 클라이언트가 업로드할 수 있는 전체 요청 본문(body) 의 최대 허용 크기 # 요청 바디(파일, 폼 데이터 등)가 이 값을 초과하면 Nginx는 즉시 413 Request Entity Too Large 에러를 반환 # 업로드 제한선. client_max_body_size 100M; # 최대 업로드 크기 제한 (애플리케이션에 맞게 조정) # 파일 캐시 - I/O 성능 향상 open_file_cache max=1000 inactive=20s; # 최대 1000개 파일 캐시, 20초 비활성 시 제거 open_file_cache_valid 30s; # 캐시 유효성 검사 주기 open_file_cache_min_uses 2; # 최소 2회 사용 시 캐시 open_file_cache_errors on; # 파일 오류도 캐시 # 로깅 설정 - 버퍼링으로 I/O 감소 access_log /log/nginx/domain.com.gunicorn_access.log main buffer=32k flush=5s; error_log /log/nginx/domain.com.gunicorn_error.log warn; # frontend에 오류 페이지 정의가 되어 있는 경우 사용 가능 # # 커스텀 오류 페이지 - 더 나은 사용자 경험 및 정보 노출 방지 # error_page 404 /404.html; # error_page 500 502 503 504 /50x.html; # location = /404.html { # internal; # 내부 리다이렉트만 허용 # root /www/error_pages; # } # location = /50x.html { # internal; # 내부 리다이렉트만 허용 # root /www/error_pages; # } # Fastapi 미디어 파일 - 사용자 업로드 파일 location /media { autoindex off; # 디렉토리 목록 비활성화 # gzip_static on; # 사전 압축된 .gz 파일 사용 expires 30d; # 브라우저 캐시 30일 후 브라우저가 다시 요청할 때 재검증 alias /www/webroot/media; # Fastapi 프로젝트의 미디어 파일 경로 # 정적 파일 캐싱 - 브라우저 캐시 최적화 add_header Cache-Control "public, immutable"; access_log off; # 액세스 로그 비활성화로 성능 향상 } # Fastapi 정적 파일 - CSS, JS, 이미지 등 location /static { autoindex off; # 디렉토리 목록 비활성화 # gzip_static on; # 사전 압축된 .gz 파일 사용 압축된 파일이 없다면 설정 무의미 expires 30d; # 브라우저 캐시 30일 후 브라우저가 다시 요청할 때 재검증 alias /www/webroot/static; # Fastapi 프로젝트의 정적 파일 경로 # 정적 파일 캐싱 - 브라우저 캐시 최적화 add_header Cache-Control "public, immutable"; access_log off; # 액세스 로그 비활성화로 성능 향상 } # 메인 애플리케이션 - 백엔드로 프록시 location / { autoindex off; # 디렉토리 목록 비활성화 # 속도 제한 - DDoS 및 무차별 대입 공격 방지 # (nginx.conf의 http 블록에서 limit_req_zone과 limit_conn_zone 정의 필요) limit_req zone=general burst=20 nodelay; # 초당 요청 제한 limit_conn addr 10; # IP당 동시 연결 제한 # HTTP 메서드 제한 - HTTP 동사 변조 공격 방지 limit_except GET POST HEAD OPTIONS { deny all; } # 백엔드 애플리케이션으로 프록시 proxy_pass http://appname:serviceport; # WebSocket 지원 - 실시간 통신 애플리케이션에 필수 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # nginx.conf에서 $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_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; # 타임아웃 설정 - 애플리케이션에 맞게 조정 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # 버퍼 설정 - 대화형 애플리케이션에 최적화 - Websocket 사용시 설정 # proxy_buffering off; # 즉시 응답 전달 # proxy_request_buffering off; # 즉시 요청 전달 # 버퍼링 활성화 (기본값) - 기본 fastapi 사용시 설정 proxy_buffering on; proxy_request_buffering on; # 버퍼 크기 설정 - 기본 fastapi 사용시 설정 proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; proxy_set_header Accept-Encoding gzip; } # Let's Encrypt 도메인 검증 프로그램 허용 (HTTPS에서도 필요시) location ^~ /.well-known/acme-challenge/ { allow all; root /www/certbot; try_files $uri =404; # 디렉토리 순회 공격 방지 } # 정적 리소스 캐싱 - 이미지, 폰트, CSS, JS 등 # 브라우저 캐시로 로드 시간 단축 및 서버 부하 감소 location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ { expires 1y; # 1년 캐시 add_header Cache-Control "public, immutable"; access_log off; # 액세스 로그 비활성화로 성능 향상 } # 닷 파일 차단 - .htaccess, .htpasswd, .svn, .git, .env 등 # 민감한 설정 파일 노출 방지 location ~ /\. { deny all; access_log off; # 차단된 시도 로그 비활성화 log_not_found off; } # 민감한 파일 확장자 차단 - 로그, 인증서, 스크립트, SQL 등 # 보안을 위해 직접 접근 차단 location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ { deny all; access_log off; # 차단된 시도 로그 비활성화 log_not_found off; } # 민감한 설정 파일 차단 - composer, package.json, phpunit 등 # 프로젝트 메타데이터 및 설정 파일 노출 방지 location ~* (composer\.json|composer\.lock|composer\.phar|contributing\.md|license\.txt|readme\.rst|readme\.md|readme\.txt|copyright|artisan|gulpfile\.js|package\.json|phpunit\.xml|access_log|error_log|gruntfile\.js)$ { deny all; access_log off; # 차단된 시도 로그 비활성화 log_not_found off; } # 파비콘 - 로그 노이즈 제거 location = /favicon.ico { log_not_found off; access_log off; } # robots.txt - 검색 엔진 크롤러 제어 location = /robots.txt { log_not_found off; access_log off; allow all; } }