본문 바로가기
개발/배포

[배포] Route 53 + Nginx + Certbot으로 Https 적용하기

by 경험의 가치 2024. 6. 23.

 

0. 시작하기전에

도메인 관련 서비스는 좋은 것이 꽤 많다. 예를 들어, DNS로는 유명한 것이 AWS Route 53이 있고, ACM 같은 것을 이용하여 손쉽게 인증서를 구입하고 적용할 수 있을 것이다. 하지만, 이런 서비스들은 꽤나 비싸다.... (Route 53은 싸긴함)

 

그래서 학생들도 부담없이 HTTPS를 적용할 수 있는 방법인 Route 53 + Nginx + Certbot 방법을 소개하고자 한다.

 

일단 ACM 같은 인증서 관리 서비스에 들어가보면, 인증서마다 가격이 천차만별이다. 왜 그럴까? 인증서도 여러가지 종류가 있기 때문이다. 인증서 종류는 크게 DV/OV/EV 3가지로 나눌 수 있다.

 

  • DV : Domain Validation, 즉 도메인 소유 정보만 검증하는 인증서이다. 그래서 발급하기도 쉽고, 누구나 발급이 가능하다. 신뢰성 면에서는 OV나 EV 인증서보단 좀 떨어지지만, TLS/SSL 암호화 과정은 동일하기 때문에 보안통신에서는 전혀 차이가 없다. 개인레벨에서 TLS/SSL 인증서는 이게 한계라고 본다.
  • OV : Organization Validation, 즉 도메인의 소유 정보와 소속되어 있는 조직 정보까지 검증하는 인증서이다. 조직의 실체가 증명되야 하므로 사업자 등록증 등의 정보가 필요하다. 그렇다보니 고객들은 DV인증서보다 더욱 이 사이트를 신뢰할 수 있는 것이다. 우리가 이름 들어본 네이버/카카오 등의 대기업들이 사용한다. 그리고 OV 인증서 레벨부터 IP 주소에 대해서 SSL 인증서를 발급받을 수 있다. (DV 인증서 직군에서는 좀 제한적임) 그래서 개인이 HTTPS를 적용하고 싶다면 거의 반드시 도메인을 구입해야된다.
  • EV : Extended Validation, 즉 OV의 확장판이다. 도메인 소유정보 + 소속되어 있는 조직 + 법인 2년 이상 운영 조건 등등 까다로운 조건이 충족되야 발급이 된다. 최상급 신뢰성을 가져서 금융권/카드사/공공기관 등에서 많이 사용한다.

그래서 우리가 발급 받을 것은 DV 인증서이다. 그 중에서도 Let's Encrypt라는 CA로 부터 인증서를 발급받을 것이다. 왜 굳이 Let's Encrypt냐? 해당 CA는 SSL 인증서 발급이 무료이다. 그래서 부담없이 HTTPS를 적용할 수 있다.

 

1. 도메인 구매하기

도메인은 어디서 살까? 많은 도메인 대행업체들이 있지만 내가 개인적으로 추천하고 싶은 것은 가비아 도메인이다. 

 

 

가비아: 대한민국 도메인 점유율 1위

대한민국 100만 도메인 등록 업체

domain.gabia.com

 

굉장히 저렴한 가격으로 도메인을 구입할 수 있다.

 

초기 1년은 왼쪽에 보이는 저렴한 가격으로 도메인 사용이 가능하다. 하지만, 1년후에는 오른쪽에 보이는 가격을 지불해야된다. 어쨋든 원하는 도메인을 찾은 후, 구매를 진행하자.

 

2. Route 53에 호스팅 영역 생성하기

 

그다음 가비아에서 구매한 도메인을 AWS Route 53에서 호스팅 할 것이다. (반드시 Route 53을 써야되는 것은 아니다. 가비아 내 DNS을 이용하여 진행해도 괜찮다. 하지만, 굳이 Route 53을 사용하는 이유는 더 신뢰성 있고 AWS 인프라와 연동이 쉽기 때문이다.)

 

 

오른쪽 상단의 호스팅 영역 생성을 클릭하자

 

 

그 다음 구매한 도메인을 입력하고 퍼블릭 호스팅 영역을 만들자.

 

