본문 바로가기

Nginx

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

반응형

 
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가 요청되는것을 확인할 수 있다.

반응형