Nginx SSL/TLS 설정 완전 정복
Nginx는 고성능 SSL/TLS 처리 능력으로 가장 널리 사용되는 HTTPS 서버 중 하나입니다. ssl_certificate, ssl_protocols, ssl_ciphers 등 핵심 지시어를 이해하고 HTTP→HTTPS 리다이렉트까지 완전한 HTTPS 환경을 구성합니다.
기본 HTTPS 설정
# /etc/nginx/conf.d/https.conf
server {
listen 443 ssl;
listen [::]:443 ssl; # IPv6
http2 on; # HTTP/2 활성화 (Nginx 1.25.1+)
server_name example.com www.example.com;
# 인증서와 개인키
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 나머지 설정...
location / {
root /var/www/html;
index index.html;
}
}
# HTTP → HTTPS 리다이렉트
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
TLS 버전과 암호 스위트 설정
권장 설정 (TLS 1.2 + 1.3)
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/ssl/certs/fullchain.pem;
ssl_certificate_key /etc/ssl/private/privkey.pem;
# TLS 버전: 1.2와 1.3만 허용
ssl_protocols TLSv1.2 TLSv1.3;
# 암호 스위트 (TLS 1.2용, TLS 1.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:'
'!DSS';
# 서버가 암호 스위트 순서를 우선시 (클라이언트 선호도 무시)
ssl_prefer_server_ciphers off; # TLS 1.3에서는 off 권장
# ECDH 파라미터
ssl_ecdh_curve X25519:prime256v1:secp384r1;
# DH 파라미터 (TLS 1.2 DHE 사용 시)
# ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out dhparam.pem 4096
}
TLS 1.3 전용 (최고 보안, 일부 구형 클라이언트 차단)
ssl_protocols TLSv1.3;
# TLS 1.3 암호 스위트는 Nginx에서 직접 제어 불가 (OpenSSL이 자동 선택)
SSL 세션 캐시 (성능 최적화)
TLS 핸드셰이크는 비용이 큰 연산입니다. 세션 캐시로 재연결 시 핸드셰이크를 생략합니다.
# nginx.conf 또는 conf.d/ 파일의 http 블록에 설정
http {
# 공유 세션 캐시: 1MB당 약 4000개 세션 저장
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d; # 세션 유지 시간: 1일
ssl_session_tickets off; # 보안상 비활성화 권장 (Forward Secrecy 보호)
}
OCSP Stapling (인증서 유효성 확인 가속)
브라우저는 인증서가 유효한지 OCSP 서버에 매번 확인합니다. OCSP Stapling은 서버가 미리 OCSP 응답을 가져와 클라이언트에 함께 전달해 지연을 줄입니다.
server {
ssl_stapling on;
ssl_stapling_verify on;
# OCSP 응답 서버가 참조할 CA 체인
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# DNS resolver (OCSP 서버 조회용)
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
}
완전한 프로덕션 Nginx HTTPS 설정
# /etc/nginx/conf.d/example.com.conf
# HTTP → HTTPS 리다이렉트
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# Let's Encrypt 갱신 경로는 제외
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 서버
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com www.example.com;
# 인증서
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS 설정
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';
ssl_prefer_server_ciphers off;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
# 세션 캐시
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 1.1.1.1 valid=300s;
resolver_timeout 5s;
# 보안 헤더
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY 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;
# 애플리케이션 설정
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;
}
# 로그
access_log /var/log/nginx/example.com-access.log;
error_log /var/log/nginx/example.com-error.log warn;
}
설정 검증
# 설정 문법 확인
sudo nginx -t
# 적용
sudo systemctl reload nginx
# SSL 설정 테스트
openssl s_client -connect example.com:443 -tls1_3 2>/dev/null | grep "Protocol"
# Protocol : TLSv1.3
# TLS 1.0, 1.1이 차단되는지 확인
openssl s_client -connect example.com:443 -tls1 2>&1 | grep -E "handshake|alert"
# handshake failure (정상: 차단됨)
# 암호 스위트 확인
openssl s_client -connect example.com:443 -cipher 'RC4' 2>&1 | grep "cipher"
# no peer certificate available (정상: 차단됨)
# SSL Labs 테스트 (외부 도구)
# https://www.ssllabs.com/ssltest/analyze.html?d=example.com
www → non-www 또는 non-www → www 리다이렉트
# www → example.com (non-www 우선)
server {
listen 443 ssl;
http2 on;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
# 메인 도메인
server {
listen 443 ssl;
http2 on;
server_name example.com;
# ... 나머지 설정
}
다음 페이지에서는 Apache mod_ssl을 사용한 HTTPS 설정을 알아봅니다.