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

# 자동화는 모든 개발자의 꿈

내가 이전에 작성한 [Let's Encrypt 와일드카드 인증서 발급받기](https://seongmin.dev/docker-lets-encrypt) 마지막에 인증서를 갱신하는 법이 나온다.

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

# 자동화 스크립트 작성하기

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

```plaintext
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
```

[전에 작성한 글](https://seongmin.dev/docker-lets-encrypt)에서 살짝 바뀐 것이 있다.

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

[공식 문서](https://certbot-dns-cloudflare.readthedocs.io/en/stable/#id3)에서 확인할 수 있듯이 위 옵션은 DNS 전파를 기다리는 시간을 기본 10초에서 원하는 시간으로 늘릴 수 있는 옵션이다.

```plaintext
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이다. 설치하는데에 있어 큰 노력이 필요없고 설정 방법도 매우 간단한 축에 속하기 때문에 이 글의 목적에 적합한 도구이다.

```plaintext
# 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](https://crontab.guru/)에 접속해서 직접 입력하면서 맞추면 된다.  
또한 crontab의 timezone은 서버의 timzone과 같기 때문에 이에 유의해서 시간을 설정해야 한다.

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

# 로그 남기기

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

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

```plaintext
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 컨테이너 시작
    

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