본문으로 건너뛰기

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 설정을 알아봅니다.