Nginx와 Certbot으로 HTTPS 환경 구축하기

김슭삵·2025년 5월 26일
post-thumbnail

들어가며

이번 글에서는 Nginx 웹 서버와 Let's Encrypt의 Certbot을 활용하여 무료 SSL 인증서를 발급받고 HTTPS 환경을 구축하는 방법, 그리고 실제 운영 중 발생할 수 있는 인증서 갱신 문제의 해결 과정을 자세히 알아보겠습니다.

Nginx란?

Nginx(엔진엑스)는 러시아의 Igor Sysoev가 개발한 고성능 웹 서버이자 리버스 프록시 서버입니다. 현재 전 세계에서 가장 널리 사용되는 웹 서버 중 하나로, 높은 성능과 안정성을 자랑합니다.

Nginx의 핵심 특징

이벤트 기반 아키텍처
전통적인 프로세스/스레드 기반 서버와 달리 이벤트 기반의 비동기 처리 방식을 사용합니다. 이를 통해 적은 메모리로 많은 동시 연결을 처리할 수 있습니다.

높은 성능과 확장성
C10K 문제(동시에 10,000개의 연결을 처리하는 문제)를 해결하기 위해 설계되어, 대량의 동시 접속을 효율적으로 처리할 수 있습니다.

낮은 메모리 사용량
Apache에 비해 훨씬 적은 메모리를 사용하면서도 더 많은 요청을 처리할 수 있어 비용 효율적입니다.

모듈식 구조
필요한 기능만 선택적으로 로드할 수 있는 모듈식 구조로 되어 있어 리소스를 효율적으로 사용합니다.

Nginx의 주요 용도

웹 서버
정적 파일(HTML, CSS, JavaScript, 이미지)을 빠르게 제공하는 웹 서버로 사용됩니다.

리버스 프록시
클라이언트의 요청을 백엔드 서버로 전달하고 응답을 다시 클라이언트에게 전달하는 중간 역할을 합니다.

로드 밸런서
여러 백엔드 서버 간에 요청을 분산시켜 부하를 균등하게 분배합니다.

캐싱 서버
자주 요청되는 콘텐츠를 메모리나 디스크에 캐싱하여 응답 속도를 향상시킵니다.

SSL 터미네이션
HTTPS 연결을 처리하고 백엔드와는 HTTP로 통신하여 SSL 처리 부담을 덜어줍니다.

Nginx vs Apache

성능

  • Nginx: 이벤트 기반으로 메모리 사용량이 적고 동시 연결 처리에 뛰어남
  • Apache: 프로세스/스레드 기반으로 메모리 사용량이 상대적으로 많음

설정

  • Nginx: 간결하고 직관적인 설정 파일
  • Apache: .htaccess 파일을 통한 유연한 디렉토리별 설정

모듈

  • Nginx: 컴파일 시점에 모듈 결정
  • Apache: 런타임에 동적 모듈 로딩 가능

Certbot과 Let's Encrypt란?

Let's Encrypt는 Mozilla, Cisco, Akamai 등이 후원하는 비영리 인증 기관(CA)으로, 무료로 SSL/TLS 인증서를 발급해주는 서비스입니다. Certbot은 Let's Encrypt에서 제공하는 공식 클라이언트 도구로, 인증서의 발급부터 설치, 갱신까지 자동화해주는 도구입니다.

Let's Encrypt의 혁신

무료 인증서
기존에 연간 수십만 원을 지불해야 했던 SSL 인증서를 무료로 제공하여 HTTPS 보급에 크게 기여했습니다.

자동화
ACME(Automated Certificate Management Environment) 프로토콜을 통해 인증서 발급과 갱신을 완전히 자동화했습니다.

도메인 검증 (DV)
도메인 소유권만 확인하여 빠르게 인증서를 발급합니다. 기업 검증(OV)이나 확장 검증(EV)은 제공하지 않습니다.

90일 유효기간
짧은 유효기간을 통해 보안을 강화하고 자동 갱신을 유도합니다.

Certbot의 인증 방식

Standalone 방식
Certbot이 임시 웹 서버를 실행하여 도메인 소유권을 확인합니다. 80번 포트가 비어있어야 사용 가능합니다.

Webroot 방식
기존 웹 서버의 문서 루트에 임시 파일을 생성하여 도메인 소유권을 확인합니다. 웹 서버를 중단하지 않고 인증서를 발급받을 수 있습니다.

DNS 방식
DNS 레코드를 추가하여 도메인 소유권을 확인합니다. 와일드카드 인증서 발급 시 사용됩니다.

플러그인 방식
Nginx, Apache 등의 웹 서버 플러그인을 통해 자동으로 설정까지 완료합니다.

Nginx 설치 및 기본 설정

1단계: Nginx 설치 및 활성화

sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx

각 명령어의 의미:

  • apt install nginx: Ubuntu 패키지 저장소에서 Nginx 설치
  • systemctl enable: 시스템 부팅 시 자동으로 Nginx 시작되도록 설정
  • systemctl start: 즉시 Nginx 서비스 시작