생성한 후 세부 정보에 들어가보면 NS 레코드에 있는 값들을 이제 가비아 도메인에 입력해줘야 된다.

 

이제 가비아에서 내 도메인 관리에 들어가서 네임서버 설정에 들어간다.

 

아까 Route 53에서 NS 레코드에서 봤던 값들을 입력해준다. 이때, 맨 뒤에 있는 .은 빼고 입력해야된다.

 

이제 우리 도메인과 ec2를 맵핑 시켜줘야된다. 레코드는 A 타입으로 만들고, 값에 우리 ec2의 고정 ip 주소를 입력하자. TTL은 DNS 캐시를 유지하는 시간을 나타낸다. 일반적으로 300으로 하므로, 300으로 하면 된다. 바꾸고 싶으면 바꿔도 무방하다. 이러면 이제 우리 도메인과 ec2가 연결이 됐다! (바로 적용 안됩니다. 몇분 ~ 몇일이 걸릴 수도 있습니다!!)

 

3. Certbot과 Nginx를 이용하여 DV 인증서 발급받기

certbot이란 Let's Encrypt CA로 부터 SSL 인증서를 쉽게 발급 받고 갱신할 수 있게 도와주는 무료 오픈소스 툴이다. 우리는 편하게 Docker로 진행할 것이므로, 진행하려는 EC2 환경에 반드시 Docker 환경을 구축해놓도록 하자!!

 

Docker 환경 구축은 아래 공식 사이트에 친절하게 잘 나와있으니 그대로 따라하면 된다.

 

Install Docker Engine on Ubuntu

Jumpstart your client-side server applications with Docker Engine on Ubuntu. This guide details prerequisites and multiple methods to install Docker Engine on Ubuntu.

docs.docker.com

 

Nginx와 Certbot이 SSL 인증서를 발급받는 원리를 간단하게 설명하자면, Certbot이 도메인의 소유권을 확인하기 위해서 Challenge 파일을 생성한다. 그리고 Let's Encrypt에서 http 80번 포트로 접속해서 이 Challenge 파일에 접근한다. 만약에 정상적으로 Challenge 파일에 도달한다면 도메인의 소유권이 증명되고, 안전한 연결이라고 SSL 인증서를 발급해주고 Certbot이 이 인증서를 서버에 저장해두는 구조이다.

 

Challenge 파일에 접근하려면 80포트(http)와 443포트(https)가 필요하므로 방화벽 설정과 Docker Compose 설정에서 해당 포트를 반드시 열어줘야한다!!

 

이제 인증서를 발급받기 위해서 Nginx와 Certbot을 띄우기 위해 Docker Compose를 작성해보자.

 

version: '3'

services:
  nginx:
    image: nginx:1.15-alpine
    restart: unless-stopped
    volumes:
      - ./conf/nginx.conf:/etc/nginx/nginx.conf
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
  certbot:
    image: certbot/certbot
    restart: unless-stopped
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

 

여기서 nginx volume부분은 nginx 설정 파일과, 아까말한 challenge 파일, 인증서들을 공유하기 위한 것이다. (certbot도 똑같음) 또한, command ~~ 부분을 주목 할만 한데, 인증서를 자동 갱신하기 위한 부분이다. Let's Encrypt로 부터 받은 SSL 인증서는 30일 후에 만료된다. 그런데 우리가 매번 인증서를 갱신할 수 없지 않은가? 그래서 30일마다 자동 갱신해주도록 구성한 것이다.

 

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

 

이 부분은 무한루프를 하면서 6시간마다 Nginx의 설정을 다시 로드하는 명령어이다. 조금 더 자세하게 소개하자면

  • do sleep 6h & wait ~~ : 현재 스크립트를 6시간동안 멈춰라
  • nginx -s reload : nginx 설정을 다시 리로드해라
  • nginx -g \"daemon off;\""" : nginx를 데몬 모드가 아닌 포어그라운드에서 실행하라는 의미이다. 이는 Docker 컨테이너의 주요 프로세스로 Nginx를 실행시켜 Nginx의 생명주기가 컨테이너의 생명기를 제어하도록 하기 위함이다. Docker 컨테이너 생명주기의 특성중 하나가 컨테이너는 주요 프로세스 하나 이상과 연계하여 실행하도록 설계된다. 즉, 컨테이너 수명은 그 주요 프로세스와 직접적으로 연관되고, 주요 프로세스가 종료되면 컨테이너도 종료된다. 만약에 Nginx가 데몬 모드로 실행되면 주요 프로세스가 없다고 인식되어서 의도치않게 컨테이너가 종료될 수 있기 때문이다.

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

 

