본문 바로가기

Nginx

[Nginx-ssl] 간단하게 Nginx에 SSL 인증 적용하기(with certbot)

스프링 부트를 사용한 예제 애플리케이션을 AWS를 통해 모노리식에서 MSA로 MSA에서 다시 컨테이너 오케스트레이션으로 개선해나가는 과정을 모두 담은 강의를 출시하게 되었습니다.
강의 과정에서 15개 이상의 서비스를 사용하게 됩니다.
그래서 클라우드 개발자가 아닌 개발자, 학생 분들도 AWS의 폭넓은 지식 쉽고 빠르게 습득할 수 있는 기회가 될 수 있다고 생각합니다!
배너를 누르면 강의로 이동됩니다.

블로그를 통해 구매하시는 분들에게만 10%할인 쿠폰을 증정중입니다.
꼭 아래 쿠폰번호를 입력해 주세요!

16861-259843d6c2d7


 

 
Ubuntu 20.04 (LTS) 환경에서 진행되었음.

 

certbot 이란?

certbotLetsEncrypt 인증서를 자동으로 사용하여 HTTPS를 활성화 오픈소스 소프트웨어 도구이다.
무료로 HTTPS를 적용하기 정말 간단하고, 자동으로 갱신할 수 있어 여러가지 이점이 있다.

 

 

certbot 설치

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository universe
$ sudo apt-get update
$ sudo apt-get install certbot python3-certbot-nginx

 

  • apt-get update - 설치된 모든 패키지를 업데이트 (참고)
  • apt-get install software-properties-common - apt 저장소의 추상화를 제공, 이를 통해 배포 및 독립 소프트웨어 공급업체의 소프트웨어를 쉽게 관리할 수 있음. (참고)
  • add-apt-repository universe - universe 저장소 추가
  • universe 저장소 - 공식적으로 지원되지 않은 커뮤니티 개발 무료 소프트웨어가 있는 저장소
  • python3-certbot-nginx - certbot용 nginx 플러그인

 

 

nginx 구성 파일 작성

진행하려면 Nginx의 80포트 접근을 허용해 주어야한다.
nginx의 data/nginx/conf.d/default.conf 파일 또는 도커로 실행 시 마운트된 볼륨의 80포트 서버블록을 다음과 같이 수정해 준다.
 

