Apache SSL/TLS 설정 완전 정복
Apache HTTPD는 mod_ssl 모듈을 통해 HTTPS를 지원합니다. SSLEngine, SSLProtocol, SSLCipherSuite 등 핵심 지시어를 설정해 안전한 HTTPS 환경을 구성합니다.
mod_ssl 설치 및 활성화
# Ubuntu/Debian
sudo apt install libapache2-mod-ssl
sudo a2enmod ssl
sudo a2enmod headers # 보안 헤더용
sudo a2enmod rewrite # HTTP→HTTPS 리다이렉트용
sudo systemctl restart apache2
# CentOS/RHEL (대부분 기본 포함)
sudo dnf install mod_ssl
sudo systemctl restart httpd
# 활성화 확인
apache2ctl -M | grep ssl
# ssl_module (shared)
기본 HTTPS VirtualHost 설정
# /etc/apache2/sites-available/example.com-ssl.conf
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/html
DirectoryIndex index.html index.php
# SSL 활성화
SSLEngine On
# 인증서 파일
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
# 애플리케이션 설정
<Directory /var/www/html>
AllowOverride All
Require all granted
</Directory>
# 로그
CustomLog /var/log/apache2/example.com-ssl-access.log combined
ErrorLog /var/log/apache2/example.com-ssl-error.log
</VirtualHost>
# 사이트 활성화
sudo a2ensite example.com-ssl.conf
sudo systemctl reload apache2
TLS 버전과 암호 스위트 전역 설정
전역 SSL 설정은 ssl.conf 또는 apache2.conf에서 관리합니다.
# /etc/apache2/mods-available/ssl.conf 또는 conf-available/ssl-security.conf
# TLS 버전: 1.2와 1.3만 허용
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
# 암호 스위트 (TLS 1.2용)
SSLCipherSuite 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
# TLS 1.3 암호 스위트
SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
# 서버 암호 스위트 우선순위 (off = 클라이언트 우선, TLS 1.3 권장)
SSLHonorCipherOrder off
# ECDH 곡선
SSLOpenSSLConfCmd Curves X25519:prime256v1:secp384r1
# 세션 캐시
SSLSessionCache shmcb:/run/apache2/ssl_scache(512000)
SSLSessionCacheTimeout 300
# OCSP Stapling
SSLUseStapling On
SSLStaplingCache shmcb:/run/apache2/ssl_stapling(32768)
SSLStaplingReturnResponderErrors off
HTTP → HTTPS 리다이렉트
# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# Let's Encrypt 인증용 경로는 제외
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
Require all granted
</Directory>
# 나머지 모든 요청 → HTTPS
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
또는 더 간단하게:
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
HSTS 및 보안 헤더 설정
<VirtualHost *:443>
ServerName example.com
SSLEngine On
# ... 인증서 설정 ...
# 보안 헤더 (mod_headers 필요)
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
# 서버 정보 숨기기
ServerTokens Prod
ServerSignature Off
</VirtualHost>
완전한 프로덕션 Apache HTTPS 설정
# /etc/apache2/sites-available/production-ssl.conf
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/html
# SSL 설정
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
# TLS 버전
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
# 암호 스위트
SSLCipherSuite 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
SSLHonorCipherOrder off
# OCSP Stapling
SSLUseStapling On
# 보안 헤더
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'"
# 리버스 프록시 (Tomcat으로)
ProxyRequests Off
ProxyPreserveHost On
ProxyPass "/" "http://localhost:8080/"
ProxyPassReverse "/" "http://localhost:8080/"
# 백엔드에 HTTPS 정보 전달
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
# 로그
CustomLog /var/log/apache2/ssl-access.log combined
ErrorLog /var/log/apache2/ssl-error.log
</VirtualHost>
설정 검증
# 문법 확인
sudo apachectl configtest
# 적용
sudo systemctl reload apache2
# SSL 설정 확인
openssl s_client -connect example.com:443 -tls1_3 2>/dev/null | head -20
# Apache SSL 상태 확인
sudo apachectl -D DUMP_RUN_CFG | grep SSL
# 포트 확인
sudo ss -tlnp | grep -E '80|443'
멀티 도메인 HTTPS (SNI)
하나의 서버에서 여러 도메인의 HTTPS를 운영합니다.
# 도메인 A
<VirtualHost *:443>
ServerName example.com
SSLEngine On
SSLCertificateFile /etc/ssl/example.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/example.com/privkey.pem
DocumentRoot /var/www/example.com
</VirtualHost>
# 도메인 B
<VirtualHost *:443>
ServerName another.com
SSLEngine On
SSLCertificateFile /etc/ssl/another.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/another.com/privkey.pem
DocumentRoot /var/www/another.com
</VirtualHost>
SNI(Server Name Indication) 덕분에 443 포트 하나로 여러 인증서를 사용할 수 있습니다. 현대 브라우저는 모두 SNI를 지원합니다.
다음 페이지에서는 HTTPS 오프로딩(SSL Termination) — 로드밸런서에서 TLS를 종료하고 HTTP로 백엔드에 전달하는 방법을 알아봅니다.