Skip to content

필사 모드: [DevOps] Nginx TLS 설정 완전 가이드: PEM/Key 적용과 보안 최적화

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

1. PEM, Key, CRT 파일 형식 이해

1.1 PEM (Privacy Enhanced Mail)

PEM은 Base64로 인코딩된 인증서/키 형식이다. 텍스트 에디터로 열어볼 수 있다.

-----BEGIN CERTIFICATE-----

MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw

TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh

... (Base64 인코딩된 데이터)

-----END CERTIFICATE-----

-----BEGIN PRIVATE KEY-----

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7o4qne60TB3pO

... (Base64 인코딩된 데이터)

-----END PRIVATE KEY-----

1.2 DER (Distinguished Encoding Rules)

바이너리 형식이다. PEM에서 Base64 인코딩을 제거한 것과 동일하다.

1.3 키 타입

| 알고리즘 | 키 크기 | 성능 | 보안 | 권장 |

| ----------- | -------- | --------- | ---- | ----------------- |

| RSA 2048 | 2048 bit | 느림 | 충분 | 호환성 중시 |

| RSA 4096 | 4096 bit | 매우 느림 | 높음 | 높은 보안 필요 시 |

| ECDSA P-256 | 256 bit | 빠름 | 충분 | 권장 (Modern) |

| ECDSA P-384 | 384 bit | 빠름 | 높음 | 높은 보안 + 성능 |

ECDSA는 RSA 대비 동일 보안 수준에서 키 크기가 훨씬 작아 TLS 핸드셰이크 성능이 우수하다.

1.4 Let's Encrypt 발급 파일 매핑

/etc/letsencrypt/live/example.com/

fullchain.pem = 서버 인증서 + 중간 CA 인증서

privkey.pem = 개인키

chain.pem = 중간 CA 인증서만

cert.pem = 서버 인증서만

Nginx에서 사용하는 파일:

ssl_certificate -> fullchain.pem

ssl_certificate_key -> privkey.pem

2. Nginx 기본 TLS 설정

2.1 최소 설정

server {

listen 443 ssl;

server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

root /var/www/html;

index index.html;

location / {

try_files $uri $uri/ =404;

}

}

2.2 HTTP에서 HTTPS로 리다이렉트