server {
    listen       80;
    listen  [::]:80;
    server_name  [server_name];

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

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

server {
    listen 443;
    listen  [::]:443;
    server_name [server_name];
    
    ssl_certificate /etc/letsencrypt/live/[자신의 도메인]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[자신의 도메인]/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    root         /usr/share/nginx/html;
    index index.html index.htm index.php;
}

 

  • 첫번째 location - http(80) 요청을 https(443) 요청으로 리다이렉트를 하기 위한 블록
  • 두번 째 location - certbot에 의해 LetsEncryt에서 80포트로 요청하여 유효한url인지 검증하는 challenge라는 작업을 하게된다. 
  • 443 server - https 요청의 구성을 작성한 블록, ssl인증서를 필요로 한다.

현재 구성은 https 요청 시 nginx기본 index파일이 보여지도록 설정되어있다. (/usr/share/nginx/html/index.html)
 

 

docker compose 파일 생성

nginx 와 certbot의 image를 구동시킬 compose파일을 다음과 같이 작성해준다.
 

version: '3.8'
services:
  nginx:
    container_name: nginx
    image: nginx
    ports:
     - 80:80
     - 443:443
    networks:
     - my-network
    volumes:
     - my-nginx-conf:/etc/nginx
     - /home/ubuntu/certbot/conf:/etc/letsencrypt
     - /home/ubuntu/certbot/www:/var/www/certbot
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

  certbot:
    container_name: certbot
    image: certbot/certbot
    restart: always
    volumes:
     - /home/ubuntu/certbot/conf:/etc/letsencrypt
     - /home/ubuntu/certbot/www:/var/www/certbot
     - /home/ubuntu/certbot/logs:/var/log/letsencrypt
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

networks:
  my-network:
    name: my-network

volumes:
  my-nginx-conf:
    external: true

 

  • nginx.ports - LetsEncrypt가 접근할 HTTP포트와 ssl 인증서가 적용되면 접근할 HTTPS 포트를 미리 포워딩해준다.
  • nginx.volumes - 이전에 작성했던 nginx 구성파일이 있는 볼륨을 마운트 해주고, (볼륨 없이 진행 시 80포트 설정 해준 파일 의 디렉토리를 적어주면 됨) nginx와 certbot의 인증서가 생성될 디렉토리를 공유해준다. -> https 접근 시 nginx에서 사용
  • nginx.command - nginx를 6시간에 한 번씩 reload 자동 실행
  • certbot.volumes - 마찬가지로 nginx와 공유할 인증서가 생성될 디렉토리, 혹시 모를 에러 로그가 작성될 로그 디렉토리를 볼륨 마운트 한다.
  • certbot.entrypoint - 12시간에 한 번씩 인증서 갱신 시도

 
 

 
 

인증서를 발급할 스크립트 파일 작성

인증서를 발급하기 위한 순서는 다음과 같다.

  1. 더미 인증서 발급 -> nginx를 구동하려면 nginx의 443 server block 에서 인증서를 필요로 하기 때문에
  2. nginx continaer 실행
  3. 더미 인증서 삭제
  4. LetsEncrypt로 인증서 요청
  5. 완료 시 nginx reload

위의 발급 과정은 스크립트 파일로 작성하여 실행 (letsencrypt.sh)
 

#!/bin/bash

if ! [ -x "$(command -v docker-compose)" ]; then
  echo 'Error: docker-compose is not installed.' >&2
  exit 1
fi

domains="domain.com" # 자신의 도메인
rsa_key_size=4096
data_path="/home/ubuntu/certbot" # host에 마운트된 certbot 디렉토리
email="email@gmail.com" # 업데이트 등 정보 수신 메일 입력 (권장?)
staging=0 # 시간당 5번의 요청 제한으로 1로 설정 시 테스트 진행(요청 카운팅 안 됨)

if [ -d "$data_path" ]; then
  read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
  if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
    exit
  fi
fi

if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
  echo "### Downloading recommended TLS parameters ..."
  mkdir -p "$data_path/conf"
  curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
  curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
  echo
fi

echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
docker-compose run --rm --entrypoint "\
  openssl req -x509 -nodes -newkey rsa:1024 -days 1\
    -keyout '$path/privkey.pem' \
    -out '$path/fullchain.pem' \
    -subj '/CN=localhost'" certbot
echo

echo "### Starting nginx ..."
docker-compose up --force-recreate -d nginx
echo

echo "### Deleting dummy certificate for $domains ..."
docker-compose run --rm --entrypoint "\
  rm -Rf /etc/letsencrypt/live/$domains && \
  rm -Rf /etc/letsencrypt/archive/$domains && \
  rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo

echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[@]}"; do
  domain_args="$domain_args -d $domain"
done

# Select appropriate email arg
case "$email" in
  "") email_arg="--register-unsafely-without-email" ;;
  *) email_arg="--email $email" ;;
esac

# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi

docker-compose run --rm --entrypoint "\
  certbot certonly --webroot -w /var/www/certbot \
    $staging_arg \
    $email_arg \
    $domain_args \
    --rsa-key-size $rsa_key_size \
    --agree-tos \
    --force-renewal" certbot
echo

echo "### Reloading nginx ..."
docker-compose exec nginx nginx -s reload

 
설명은 주석으로 대신함.
 
해당 스크립트 파일은 전에 생성한 docker compose 파일과 같은 폴더에 넣고 실행해야한다.

  • 스크립트 파일의 docker-compose명령어는 같은 폴더의 docker-compose.yml파일을 인식하도록 작성된다., 다른 이름 다른 디렉토리에 작성 시 -f [파일 위치] 명령어를 추가로 작성해줘야한다.

 

./letsencrypt.sh

 
Successfully received certificate. <- 로그가 출력되면 발급 성공.
 

ls -al /home/ubuntu/certbot/conf/live/도메인 이름/

인증서 파일 확인

 
 

HTTPS 요청 테스트

 

https://도메인 이름

 
요청시 default.conf 파일에 설정해놓은 데로 nginx의 기본 index파일이 응답 되었고,
HTTP 요청시에도 리다이렉트 80포트 요청에 redirect location direct를 작성해서 HTTPS가 요청되는것을 확인할 수 있다.