웹 페이지의 보안을 위해 Https는 필수적으로 사용되고 있습니다. Https를 사용하기 위해서는 SSL 인증서가 필요합니다.
이번 글에서는 무료 SSL 발급 인증 기관인 Let's Encrypt에서 제공하는 Certbot Docker image를 이용하여 SSL 인증서를 발급 받는 방법을 알아보겠습니다.
본 글에서는 Docker의 설치와 사용법에 대해 다루지 않습니다. 기본적인 Docker 사용법을 숙지하시기 바랍니다. 또한 서버 인증에 필요한 도메인도 미리 준비하시길 바랍니다.
Let's Encrypt를 이용하여 SSL 인증서를 발급받는 방법에는 크게 3가지 방법이 있습니다.
이번 글에서는 Webroot 방식을 이용하여 SSL 인증서를 발급받는 방법에 대해 알아보겠습니다.
Webroot 방식은 서버의 root 디렉토리에 Let's Encrypt에서 발급한 임의의 값을 넣어두고, 외부에서 해당 서버에 접근했을때 웹 서버의 root 디렉토리에 임의의 값이 있는지 확인하여 서버 인증을 받는 방식입니다. Webroot 방식을 사용하면 현재 운영중인 서버에서도 인증과 갱신이 가능하다는 장점이 있습니다.
하지만 Webroot 방식은 와일드카드 도메인 인증이 불가능 합니다. 와일드카드 도메인은 *.domain.com과 같이 sub 도메인을 포함한 모든 도메인을 의미합니다. 와일드카드 인증을 받으면 모든 sub 도메인에서도 Https 설정이 가능하지만, 해당 기능은 DNS 방식만 지원합니다.
Let's Encrypt로 부터 실제로 운영하고 있는 서버라는 사실을 인정받기 위해 외부에서 접근할 수 있는 서버를 실행시켜야 합니다.
Nginx를 통해 외부에서 서버에 접근할 수 있도록 Nginx를 설정 파일을 작성해주겠습니다.
SSL 인증서를 받기위해 임의의 디렉토리를 미리 생성한 후, 해당 디렉토리에서 실행하였습니다. 각자 상황에 맞게 디렉토리를 지정하기 바랍니다.
또한 Let's Encrypt 인증은 80 포트와 443 포트만 가능합니다.
server {
listen [::]:80;
listen 80;
server_name domain.com www.domain.com;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/certbot;
}
}
Nginx의 설정 파일을 모두 작성했으면, 작업 디렉토리/conf.d/default.conf로 저장합니다.
이미 사용중인 Nginx 파일이 있다면 '/.well-known/acme-challenge' 해당 경로에 대한 설정만 추가도 무방합니다.
Nginx와 Certbot docker를 실행시킬 docker-compose.yml 파일을 작성해줍니다.
version: "3.8"
services:
web:
image: nginx:latest
restart: always
volumes:
- work dir/conf.d:/etc/nginx/conf.d
- work dir/certbot/conf:/etc/nginx/ssl
- work dir/certbot/data:/var/www/certbot
ports:
- 80:80
- 443:443
certbot:
image: certbot/certbot:latest
command: certonly --webroot --webroot-path=/var/www/certbot --email myemail@google.com --agree-tos --no-eff-email -d domain.com
volumes:
- work dir/certbot/conf:/etc/letsencrypt
- work dir/certbot/logs:/var/log/letsencrypt
- work dir/certbot/data:/var/www/certbot
Docker volume을 유의하여 docker-compose.yml 파일을 작성합니다. Certbot command에 있는 --webroot-path와 nginx의 volume의 경로에 유의하시길 바랍니다.
command에 대해 자세히 알아보겠습니다
docker-compose.yml 파일을 모두 작성했으면 docker-compose를 실행시켜 SSL 인증서를 발급받습니다.
docker-compose up -d
위 커맨드를 실행하여 인증을 시도합니다.
Creating network "nginx-ssl_default" with the default driver
Pulling web (nginx:latest)…
latest: Pulling from library/nginx
8559a31e96f4: Pull complete
8d69e59170f7: Pull complete
3f9f1ec1d262: Pull complete
d1f5ff4f210d: Pull complete
1e22bfa8652e: Pull complete
Digest: sha256:21f32f6c08406306d822a0e6e8b7dc81f53f336570e852e25fbe1e3e3d0d0133
Status: Downloaded newer image for nginx:latest
Pulling certbot (certbot/certbot:latest)…
latest: Pulling from certbot/certbot
cbdbe7a5bc2a: Pull complete
26ebcd19a4e3: Pull complete
a29d43ca1bb4: Pull complete
979dbbcf63e0: Pull complete
30beed04940c: Pull complete
48a1f8a4d505: Pull complete
4416e9b4bbe0: Pull complete
8173b4be7870: Pull complete
21c8dd124dab: Pull complete
c19b04e11dc7: Pull complete
1b560611cec1: Pull complete
Digest: sha256:568b8ebd95641a365a433da4437460e69fb279f6c9a159321988d413c6cde0ba
Status: Downloaded newer image for certbot/certbot:latest
Creating nginx-ssl_certbot_1 … done
Creating nginx-ssl_web_1 … done
위와 같이 Nginx와 Cerbot docker image를 pull 받고 컨테이너를 실행합니다.
인증에 성공했는지 확인해봅시다.
docker-compose ps
docker-compose의 상태를 확인해서 아래와 같이 Certbot의 상태고 Exit 0으로 표시된다면 정상적으로 발급된 상태입니다!
Name Command State Ports
certbot certbot certonly --webroot … Exit 0
web /docker-entrypoint.sh ngin … Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
만일 Certbot의 상태가 Exit 0이 아니라면 docker-comopse.yml과 log를 확인합니다.
log는 아래 커맨드로 확인 가능합니다.
docker-compose logs -f
인증에 성공하였으면 certbot/conf 경로 아래 SSL 키가 생성된것을 알 수 있습니다.
해당 키값을 실제 실행 시키는 웹 서버의 설정 파일에 적용합니다.
Nginx는 아래와 같이 SSL 인증서 파일을 설정해줍니다.
.
.
.
http {
server {
listen 443 ssl;
server_name domain.com;
ssl_certificate /etc/letsencrypt/archive/domain.com/fullchain1.pem;
ssl_certificate_key /etc/letsencrypt/archive/domain.com/privkey1.pem;
.
.
.
각자 상황에 맞게 인증서 위치를 설정해줍니다.
Let's Encrypt에서 제공하는 인증서의 유효 기간은 90일 입니다. 따라서 90일 마다 인증서를 갱신해주어야 합니다.
인증서는 만료 기간이 30일 이내일때 재발급 가능하며 --force-renewal 옵션을 통해 강제 재발급이 가능하지만, 인증서 발급 제한사항에 위배될 가능성이 있어 추천드리지 않습니다.
인증서 발급에 유의할 제약사항에 대해 자세한 내용을 알고싶다면 아래 글을 참조하시길 바랍니다.
https://findstar.pe.kr/2018/09/08/lets-encrypt-certificates-rate-limit/
인증서 재발급을 위한 Certbot docker 커맨드는 아래와 같습니다.
docker run --rm --name certbot -v '/etc/letsencrypt:/etc/letsencrypt' -v '/var/log/letsencrypt:/var/log/letsencrypt' -v '/etc/letsencrypt/data:/var/www/certbot' certbot/certbot renew --server https://acme-v02.api.letsencrypt.org/directory --cert-name domain.com
Docker volume은 자신의 환경에 맞게 적절히 설정해주시길 바랍니다.
위 커맨드를 실행 한 후 아래 커맨드로 남은 인증서 만료일을 확인하여 정상적으로 갱신되었는지 확인합니다.
docker run -it --rm --name certbot -v '/etc/letsencrypt:/etc/letsencrypt' -v '/var/log/letsencrypt:/var/log/letsencrypt' -v '/etc/letsencrypt/data:/var/www/certbot' certbot/certbot certificates
여기까지 Let's Ecrypt와 docker를 이용한 SSL 인증서 발급받는 방법에 대해 알아보았습니다. 인증서를 자동으로 갱신하기 위해 Crontab 등을 활용할 수 있습니다. Crontab을 위한 자동 갱신 코드 첨부합니다. 이 또한 각자의 환경과 상황에 맞게 사용하시길 바랍니다.
#!/bin/bash
docker run --rm --name certbot -v '/etc/letsencrypt:/etc/letsencrypt' -v '/var/log/letsencrypt:/var/log/letsencrypt' -v '/etc/letsencrypt/data:/var/www/certbot' certbot/certbot renew --server https://acme-v02.api.letsencrypt.org/directory --cert-name domain.com
위 커맨드를 .sh 파일로 저장한 후 chmod 400등으로 실행 권한을 부여합니다.
이후 crontab -e에 갱신 시케줄을 등록합니다. 저는 매일 새벽 4시에 실행하도록 설정하였습니다.
* 4 * * * /mydir/certbot-renew.sh
자신의 환경에 맞게 /etc/crontab에 실행 환경변수를 설정해줍니다.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
감사합니다.