[YSM의 서버 세팅] - Ssl 갱신 자동화

crontab을 이용해 SSL 갱신을 자동화 해봅니다

[YSM의 서버 세팅] - Ssl 갱신 자동화

Photo by Tim Stief on Unsplash

자동화는 모든 개발자의 꿈

내가 이전에 작성한 Let's Encrypt 와일드카드 인증서 발급받기 마지막에 인증서를 갱신하는 법이 나온다.

따라서 "Let's Encrypt certificate expiration notice" 라고 시작하는 메일이 오면 그때 수동으로 갱신해도 되지만 자동화는 멋지고 아름다운 것이기에 자동화를 적용해보자.

자동화 스크립트 작성하기

새로운 옵션, --dns-cloudflare-propagation-seconds

docker run --rm --name certbot \
    -e TZ=UTC \
    -v ~/docker/volume/certbot/seongmin.dev/etc:/etc/letsencrypt \
    -v ~/docker/volume/certbot/seongmin.dev/var:/var/lib/letsencrypt \
    -v ~/.secrets/certbot/cloudflare.ini:/cloudflare.ini \
    certbot/dns-cloudflare:arm64v8-latest \
    renew --dns-cloudflare-propagation-seconds 60

전에 작성한 글에서 살짝 바뀐 것이 있다.

바로 --dns-cloudflare-propagation-seconds 옵션이다.

공식 문서에서 확인할 수 있듯이 위 옵션은 DNS 전파를 기다리는 시간을 기본 10초에서 원하는 시간으로 늘릴 수 있는 옵션이다.

Certbot failed to authenticate some domains (authenticator: dns-cloudflare). The Certificate Authority reported these problems:
  Domain: seongmin.dev
  Type:   unauthorized
  Detail: Incorrect TXT record "GSHbfjsmHEIYhu9elbhC29XC5Z45euWwrBwTDUPwbF0" found at _acme-challenge.seongmin.dev

Hint: The Certificate Authority failed to verify the DNS TXT records created by --dns-cloudflare. Ensure the above domains are hosted by this DNS provider, or try increasing --dns-cloudflare-propagation-seconds (currently 10 seconds).

위 로그는 실제로 필자가 운영하는 서버에서 발생한 로그로 Cloudflare API로 _acme-challenge 레코드를 추가했지만 DNS 전파 시간때문에 확인에 실패해 최종적으로 갱신에 실패한 것을 확인할 수 있다.

수동으로 갱신을 진행하면 바로 한번 더 실행하는 방식으로 해결하겠지만 이 글의 목표는 자동화기 때문에 DNS 전파를 기다리는 시간을 늘려 이 문제를 회피할 것이다.

Cloudflare의 DNS 전파 시간은 짧은 편이기에 60초면 대부분의 경우에 성공할 것이다

주기적으로 명령어를 실행하는 crontab

리눅스에서 주기적으로 명령어를 실행하는 방법중 가장 보편적인 방법은 crontab이다. 설치하는데에 있어 큰 노력이 필요없고 설정 방법도 매우 간단한 축에 속하기 때문에 이 글의 목적에 적합한 도구이다.

# crontab -e

SHELL=/bin/bash

# m h  dom mon dow   command
# UTC+9 매월 1일 오전 3시 SSL 갱신
0 18 1 * * bash /home/ubuntu/renew-ssl.sh

crontab -e 를 통해 crontab 설정 파일을 열 수 있다.

실행할 시간(0 18 1 * *)과 실행할 명령어(bash /home/ubuntu/renew-ssl.sh)를 적고 저장하면 지정한 시간에 실행될 것이다.

실행할 시간을 적는 것이 어렵다면 crontab guru에 접속해서 직접 입력하면서 맞추면 된다.
또한 crontab의 timezone은 서버의 timzone과 같기 때문에 이에 유의해서 시간을 설정해야 한다.

서버의 timezone은 date 명령어를 통해 확인할 수 있다

로그 남기기

crontab은 따로 로그를 남기지 않기 때문에 정상적으로 잘 실행된건지 추후에 확인하는 것이 제한된다.

따라서 주기적으로 실행할 파일에 로그를 남기고 갱신을 하는 내용을 담는 것이 좋다.

echo "Renewing SSL - $(date)" >> /home/ubuntu/log/crontab-certbot.log
docker stop nginx-proxy
bash /home/ubuntu/docker/sh/certbot-renew.sh >> /home/ubuntu/log/crontab-certbot.log
echo "##################################################################################" >> /home/ubuntu/log/crontab-certbot.log

sudo cp -f /home/ubuntu/docker/volume/certbot/seongmin.dev/etc/live/seongmin.dev/cert.pem /home/ubuntu/docker/volume/nginx-proxy/cert/seongmin.dev.crt
sudo cp -f /home/ubuntu/docker/volume/certbot/seongmin.dev/etc/live/seongmin.dev/privkey.pem /home/ubuntu/docker/volume/nginx-proxy/cert/seongmin.dev.key

docker start nginx-proxy
  • 갱신하는 시간을 log 파일에 기록

  • nginx-proxy 컨테이너 멈추기

  • 갱신 Docker 스크립트(자동화 스크립트 작성하기에서 작성한 것) 실행하고 stdout은 log 파일에 기록

  • #으로 구분

  • 새로운 인증서들을 nginx-proxy에 적용

  • nginx-proxy 컨테이너 시작

위 스크립트는 예시이며 본인의 환경에 맞춰 적절히 수정하면 된다.