이 부분은 무한루프를 실행하면서 12시간마다 Certbot을 이용해서 SSL 인증서를 갱신하는 명령어이다. 이것도 간단하게 설명해보자면

 

  • trap exit TERM : TERM 시그널을 받으면 trap을 발생시켜서 종료해라. Docker 컨테이너를 종료할 때는 보통 TERM 시그널을 보내므로, 이 명령을 통해 Docker 컨테이너를 정상적으로 종료할 수 있다.
  • do certbot renew : 인증서 갱신 명령어

그럼 이제 Nginx conf 파일을 작성해보자.

 

./conf/nginx.conf 파일이다.

server {
    listen 80;
    server_name example.org;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name example.org;
    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass  http://example.org;
        proxy_set_header    Host                $http_host;
        proxy_set_header    X-Real-IP           $remote_addr;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
    }
}

 

example.org 부분에 자신의 도메인을 넣어주면 된다. 중요한 것이 AWS EC2에 기본으로 발급되는 도메인으로는 SSL 인증서가 발급되지 않는다!!! 반드시 따로 도메인을 구입하고, 그것으로 인증서 발급을 받아야한다.

 

여기서 location /.well-known/acme-challenge/ 이 부분이 바로 challenge 파일 해석을 통해서 도메인 소유권을 확인하게되는 경로인 것이다.

 

return 301 ~~ 부분은 80포트로 들어오는 HTTP 요청을 모두 HTTPS로 리다이렉트하는 부분이다. 301은 Moved Permanetly를 나타낸다.

 

근데 좀 이상한 부분이 있다. 아마 위처럼 구성하고 Docker Compose를 실행하면 작동하지 않을 것이다. 왜냐하면 Let's Encrypt로부터 인증서를 발급받으려면 Nginx가 필요하지만, 인증서가 없으면 Nginx가 시작되지 않는다. 그래서 임시로 https를 사용하지 않는 척 더미 인증서를 발급받고, nginx 서버를 시작한 후, 더미 인증서를 삭제하고 실제 인증서를 발급 받는 것이다. 이 과정을 자동화 해둔 좋은 스크립트가 있다.

 

 

GitHub - wmnnd/nginx-certbot: Boilerplate configuration for nginx and certbot with docker-compose

Boilerplate configuration for nginx and certbot with docker-compose - wmnnd/nginx-certbot

github.com

 

curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > init-letsencrypt.sh
chmod +x init-letsencrypt.sh
vim init-letsencrypt.sh
sudo ./init-letsencrypt.sh

 

위 과정을 통해서 더미 인증서를 발급받고, 실제 인증서를 발급하는 과정을 자동화 해보자. 만약 안된다면 높은 확률로 Docker Compose의 Volume 설정이 잘못되거나 포트를 열지 않은 것이다. 내가 Volume 설정을 잘못해서 많이 애먹었다...

 

또한, vim init ~~ 하는 과정에서 바꿔야될 부분이 몇몇 있다. 

domain에는 우리의 도메인을 입력해주고, email에는 SSL 인증서를 발급받았을 때 알림을 받을 이메일을 써준다. (근데 안올때도 있는듯..?) staging은 테스트로 발급 받을거면 1로 바꾸면 된다. 인증서 발급받을 수 있는 횟수 제한이 있어서 테스트로 해볼거면 1로 해보는 것이다.

 

이렇게 바꿔주고 설정을 제대로 했다면, 정상적으로 우리 도메인에 대한 인증서가 발급될 것이고, https로 접속이 가능해질 것이다.

 

 짜잔! 이렇게 인증서 발급에 성공했다!! 내가 이걸 5월 정도에 했었는데, 자동으로 갱신도 잘 되었다!


💡참고자료

 

 

'개발 > 배포' 카테고리의 다른 글

[배포] "외국민" 서비스 배포 과정 - (1)  (0) 2024.05.04