[HTTPS,Nginx,Docker] Let's Encrypt를 사용해, Docker 기반으로 HTTPS 설정하기 2

2023. 6. 6. 20:59프로젝트 로그/테스트x솔루션 JIG 개발기

반응형

 Docker  환경을 위한 디렉터리 Tree

D:.
|   .env.prod
|   init-letsencrypt.sh
|   01_start_1st_install.sh
|   02_update.sh
|   03_pull_repository.sh
|   docker-compose.for1stInstall.yml
|   docker-compose.prod.yml
|   README.md
|   tree.txt
|   
+---data
|       README.txt
|       
+---django
|       .gitignore
|       Dockerfile.prod
|       entrypoint.prod.sh
|       LICENSE
|       manage.py
|       README.md
|       requirements.txt
|       
+---nginx
|       Dockerfile.prod
|       Dockerfile_for1stInstall.prod
|       nginx.conf
|       nginx_for1stInstall.conf
|       
+---postgresql
|       Dockerfile.prod
|       entrypoint.prod.sh
|       
\---redis
        Dockerfile.prod

 

nginx 설정

nginx/Dockerfile_for1stInstall.prod

FROM nginx:1.19.0-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx_for1stInstall.conf /etc/nginx/conf.d/

nginx/nginx_for1stInstall.conf

upstream web {
    ip_hash;
    server web:8000;
}

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

    location / {
        proxy_pass http://web/;
        client_max_body_size 100M;
    }

    # static 관련 추가된 부분
    location /static/ {
        alias /home/app/web/static/;
    }

    location /media/ {
        alias /home/app/web/media/;
    }

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

 

Let's Encrypt init_script

docker-compose.for1stInstall.yml

초기 Let's Encrypt에서 인증서를 받아 올 때 사용하기 위한 Docker Image를 위한 스크립트이다.

해당 스크립트의 주 동작은 nginx와 certbot 서비스를 동작 시키기 위해 사용되며, 아래 init_script에서 해당 파일을 이용하여 Docker 컨테이너들을 생성하고 실행 한다.

version: '3.7'

services:
  nginx:
    restart: always
    build:
      context: ./nginx
      network: host
      dockerfile: Dockerfile_for1stInstall.prod

    volumes:
      - static_volume:/home/app/web/static
      - media_volume:/home/app/web/media
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
 
    ports:
      - 80:80
      - 443:443

    depends_on:
      - web

    command : "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
  
  certbot:
      image: certbot/certbot
      container_name: certbot_service
      restart: always
      volumes:
        - ./data/certbot/conf:/etc/letsencrypt
        - ./data/certbot/www:/var/www/certbot
      depends_on:
        - nginx

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


  web:
    build:
      context: ./django
      network: host
      dockerfile: Dockerfile.prod

    command: gunicorn config.wsgi:application --bind 0:8000
    volumes:
      - static_volume:/home/app/web/static
      - media_volume:/home/app/web/media
    # ports:
    #   - 8000:8000
    expose:
      - "8000"
    env_file:
      - ./.env.prod
    depends_on:
      - db

  db:
    build:
      context: ./postgresql
      network: host
      dockerfile: Dockerfile.prod

    ports:
      - 5432:5432
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    env_file:
      - ./.env.prod
    
  redis:
    build:
      context: ./redis
      network: host
      dockerfile: Dockerfile.prod

    ports:
      - 6379:6379

  rabbitmq:
    container_name: rabbitmq_service
    image: rabbitmq:3.7.14-management-alpine

    env_file:
      - ./.env.prod

    ports:
      - "5672:5672"   # RabbitMQ Default Port
      - "15672:15672" # UI Web을 위한 Port
    
volumes:
  postgres_data:
  static_volume:
  media_volume:

init_script 내용 수정

아래 파일 내용에서 {YOUR DOMAIN}, {YOUR E-MAIL}, Docker-Compose 실행 명령만 변경함.

#!/bin/bash

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

domains="{YOUR DOMAIN}"
rsa_key_size=4096
data_path="./data/certbot"
email="{YOUR E-MAIL}" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits

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 명령 수행
sudo docker-compose -f docker-compose.for1stInstall.yml run --rm --entrypoint "\
  openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\
    -keyout '$path/privkey.pem' \
    -out '$path/fullchain.pem' \
    -subj '/CN=localhost'" certbot
echo


echo "### Starting nginx ..."
# Nginx 실행을 위한 Docker 명령 수행
sudo docker-compose -f docker-compose.for1stInstall.yml up --force-recreate -d nginx
echo

echo "### Deleting dummy certificate for $domains ..."
# 임시 인증서 삭제를 위한 Docker 명령 수행
sudo docker-compose -f docker-compose.for1stInstall.yml 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

# 
sudo docker-compose -f docker-compose.for1stInstall.yml run --rm --entrypoint "\
  certbot certonly -a webroot -v --debug-challenges -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 ..."
sudo docker-compose -f docker-compose.for1stInstall.yml exec nginx nginx -s reload

init_script.sh 수행 결과

Existing data found for testx.twarelab.com. Continue and replace existing certificate? (y/N) y
### Downloading recommended TLS parameters ...

### Creating dummy certificate for testx.twarelab.com ...
Creating django_testx_certbot_run ... done
Generating a RSA private key
.......................................................................................................................................................................................................................................
........................................................................++++
.....................................................................................................................................................................................................++++
writing new private key to '/etc/letsencrypt/live/testx.twarelab.com/privkey.pem'
-----

### Starting nginx ...
Recreating django_testx_db_1 ... done
Recreating django_testx_web_1 ... done
Recreating django_testx_nginx_1 ... done

### Deleting dummy certificate for {Your URL} ...
Creating django_testx_certbot_run ... done

### Requesting Let's Encrypt certificate for {Your URL} ...
Creating django_testx_certbot_run ... done
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Account registered.
Requesting a certificate for {Your URL}
Performing the following challenges:
http-01 challenge for {Your URL}
Using the webroot path /var/www/certbot for all unmatched domains.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Challenges loaded. Press continue to submit to CA.

The following URLs should be accessible from the internet and return the value
mentioned:

URL:
http://{Your URL}/.well-known/acme-challenge/~~~~~o~~~
Expected value:
xxxxxxxzzxxxxxxxxxxxxxxxxxxxxx
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Waiting for verification...
Cleaning up challenges

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/{Your URL}/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/{Your URL}/privkey.pem
This certificate expires on 2022-08-21.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for 
instructions.
Subscribe to the EFF mailing list (email: ).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

### Reloading nginx ...
2022/05/23 06:42:00 [notice] 10#10: signal process started

 

data/certbot/conf/live/{Your URL} 디렉터리에 아래와 같은 파일들이 생성 된다. 

  • privkey.pem : 인증서의 개인키
  • fullchain.pem :  범용적으로 서버 소프트웨어에서 사용되는 인증서 체인
  • chain.pem : OCSP stapling을 위한 인증서
  • cert.pem : 
README  cert.pem  chain.pem  fullchain.pem  privkey.pem

 

 

참고 자료

 

반응형