들어가며
이번 글에서는 Nginx 웹 서버와 Let's Encrypt의 Certbot을 활용하여 무료 SSL 인증서를 발급받고 HTTPS 환경을 구축하는 방법, 그리고 실제 운영 중 발생할 수 있는 인증서 갱신 문제의 해결 과정을 자세히 알아보겠습니다.
Nginx(엔진엑스)는 러시아의 Igor Sysoev가 개발한 고성능 웹 서버이자 리버스 프록시 서버입니다. 현재 전 세계에서 가장 널리 사용되는 웹 서버 중 하나로, 높은 성능과 안정성을 자랑합니다.
이벤트 기반 아키텍처
전통적인 프로세스/스레드 기반 서버와 달리 이벤트 기반의 비동기 처리 방식을 사용합니다. 이를 통해 적은 메모리로 많은 동시 연결을 처리할 수 있습니다.
높은 성능과 확장성
C10K 문제(동시에 10,000개의 연결을 처리하는 문제)를 해결하기 위해 설계되어, 대량의 동시 접속을 효율적으로 처리할 수 있습니다.
낮은 메모리 사용량
Apache에 비해 훨씬 적은 메모리를 사용하면서도 더 많은 요청을 처리할 수 있어 비용 효율적입니다.
모듈식 구조
필요한 기능만 선택적으로 로드할 수 있는 모듈식 구조로 되어 있어 리소스를 효율적으로 사용합니다.
웹 서버
정적 파일(HTML, CSS, JavaScript, 이미지)을 빠르게 제공하는 웹 서버로 사용됩니다.
리버스 프록시
클라이언트의 요청을 백엔드 서버로 전달하고 응답을 다시 클라이언트에게 전달하는 중간 역할을 합니다.
로드 밸런서
여러 백엔드 서버 간에 요청을 분산시켜 부하를 균등하게 분배합니다.
캐싱 서버
자주 요청되는 콘텐츠를 메모리나 디스크에 캐싱하여 응답 속도를 향상시킵니다.
SSL 터미네이션
HTTPS 연결을 처리하고 백엔드와는 HTTP로 통신하여 SSL 처리 부담을 덜어줍니다.
성능
설정
모듈
Let's Encrypt는 Mozilla, Cisco, Akamai 등이 후원하는 비영리 인증 기관(CA)으로, 무료로 SSL/TLS 인증서를 발급해주는 서비스입니다. Certbot은 Let's Encrypt에서 제공하는 공식 클라이언트 도구로, 인증서의 발급부터 설치, 갱신까지 자동화해주는 도구입니다.
무료 인증서
기존에 연간 수십만 원을 지불해야 했던 SSL 인증서를 무료로 제공하여 HTTPS 보급에 크게 기여했습니다.
자동화
ACME(Automated Certificate Management Environment) 프로토콜을 통해 인증서 발급과 갱신을 완전히 자동화했습니다.
도메인 검증 (DV)
도메인 소유권만 확인하여 빠르게 인증서를 발급합니다. 기업 검증(OV)이나 확장 검증(EV)은 제공하지 않습니다.
90일 유효기간
짧은 유효기간을 통해 보안을 강화하고 자동 갱신을 유도합니다.
Standalone 방식
Certbot이 임시 웹 서버를 실행하여 도메인 소유권을 확인합니다. 80번 포트가 비어있어야 사용 가능합니다.
Webroot 방식
기존 웹 서버의 문서 루트에 임시 파일을 생성하여 도메인 소유권을 확인합니다. 웹 서버를 중단하지 않고 인증서를 발급받을 수 있습니다.
DNS 방식
DNS 레코드를 추가하여 도메인 소유권을 확인합니다. 와일드카드 인증서 발급 시 사용됩니다.
플러그인 방식
Nginx, Apache 등의 웹 서버 플러그인을 통해 자동으로 설정까지 완료합니다.
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
각 명령어의 의미:
웹 서버가 외부에서 접근 가능하도록 필요한 포트를 개방합니다.
# 방화벽 설정
sudo ufw allow 'Nginx Full'
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable
포트별 용도:
웹 브라우저에서 http://[서버IP]로 접속하여 Nginx 기본 페이지가 표시되는지 확인합니다.
# Nginx 상태 확인
sudo systemctl status nginx
# Nginx 설정 테스트
sudo nginx -t
sudo apt install -y certbot python3-certbot-nginx
설치되는 패키지:
# SSL/TLS 인증서 발급
sudo certbot --nginx -d <EC2_public_ip> -d <your domain>
명령어 옵션 설명:
인증서 발급 과정:
1. 도메인 소유권 확인: 각 도메인에 임시 파일을 생성하여 소유권 확인
2. 인증서 생성: Let's Encrypt에서 인증서 발급
3. Nginx 설정 자동 수정: SSL 설정이 자동으로 추가됨
4. HTTPS 리다이렉트 설정: HTTP 요청을 HTTPS로 자동 리다이렉트
# 발급된 인증서 확인
sudo certbot certificates
# 인증서 갱신 테스트
sudo certbot renew --dry-run
실제 운영 환경에서 다음과 같은 문제가 발생했습니다:
문제 증상
systemctl status certbot 실행 시 "Failed to start Certbot" 오류 표시초기 진단
# 서비스 상태 확인
sudo systemctl status certbot
# 인증서 상태 확인
sudo certbot certificates
# 인증서 목록 확인
sudo certbot certificates
확인 결과
갱신 테스트 실행
sudo certbot renew --dry-run
문제 발견
근본 원인
1. 포트 충돌: Nginx가 80번 포트를 사용 중인 상태에서 Certbot의 standalone 방식이 같은 포트 사용 시도
2. 인증 방식 문제: 기존 설정이 standalone 방식으로 되어 있어 웹 서버와 충돌
3. 자동 갱신 비활성화: Certbot 타이머가 비활성화 상태
설정 파일 확인
# Nginx 설정 확인
sudo cat /etc/nginx/conf.d/<your_domain_name>.conf
# Certbot 갱신 설정 확인
sudo cat /etc/letsencrypt/renewal/<your domain>.conf
# 웹루트 디렉토리 생성
sudo mkdir -p /var/www/certbot/.well-known/acme-challenge
# 적절한 소유권 설정
sudo chown -R www-data:www-data /var/www/certbot
# 적절한 권한 설정
sudo chmod -R 755 /var/www/certbot
권한 설정의 중요성
# 테스트 파일 생성
echo "test" | sudo tee /var/www/certbot/.well-known/acme-challenge/test.txt
# 웹에서 접근 가능한지 확인
curl http://<your_domain>/.well-known/acme-challenge/test.txt
# 테스트 파일 삭제
sudo rm /var/www/certbot/.well-known/acme-challenge/test.txt
테스트 성공 시 예상 결과
$ curl http://<your_domain>/.well-known/acme-challenge/test.txt
test
가장 중요한 단계로, 인증 방식을 standalone에서 webroot로 변경합니다.
# 갱신 설정 파일 편집
sudo vi /etc/letsencrypt/renewal/<your_domain>.conf
설정 파일 수정 내용
# renew_before_expiry = 30 days
version = 1.21.0
archive_dir = /etc/letsencrypt/archive/<your_domain>
cert = /etc/letsencrypt/live/<your_domain>/cert.pem
privkey = /etc/letsencrypt/live/<your_domain>/privkey.pem
chain = /etc/letsencrypt/live/<your_domain>/chain.pem
fullchain = /etc/letsencrypt/live/<your_domain>/fullchain.pem
# Options used in the renewal process
[renewalparams]
account = 8324c4cd6d5c9f9baf208de12ccda06f
# authenticator = standalone # 기존 설정 주석 처리
authenticator = webroot # webroot 방식으로 변경
webroot_path = /var/www/certbot # 웹루트 경로 지정
server = https://acme-v02.api.letsencrypt.org/directory
변경 사항 설명
standalone → webroot로 변경# 명시적 웹루트 경로 지정하여 갱신 테스트
sudo certbot renew --dry-run --webroot -w /var/www/certbot
성공 시 출력 예시
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/<your_domain>/fullchain.pem (success)
/etc/letsencrypt/live/<your_ec2_ip>/fullchain.pem (success)
# Certbot 타이머 활성화
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
# 타이머 상태 확인
sudo systemctl status certbot.timer
# 타이머 스케줄 확인
sudo systemctl list-timers certbot.timer
자동 갱신의 중요성
# /etc/nginx/conf.d/security.conf
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# SSL 프로토콜 및 암호화 방식 설정
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# SSL 세션 설정
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
1. 인증서 발급 실패
# DNS 전파 확인
nslookup yourdomain.com
# 방화벽 상태 확인
sudo ufw status
# 웹 서버 접근 테스트
curl -I http://yourdomain.com/.well-known/acme-challenge/
2. 인증서 갱신 실패
# 갱신 로그 확인
sudo certbot renew --dry-run --verbose
# 개별 인증서 갱신
sudo certbot renew --cert-name yourdomain.com
3. Mixed Content 오류
4. SSL 핸드셰이크 오류
# SSL 설정 테스트
openssl s_client -connect yourdomain.com:443
# SSL 인증서 체인 확인
openssl x509 -in /etc/letsencrypt/live/yourdomain.com/fullchain.pem -text -noout
마치며
Nginx와 Certbot을 활용한 HTTPS 환경 구축은 현대 웹 서비스의 필수 요소입니다. 무료 SSL 인증서를 통해 비용 부담 없이 보안을 강화할 수 있으며, 자동 갱신 시스템으로 운영 부담도 크게 줄일 수 있습니다.