2단계: 방화벽 설정

웹 서버가 외부에서 접근 가능하도록 필요한 포트를 개방합니다.

# 방화벽 설정
sudo ufw allow 'Nginx Full'
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

포트별 용도:

  • 80번 포트: HTTP 트래픽용
  • 443번 포트: HTTPS 트래픽용
  • 'Nginx Full': Nginx의 HTTP/HTTPS 프로필을 한번에 허용

3단계: Nginx 동작 확인

웹 브라우저에서 http://[서버IP]로 접속하여 Nginx 기본 페이지가 표시되는지 확인합니다.

# Nginx 상태 확인
sudo systemctl status nginx

# Nginx 설정 테스트
sudo nginx -t

Certbot 설치 및 SSL 인증서 발급

1단계: Certbot 설치

sudo apt install -y certbot python3-certbot-nginx

설치되는 패키지:

  • certbot: Let's Encrypt 클라이언트
  • python3-certbot-nginx: Nginx 플러그인

2단계: SSL 인증서 발급

# SSL/TLS 인증서 발급
sudo certbot --nginx -d <EC2_public_ip> -d <your domain>

명령어 옵션 설명:

  • --nginx: Nginx 플러그인 사용
  • -d: 인증서에 포함할 도메인 지정 (여러 도메인 지정 가능)

인증서 발급 과정:
1. 도메인 소유권 확인: 각 도메인에 임시 파일을 생성하여 소유권 확인
2. 인증서 생성: Let's Encrypt에서 인증서 발급
3. Nginx 설정 자동 수정: SSL 설정이 자동으로 추가됨
4. HTTPS 리다이렉트 설정: HTTP 요청을 HTTPS로 자동 리다이렉트

3단계: 인증서 확인

# 발급된 인증서 확인
sudo certbot certificates

# 인증서 갱신 테스트
sudo certbot renew --dry-run

실제 운영 중 발생한 SSL 인증서 갱신 문제 및 해결

1단계: 초기 문제 상황 파악

실제 운영 환경에서 다음과 같은 문제가 발생했습니다:

문제 증상

  • Certbot 서비스가 성공적으로 시작되지 않음
  • systemctl status certbot 실행 시 "Failed to start Certbot" 오류 표시
  • 서비스가 시작 후 즉시 종료되는 현상

초기 진단

# 서비스 상태 확인
sudo systemctl status certbot

# 인증서 상태 확인
sudo certbot certificates

2단계: 인증서 상태 확인 및 문제 분석

# 인증서 목록 확인
sudo certbot certificates

확인 결과

  • 두 개의 인증서(your domain, EC2 public ip) 존재
  • 모든 인증서가 유효한 상태 (89일 남음)
  • 인증서 자체에는 문제가 없음

갱신 테스트 실행

sudo certbot renew --dry-run

문제 발견

  • your domain 인증서 갱신 실패
  • 80번 포트 바인딩 문제 발생
  • 오류 메시지: "Address already in use" 또는 "Port 80 is already in use"

3단계: 문제 원인 분석

근본 원인
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

4단계: 해결 과정

4-1. 웹루트 디렉토리 설정 및 권한 조정

# 웹루트 디렉토리 생성
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

권한 설정의 중요성

  • 소유권: www-data 사용자가 파일을 읽고 쓸 수 있도록 설정
  • 권한: 755 권한으로 디렉토리 접근과 파일 읽기 허용

4-2. 연결 테스트

# 테스트 파일 생성
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

4-3. Certbot 인증 방식 변경

가장 중요한 단계로, 인증 방식을 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

변경 사항 설명

  • authenticator: standalonewebroot로 변경
  • webroot_path: 웹루트 디렉토리 경로 명시적 지정

4-4. 갱신 테스트 재실행

# 명시적 웹루트 경로 지정하여 갱신 테스트
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)

4-5. 자동 갱신 활성화

# Certbot 타이머 활성화
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

# 타이머 상태 확인
sudo systemctl status certbot.timer

# 타이머 스케줄 확인
sudo systemctl list-timers certbot.timer

자동 갱신의 중요성

  • Let's Encrypt 인증서는 90일마다 갱신 필요
  • 자동 갱신 설정으로 인증서 만료 방지
  • 일반적으로 하루에 두 번 갱신 체크 수행

Nginx SSL 설정 최적화

보안 헤더 추가

# /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 프로토콜 및 암호화 방식 설정
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 오류

  • HTTP 리소스를 HTTPS 페이지에서 로드할 때 발생
  • 모든 리소스 URL을 HTTPS로 변경 필요

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 인증서를 통해 비용 부담 없이 보안을 강화할 수 있으며, 자동 갱신 시스템으로 운영 부담도 크게 줄일 수 있습니다.

profile
비전공자의 개발 적응기

0개의 댓글