server {

listen 80;

server_name example.com www.example.com;

ACME 챌린지용 (Let's Encrypt 갱신)

location /.well-known/acme-challenge/ {

root /var/www/certbot;

}

나머지 모든 요청을 HTTPS로 리다이렉트

location / {

return 301 https://$host$request_uri;

}

}

2.3 완전한 프로덕션 설정 예제

/etc/nginx/conf.d/ssl-params.conf

공통 SSL 파라미터 (모든 서버 블록에서 include)

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:DHE-RSA-AES256-GCM-SHA384;

ssl_prefer_server_ciphers off;

DH 파라미터

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

HSTS

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

OCSP Stapling

ssl_stapling on;

ssl_stapling_verify on;

ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

resolver 8.8.8.8 8.8.4.4 valid=300s;

resolver_timeout 5s;

SSL 세션 캐싱

ssl_session_cache shared:SSL:10m;

ssl_session_timeout 1d;

ssl_session_tickets off;

보안 헤더

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;

/etc/nginx/sites-available/example.com

server {

listen 80;

server_name example.com www.example.com;

location /.well-known/acme-challenge/ {

root /var/www/certbot;

}

location / {

return 301 https://$host$request_uri;

}

}

server {

listen 443 ssl http2;

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;

include /etc/nginx/conf.d/ssl-params.conf;

root /var/www/html;

index index.html;

location / {

try_files $uri $uri/ =404;

}

정적 파일 캐싱

location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {

expires 30d;

add_header Cache-Control "public, immutable";

}

}

3. TLS 버전 설정

3.1 TLS 버전별 보안 상태

| 버전 | 상태 | 권장 |

| ------- | -------------------- | -------------- |

| SSL 2.0 | 폐기 (1996년) | 절대 사용 금지 |

| SSL 3.0 | 폐기 (POODLE 취약점) | 절대 사용 금지 |

| TLS 1.0 | 폐기 (2021년) | 비활성화 |

| TLS 1.1 | 폐기 (2021년) | 비활성화 |

| TLS 1.2 | 현재 표준 | 사용 |

| TLS 1.3 | 최신 표준 | 사용 (권장) |

3.2 TLS 1.2/1.3만 허용

TLS 1.2와 1.3만 허용 (권장)

ssl_protocols TLSv1.2 TLSv1.3;

3.3 TLS 1.3 전용 (Modern)

TLS 1.3만 허용 (최신 클라이언트만 지원)

ssl_protocols TLSv1.3;

TLS 1.3의 장점:

- 핸드셰이크 라운드 트립 감소 (1-RTT, 0-RTT)

- 취약한 레거시 암호화 스위트 제거

- 전방 보안(Forward Secrecy) 기본 적용

- 핸드셰이크 암호화 (서버 인증서 포함)

4. 암호화 스위트 설정

4.1 Mozilla SSL Configuration Generator 프로파일

Mozilla는 세 가지 구성 프로파일을 제공한다.

**Modern (TLS 1.3 전용):**

ssl_protocols TLSv1.3;

TLS 1.3은 별도 cipher 설정 불필요 (프로토콜에 내장)

ssl_prefer_server_ciphers off;

**Intermediate (TLS 1.2 + 1.3, 권장):**

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:DHE-RSA-AES256-GCM-SHA384;

ssl_prefer_server_ciphers off;

**Old (레거시 호환, 비권장):**

ssl_protocols TLSv1 TLSv1.1 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:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA;

ssl_prefer_server_ciphers on;

4.2 암호화 스위트 이름 해석

ECDHE-RSA-AES256-GCM-SHA384 의 의미:

ECDHE = 키 교환 알고리즘 (Elliptic Curve Diffie-Hellman Ephemeral)

→ Forward Secrecy 제공

RSA = 인증 알고리즘 (서버 인증서 서명)

AES256 = 대칭 암호화 (256비트 AES)

GCM = 암호화 모드 (Galois/Counter Mode, AEAD)

SHA384 = 해시 함수 (무결성 검증)

4.3 ssl_prefer_server_ciphers

TLS 1.2: on으로 설정하면 서버가 선호하는 cipher를 우선 사용

TLS 1.3: 클라이언트가 결정 (이 설정 무시됨)

Mozilla Intermediate에서는 off 권장

ssl_prefer_server_ciphers off;

5. DH 파라미터

Diffie-Hellman 키 교환에 사용되는 파라미터다. DHE 암호화 스위트를 사용할 때 필요하다.

DH 파라미터 생성 (2048비트 이상 권장)

openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

더 강력한 4096비트 (생성 시간이 오래 걸림)

openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

참고: TLS 1.3에서는 DHE 대신 ECDHE만 사용하므로 DH 파라미터가 필요 없다. TLS 1.2의 DHE 암호화 스위트를 제거하면 DH 파라미터도 불필요하다.

6. HSTS (HTTP Strict Transport Security)

6.1 HSTS란

HSTS는 브라우저에게 해당 도메인에 항상 HTTPS로 접속하도록 지시하는 HTTP 헤더다.

max-age: HSTS 유지 기간 (초 단위, 63072000 = 2년)

includeSubDomains: 모든 서브도메인에도 적용

preload: 브라우저 Preload List 등록 의사 표시

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

6.2 HSTS Preload List

HSTS Preload List에 등록하면 브라우저가 첫 접속부터 HTTPS를 강제한다.

등록 조건:

- 유효한 TLS 인증서

- 포트 80에서 443으로 리다이렉트

- 모든 서브도메인에 HTTPS 적용

- HSTS 헤더에 max-age 최소 31536000(1년), includeSubDomains, preload 포함

등록 사이트: hstspreload.org

6.3 주의사항

- HSTS를 설정하면 되돌리기 어려움 (max-age 동안 브라우저가 HTTP 접속 차단)

- 처음에는 작은 max-age (예: 300초)로 시작해서 점진적으로 늘리는 것을 권장

- 모든 서브도메인이 HTTPS를 지원하는지 확인 후 includeSubDomains 추가

7. OCSP Stapling

7.1 OCSP Stapling이란

OCSP(Online Certificate Status Protocol)는 인증서가 폐기(revoke)되었는지 확인하는 프로토콜이다. OCSP Stapling은 서버가 CA에서 OCSP 응답을 미리 받아서 TLS 핸드셰이크 시 클라이언트에게 전달하는 기술이다.

OCSP Stapling 없이:

Client → Server (TLS 핸드셰이크)

Client → CA OCSP Server (인증서 유효성 확인) ← 추가 지연

OCSP Stapling 있을 때:

Server → CA OCSP Server (주기적으로 OCSP 응답 갱신)

Client → Server (TLS 핸드셰이크 + OCSP 응답 포함) ← 빠름

7.2 설정

ssl_stapling on;

ssl_stapling_verify on;

중간 CA 인증서 (chain.pem)

ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

OCSP 응답 서버의 DNS 해석용 리졸버

resolver 8.8.8.8 8.8.4.4 valid=300s;

resolver_timeout 5s;

7.3 OCSP Stapling 확인

OCSP Stapling 동작 확인

openssl s_client -connect example.com:443 -servername example.com -status < /dev/null 2>/dev/null | grep -A 20 "OCSP Response"

정상 응답 예시:

OCSP Response Status: successful (0x0)

OCSP Response Data:

OCSP Response Status: successful (0x0)

Cert Status: good

8. SSL 세션 캐싱

8.1 세션 캐시

TLS 핸드셰이크는 비용이 크다. 세션 캐시를 사용하면 재연결 시 전체 핸드셰이크를 생략할 수 있다.

공유 메모리 캐시 (여러 worker 프로세스 간 공유)

10MB 캐시 = 약 40,000 세션 저장

ssl_session_cache shared:SSL:10m;

세션 유효 기간

ssl_session_timeout 1d;

세션 티켓 비활성화 (Forward Secrecy 보장을 위해)

ssl_session_tickets off;

8.2 왜 Session Tickets를 비활성화하는가

Session Tickets는 서버 메모리 대신 암호화된 티켓을 클라이언트에 저장한다. 문제점:

- 티켓 암호화 키가 모든 세션의 보안을 좌우

- 키 로테이션이 제대로 되지 않으면 Forward Secrecy가 깨짐

- TLS 1.3에서는 0-RTT 재연결로 대체 가능

9. HTTP/2 설정

9.1 HTTP/2 활성화

server {

listen 443 ssl http2;

server_name example.com;

... SSL 설정 ...

}

HTTP/2의 장점:

- **멀티플렉싱**: 하나의 TCP 연결에서 여러 요청을 동시 처리

- **헤더 압축**: HPACK으로 HTTP 헤더 압축

- **서버 푸시**: 클라이언트가 요청하기 전에 리소스 전송

- **우선순위**: 리소스별 전송 우선순위 설정

9.2 HTTP/3 (QUIC) 준비

Nginx 1.25.0+ (또는 nginx-quic)

server {

listen 443 ssl;

listen 443 quic reuseport;

http2 on;

http3 on;

server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

QUIC 광고 헤더

add_header Alt-Svc 'h3=":443"; ma=86400' always;

}

10. mTLS (Mutual TLS) 설정

10.1 mTLS란

일반 TLS는 서버만 인증서를 제시하지만, mTLS는 **클라이언트도 인증서를 제시**하여 양방향 인증을 수행한다.

일반 TLS:

Client ──── 서버 인증서 확인 ───> Server

Mutual TLS:

Client <─── 서버 인증서 확인 ───> Server

Client ──── 클라이언트 인증서 ──> Server (서버가 클라이언트 인증서 확인)

사용 사례:

- 마이크로서비스 간 통신 (서비스 메시)

- API 인증 (API Gateway)

- IoT 디바이스 인증

- 내부 관리 도구 접근 제어

10.2 CA 인증서로 클라이언트 인증서 발급

1. CA 개인키 생성

openssl genrsa -out ca.key 4096

2. CA 인증서 생성 (자체 서명)

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \

-subj "/C=KR/ST=Seoul/O=MyOrg/CN=Internal CA"

3. 클라이언트 개인키 생성

openssl genrsa -out client.key 2048

4. 클라이언트 CSR 생성

openssl req -new -key client.key -out client.csr \

-subj "/C=KR/ST=Seoul/O=MyOrg/CN=service-a"

5. CA로 클라이언트 인증서 서명

openssl x509 -req -days 365 -in client.csr \

-CA ca.crt -CAkey ca.key -CAcreateserial \

-out client.crt

6. PFX/PKCS12 번들 생성 (브라우저 임포트용)

openssl pkcs12 -export -out client.pfx \

-inkey client.key -in client.crt -certfile ca.crt

10.3 Nginx mTLS 설정

server {

listen 443 ssl http2;

server_name api.example.com;

ssl_certificate /etc/nginx/ssl/server.fullchain.pem;

ssl_certificate_key /etc/nginx/ssl/server.privkey.pem;

클라이언트 인증서 검증

ssl_client_certificate /etc/nginx/ssl/ca.crt;

ssl_verify_client on; # on: 필수, optional: 선택적

ssl_verify_depth 2; # 인증서 체인 검증 깊이

CRL (Certificate Revocation List) 설정

ssl_crl /etc/nginx/ssl/ca.crl;

클라이언트 인증서 정보를 백엔드로 전달

location / {

proxy_pass http://backend;

proxy_set_header X-SSL-Client-Cert $ssl_client_cert;

proxy_set_header X-SSL-Client-S-DN $ssl_client_s_dn;

proxy_set_header X-SSL-Client-Verify $ssl_client_verify;

proxy_set_header X-SSL-Client-Serial $ssl_client_serial;

}

}

10.4 ssl_verify_client 옵션

on: 클라이언트 인증서 필수 (없으면 400 에러)

ssl_verify_client on;

optional: 인증서 선택적 (없어도 접속 가능, 인증서가 있으면 검증)

ssl_verify_client optional;

optional_no_ca: 인증서 검증 없이 전달만 (백엔드에서 검증)

ssl_verify_client optional_no_ca;

10.5 mTLS 테스트

클라이언트 인증서로 요청

curl --cert client.crt --key client.key \

--cacert ca.crt \

https://api.example.com/data

인증서 없이 요청 (ssl_verify_client on이면 실패)

curl --cacert ca.crt https://api.example.com/data

400 Bad Request - No required SSL certificate was sent

11. 자체 서명 인증서 생성 (개발용)

11.1 단일 도메인

개인키 + 자체 서명 인증서 한 번에 생성

openssl req -x509 -newkey rsa:2048 -nodes \

-keyout selfsigned.key \

-out selfsigned.crt \

-days 365 \

-subj "/C=KR/ST=Seoul/O=Dev/CN=localhost"

11.2 SAN (Subject Alternative Name) 포함

여러 도메인이나 IP를 포함하는 인증서:

SAN 설정 파일 생성

cat > san.cnf << 'SANEOF'

[req]

default_bits = 2048

prompt = no

default_md = sha256

distinguished_name = dn

req_extensions = v3_req

[dn]

C = KR

ST = Seoul

O = Dev

CN = localhost

[v3_req]

subjectAltName = @alt_names

[alt_names]

DNS.1 = localhost

DNS.2 = myapp.local

DNS.3 = *.myapp.local

IP.1 = 127.0.0.1

IP.2 = 192.168.1.100

SANEOF

자체 서명 인증서 생성

openssl req -x509 -newkey rsa:2048 -nodes \

-keyout selfsigned.key \

-out selfsigned.crt \

-days 365 \

-config san.cnf \

-extensions v3_req

11.3 ECDSA 자체 서명 인증서

ECDSA P-256 키 생성

openssl ecparam -genkey -name prime256v1 -out ecdsa.key

자체 서명 인증서

openssl req -x509 -new -key ecdsa.key \

-out ecdsa.crt \

-days 365 \

-subj "/C=KR/ST=Seoul/O=Dev/CN=localhost"

12. 인증서 변환

12.1 PEM에서 DER로

인증서 변환

openssl x509 -in cert.pem -outform DER -out cert.der

개인키 변환

openssl rsa -in key.pem -outform DER -out key.der

12.2 DER에서 PEM으로

openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem

12.3 PFX/PKCS12에서 PEM으로

PFX에서 인증서 추출

openssl pkcs12 -in certificate.pfx -clcerts -nokeys -out cert.pem

PFX에서 개인키 추출

openssl pkcs12 -in certificate.pfx -nocerts -nodes -out key.pem

PFX에서 CA 체인 추출

openssl pkcs12 -in certificate.pfx -cacerts -nokeys -out chain.pem

12.4 PEM에서 PFX/PKCS12로

openssl pkcs12 -export \

-out certificate.pfx \

-inkey key.pem \

-in cert.pem \

-certfile chain.pem

13. 인증서 검증 명령어

13.1 인증서 내용 확인

인증서 전체 정보

openssl x509 -in cert.pem -text -noout

발급자 정보

openssl x509 -in cert.pem -issuer -noout

주체 정보

openssl x509 -in cert.pem -subject -noout

만료일

openssl x509 -in cert.pem -enddate -noout

SAN (Subject Alternative Names)

openssl x509 -in cert.pem -noout -ext subjectAltName

시리얼 번호

openssl x509 -in cert.pem -serial -noout

13.2 원격 서버 인증서 확인

서버 인증서 조회

openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \

openssl x509 -text -noout

인증서 체인 확인

openssl s_client -connect example.com:443 -servername example.com -showcerts < /dev/null 2>/dev/null

TLS 버전 및 cipher 확인

openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \

grep -E "Protocol|Cipher"

13.3 인증서-키 매칭 확인

인증서와 키의 modulus 비교 (같아야 매칭)

openssl x509 -noout -modulus -in cert.pem | openssl md5

openssl rsa -noout -modulus -in key.pem | openssl md5

두 값이 동일하면 인증서와 키가 매칭

14. 보안 점검 도구

14.1 SSL Labs

온라인으로 TLS 설정을 점검하는 서비스다.

https://www.ssllabs.com/ssltest/analyze.html?d=example.com

등급 기준:

A+ = 최상 (HSTS + 강력한 설정)

A = 우수

B = 양호 (개선 권장)

C = 미흡 (보안 위험)

F = 위험 (즉시 조치 필요)

14.2 testssl.sh

커맨드라인에서 TLS 설정을 점검하는 오픈소스 도구다.

설치

git clone --depth 1 https://github.com/drwetter/testssl.sh.git

전체 점검

./testssl.sh/testssl.sh example.com

특정 항목만 점검

./testssl.sh/testssl.sh --protocols example.com

./testssl.sh/testssl.sh --ciphers example.com

./testssl.sh/testssl.sh --headers example.com

./testssl.sh/testssl.sh --vulnerabilities example.com

14.3 Nginx 설정 검증

Nginx 설정 문법 검사

sudo nginx -t

Nginx 설정 전체 출력

sudo nginx -T

Gixy (Nginx 보안 분석 도구)

pip install gixy

gixy /etc/nginx/nginx.conf

15. Let's Encrypt 자동 갱신 연동

15.1 Certbot + Nginx Reload Hook

certbot 갱신 후 Nginx reload

sudo certbot renew --deploy-hook "systemctl reload nginx"

또는 renewal 설정 파일에 직접 추가

/etc/letsencrypt/renewal/example.com.conf

[renewalparams]

...

renew_hook = systemctl reload nginx

15.2 Docker Compose에서 자동 갱신

version: '3.8'

services:

nginx:

image: nginx:latest

ports:

- '80:80'

- '443:443'

volumes:

- ./nginx/conf.d:/etc/nginx/conf.d

- ./certbot/conf:/etc/letsencrypt

- ./certbot/www:/var/www/certbot

restart: unless-stopped

command: '/bin/sh -c ''while :; do sleep 6h & wait; nginx -s reload; done & nginx -g "daemon off;"'''

certbot:

image: certbot/certbot

volumes:

- ./certbot/conf:/etc/letsencrypt

- ./certbot/www:/var/www/certbot

entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait; done'"

16. 설정 체크리스트

프로덕션 배포 전 확인해야 할 항목:

| 항목 | 명령어 / 확인 방법 | 기준 |

| --------------- | ------------------------ | ----------------- |

| TLS 버전 | ssl_protocols | TLSv1.2 TLSv1.3만 |

| 인증서 체인 | fullchain.pem 사용 | 중간 CA 포함 |

| HSTS | 헤더 확인 | max-age 1년 이상 |

| OCSP Stapling | openssl s_client -status | Cert Status: good |

| HTTP 리다이렉트 | curl -I http://domain | 301 to HTTPS |

| SSL Labs 등급 | ssllabs.com | A+ 목표 |

| 개인키 권한 | ls -la privkey.pem | 600 (root only) |

| 자동 갱신 | certbot renew --dry-run | 성공 |

| DH 파라미터 | 2048비트 이상 | 생성 완료 |

| Session Tickets | off | Forward Secrecy |

17. 결론

Nginx TLS 설정은 단순히 인증서를 적용하는 것을 넘어서 종합적인 보안 최적화가 필요하다. 핵심 정리:

- **fullchain.pem + privkey.pem**을 사용하여 인증서 체인을 완성

- **TLS 1.2/1.3**만 허용하고 레거시 프로토콜 비활성화

- **Mozilla Intermediate** 프로파일의 암호화 스위트 권장

- **HSTS**로 HTTPS 접속 강제, **OCSP Stapling**으로 성능 향상

- **SSL 세션 캐싱**으로 핸드셰이크 오버헤드 감소

- **HTTP/2**로 웹 성능 최적화

- **mTLS**로 마이크로서비스 간 양방향 인증 구현

- **SSL Labs**에서 A+ 등급을 목표로 설정 최적화

- Let's Encrypt 인증서 **자동 갱신**을 반드시 설정

현재 단락 (1/351)

PEM은 Base64로 인코딩된 인증서/키 형식이다. 텍스트 에디터로 열어볼 수 있다.

작성 글자: 0원문 글자: 13,973작성 단락: 0/351