Let’s Encrypt 기존에는 도메인 업체에서 1년치의 SSL을 사서 넣곤 했다. 그러나 Let’s Encrypt 를 통해 SSL을 적용하면 무료로 인증서를 발급하고 HTTPS 환경을 구축할 수 있다. 하지만 단점도 존재하는데, 일반적인 방법으로 발급 시 90일동안만 유효하고, 다시 발급해야하는 번거로움이 있다. 90일 후의 연장을 알아서 하게끔 도와주는 docker 셋업 파일을 깃허브에서 찾았고, 작업 중인 프로젝트에 적용해보려 한다.
도메인 설정 당연히 도메인이 필요하다. 나는 네임칩 을 이용하고 있다. 프론트엔드의 IP를 도메인에 걸어줘야 하는데, A Record나 AAAA Record 둘 중의 하나로 적용해야 인증서를 발급할 수 있다.
이제 도메인에 대한 설정은 끝났다.
Docker-compose 수정 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 version: '3.1' networks: app-tier: driver: bridge services: nginx: networks: - app-tier build: context: ./frontend dockerfile: ./Dockerfile container_name: kiwi-frontend volumes: - /app/node_modules - ./frontend:/app - ../certbot/conf:/etc/letsencrypt - ../certbot/www:/var/www/certbot restart: always ports: - '80:80' - '443:443' expose: - '80' - '443' 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 volumes: - ../certbot/conf:/etc/letsencrypt - ../certbot/www:/var/www/certbot entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
Docker-compose 파일을 수정하는데, 위와 같이 nginx service에 certbot에 대한 볼륨 2개를 추가해주고, certbot 서비스 전체를 추가해주면 된다.
nginx.conf 작성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 worker_processes auto; events { worker_connections 1024; } http { include mime.types; sendfile on; server { listen 80; server_name YOUR_DOMAIN_ADDRESS; server_tokens off; location / { return 301 https://$host$request_uri; } location /.well-known/acme-challenge/ { root /var/www/certbot; } } server { listen 443 ssl; server_name YOUR_DOMAIN_ADDRESS; server_tokens off; location /api { # 이 부분은 api라는 uri로 통신 시 백엔드에 프록시 처리를 하기 위함 proxy_pass http://app:4000; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; } location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN_ADDRESS/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN_ADDRESS/privkey.pem; } include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; }
nginx.conf
파일을 만드는데, 기존 80 포트로 들어오는 요청을 443 포트로 리다이렉션 시켜준다. 443 포트는 SSL에 대한 정보를 같이 작성한다. YOUR_DOMAIN_ADDRESS
부분을 본인의 도메인으로 바꿔준다. api
에 대한 부분은, 프론트/백엔드를 분리하여 프론트 요청을 백엔드로 프록시하기 위함인데, SSL과는 상관이 없다.
쉘 스크립트 추가 이 쉘 스크립트는 깃허브 nginx-certbot 에서 찾았다. 귀찮은 SSL 세팅 작업을 수고스럽게 해주셨다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #!/bin/bash if ! [ -x "$(command -v docker-compose) " ]; then echo 'Error: docker-compose is not installed.' >&2 exit 1 fi domains="도메인 주소" rsa_key_size=4096 data_path="../certbot" email="이메일 주소" staging=0 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:$rsa_key_size -days 1\ -keyout '$path /privkey.pem' \ -out '$path /fullchain.pem' \ -subj '/CN=localhost'" certbotecho 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" certbotecho echo "### Requesting Let's Encrypt certificate for $domains ..." domain_args="" for domain in "${domains[@]} " ; do domain_args="$domain_args -d $domain " done case "$email " in "" ) email_arg="--register-unsafely-without-email" ;; *) email_arg="--email $email " ;; esac 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" certbotecho echo "### Reloading nginx ..." docker-compose exec nginx nginx -s reload
쉘 스크립트를 init-letsencrypt.sh
파일로 docker-compose.yaml
파일이 있는 경로에 함께 저장한다.
빌드하기 이제 Docker-compose를 통해 도커 이미지 빌드 후 배포하는데, docker-compose up
이 아닌 위에서 작성한 쉘 스크립트를 실행한다.
1 2 chmod +x init-letsencrypt.sh ./init-letsencrypt.sh
주의할 점은, 빌드를 반복하면 Let’s Encrypt에서는 Request Limits를 걸고 있는데, 일정 요청을 초과하면 당분간 해당 도메인 주소에 SSL을 발급하지 못하게 된다. 따라서 테스트 빌드시에는 쉘 스크립트의 staging = 0
부분을 1
로 변경 후 배포를 테스트하자.
한번 배포하면 SSL에 대해 귀찮을 일이 없는 HTTPS 환경이 만들어졌다.