몇년 전에 Lets’ Encrypt SSL 와일드카드 인증서 발급/갱신과 관련된 글을 작성했는데요.
Lets’ Encrypt SSL 와일드카드 인증서 발급/갱신
설치/설정 과정이 번거롭기도 하고 스케줄러로 동작시킬 때 제대로 인증서를 갱신하지 못하는 문제도 있고해서 도커 컨테이너로 만들어봤습니다.
지인과 함께 테스트해보니 잘 동작되어서 도커 헙에도 배포하였습니다.
https://hub.docker.com/r/isul/letsencrypt-aws-lightsail
이 컨테이너를 사용하기 위해서는 DNS 서비스로 AWS Lightsail을 사용해야 됩니다.
컨테이너를 실행하면 모든 것이 자동으로 완료됩니다.
1. 준비사항
- 인증서를 발급 받고자 하는 도메인
- AWS(Amazon Web Services) 계정 – 결제 신용카드 등록까지 필요
2. 이용 서비스
- Lets’ Encryt
- AWS Lightsail – DNS 서비스(3개 도메인까지 무료, 월 3백만 쿼리까지 무료)
3. Amazon Lightsail 설정 및 네임서버 변경
DNS 서비스를 이용하기 위해서 Amazon Lightsail 사이트에 접속합니다. 먼저 아마존 웹서비스(AWS)에 가입되어 있어야 됩니다.
https://lightsail.aws.amazon.com/ls/webapp/home/networking
위 사이트에 접속하여 “DNS 영역 생성” 버튼을 눌러 도메인을 입력하고 진행합니다.
그리고, 기존에 사용하던 DNS 레코드를 그대로 모두 입력합니다. DNS 서비스를 이전하기 전에 미리 설정해두는 것이 좋습니다.
DNS 레코드를 모두 설정한 후 화면 제일 아래에 표시되는 “이름 서버”를 자신이 도메인을 등록한 업체의 웹사이트에 접속해서 네임서버의 정보에 모두 입력합니다.
네임서버 정보가 변경되기까지 서비스 업체별로 시간이 조금 다릅니다. DNS 레코드에 새로운 서브도메인을 하나 추가해두고 ping 테스트를 해보면 변경되었는지 쉽게 확인할 수 있습니다.
4. AWS 액세스키 발급 및 설정
인증서 발급 과정 중에 Lets’ Encrypt에서 자신의 도메인이 맞는지 확인하는 과정이 있습니다. 이를 위해 해당 도메인에 Lets’ Encrypt에서 알려주는 값으로 TXT 레코드를 등록해야 되는데요. 이 컨테이너에서는 이를 자동으로 처리합니다. 이를 위해서 컨테이너 내부에 설치된 awscli가 AWS Lightsail에 접근할 수 있도록 액세스 키를 생성해야 됩니다. 아래 URL에 접속하여
https://lightsail.aws.amazon.com/ls/webapp/account/advanced
고급 – IAM 콘솔로 이동 – 보안 자격 증명으로 계속 – 액세스 키(액세스 키 ID 및 보안 액세스 키) – 새 액세스 키 만들기를 해서 생성합니다. 이렇게 생성된 키는 다음 단계에서 사용됩니다.
5. 인증서 발급
아래 도커 명령으로 인증서를 발급받습니다. 아래 명령은 샘플로 각종 파라미터를 자신의 환경에 맞게 변경해야 됩니다.
1 2 3 4 5 6 7 |
docker run -it --rm --name lightsail \ -v /volume1/letsencrypt:/usr/local/dehydrated/certs \ isul/letsencrypt-aws-lightsail:v1.2 \ /usr/local/dehydrated/lightsail domain=yourdomain.com email=you@yourdomain.com attempts=10 sleep_time=30 \ aws_region=us-east-1 aws_access_key_id=your_access_key_id aws_secret_access_key=your_secret_access_key |
/volume1/letsencrypt:인증서 파일이 저장될 경로입니다. 도커 host에 존재하는 경로입니다. 이 폴더 하위에 도메인명으로 폴더가 생성되고, 그 안에 인증서 파일이 생성됩니다.
domain: 자신의 도메인을 입력합니다.
email: 이메일 주소를 입력합니다. 인증서 만료가 다가오면 이 이메일로 알려줍니다.
attempts: 인증서 발급 과정 중 Lets’ Encrypt에서 알려주는 값으로 TXT 레코드를 설정하는데요. 이때 해당 값이 제대로 설정되었는지 검사하는 횟수를 설정합니다. 짧게 설정하면 발급에 실패할 수도 있습니다. 기본값은 3으로 생략할 경우 3번까지 검사합니다.
sleep_time: TXT 레코드 설정 후 그 값을 조회할 때 기다리는 시간을 설정합니다. DNS 캐시로 인하여 “ERROR: Challenge is invalid!” 에러가 발생할 경우 시간을 늘려줍니다. 기본 값은 30초입니다. 크게 설정할수록 안정적으로 동작됩니다.
aws_region: AWS Region으로 “us-east-1”로 설정해야 됩니다.
aws_access_key_id: 4번 과정에서 생성한 access key를 입력합니다.
aws_secret_access_key: 4번 과정에서 생성한 access key에 대한 secret key를 입력합니다.
* 도커 이미지 버전은 업데이트될 수도 있으니 아래 링크에 접속하여 최신 버전을 확인하기 바랍니다.
https://hub.docker.com/r/isul/letsencrypt-aws-lightsail
위 도커 명령을 실행하면 아래와 같이 인증서 발급이 시작되고
완료되면 아래와 같이 인증서 파일이 생성된 것을 볼 수 있습니다.
* 이 컨테이너는 –rm 옵션 사용으로 인증서 발급 완료 후 자동으로 삭제됩니다.
이제 생성된 인증서를 자신의 웹 서버에 적용하면 됩니다.
6. 샘플 스크립트
참고로 저는 아래처럼 스크립트로 만들어서 한 달에 한 번 호출되도록 스케줄러에 등록하여 사용 중입니다. 한 달 후에 자동 갱신까지 문제없이 완료되어야 최종 성공입니다. 성공 여부는 그때 업데이트하겠습니다.
시작, 종료 시에 텔레그램으로 알림 메시지를 보내고, 인증서 발급 후 프록시 프로그램인 haproxy를 재시작하여 인증서가 적용되게 처리하였습니다.
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 |
#!/bin/sh DOMAIN=damoatour.com EMAIL=isul@isulnara.com ATTEMPTS=20 SLEEP=90 AWS_REGION=us-east-1 AWS_ACCESS_KEY_ID=AJIAJO AWS_SECRET_ACCESS_KEY=Vd2csm1keXdx CERTS_PATH=/volume1/letsencrypt REGISTRY=isul/letsencrypt-aws-lightsail:v1.2 CHAT_ID="1122334455" TOKEN="529199170:FADnbfDci1ZP_z-yYTRHW13Q22htu7ZBTz0" msg="Let's Encrypt SSL certificate($DOMAIN) updates -> start" curl -s -F chat_id=$CHAT_ID -F text="$msg" https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null docker run -it --rm --name lightsail \ -v $CERTS_PATH:/usr/local/dehydrated/certs \ $REGISTRY \ /usr/local/dehydrated/lightsail domain=$DOMAIN email=$EMAIL attempts=$ATTEMPTS sleep_time=$SLEEP \ aws_region=$AWS_REGION aws_access_key_id=$AWS_ACCESS_KEY_ID aws_secret_access_key=$AWS_SECRET_ACCESS_KEY if [ -f "$CERTS_PATH/$DOMAIN/fullchain.pem" ]; then cat $CERTS_PATH/$DOMAIN/fullchain.pem $CERTS_PATH/$DOMAIN/privkey.pem > $CERTS_PATH/$DOMAIN/$DOMAIN.pem killall haproxy<br /> /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/var/haproxy.cfg -p /usr/local/haproxy/var/haproxy.pid msg="Let's Encrypt SSL certificate($DOMAIN) updates -> success" curl -s -F chat_id=$CHAT_ID -F text="$msg" https://api.telegram.org/bot$TOKEN/sendMessage else msg="Let's Encrypt SSL certificate($DOMAIN) updates -> fail" curl -s -F chat_id=$CHAT_ID -F text="$msg" https://api.telegram.org/bot$TOKEN/sendMessage fi |
*2020-08-06: DNS 캐시로 인하여 “ERROR: Challenge is invalid!” 에러가 발생하는 경우가 있어서 sleep_time 파라미터를 추가하고, 도커 이미지 버전을 1.2로 업데이트하였습니다.
오 이건 정말 쉽게되네요..
haproxy요놈은 이제 파일을 찾을수 없나봅니다.. 게시글을 찾아도 안나오네요
그것까지는 욕심이겟죠.. 아무튼
저도 .sh 파일을 만들고
작성해주신 코드르 적어서 저장을하면
“runcert.sh”
E502: “runcert.sh” is a directory
Press ENTER or type command to continue
이런에러가 뜹니다..
구글링해도 안나오네요.. 혹시 알수있을까요?
haproxy는 이제 최신 버전의 나스를 지원하지 않더군요.
샘플 코드를 runcert.sh로 저장을 했다는 것이죠?
해당 에러 메시지가 runcert.sh로 저장할 때 발생하는 것인지 아니면 실행할 때 발생하는 것인지 정확히 알려주세요.
샘플 코드를 vi로 직접 생성해도 되고 PC에서 생성한 후 특정 웹 서버에 올려두고 wget으로 내려받아 실행 권한을 주고 실행해도 됩니다.
#!/bin/bash 선언하고
작성해주신 코드 입력하고
:wq!
이렇게하거나
:w
이것만 하면 바로 에러가 뜹니다
:q!
요건 먹어용..
pc에서 만들고 cp 명령어 써서 옮긴다음에
sh runcert.sh 요롷게 하면 실행된다던데
똑같이 is directory 요론 에러가뜹니다..
혹시 해당 파일 생성 시도한 폴더가 쓰기 권한이 없는 것은 아닌가요?
CHMOD 했죠 물론,,
그냥 포기하고 수동으로 해야겟어용,,
그래도 이전보다 쉬워져서 다행입니다. 감사합니다.
혹시 텔레그램 chatID, Token은 어떻게 넣으면 될까요?
소스가 정말 좋아요!
안녕하세요.
텔레그램 관련된 부분은 옵션으로 인증서 발급 후 텔레그램으로 알림 메시지를 보내주는 것인데요. 사용하지 않아도 됩니다.
* 사용하지 않으려면
샘플 스크립트의 마지막 if문과 else문에 내에 있는 아래 코드를 삭제하면 됩니다.
msg=”~~~~”
curl -s -F ~~~
* 사용하려면
-텔레그램에서 @BotFather 사용자를 친구 추가하고 @BotFather에게 채팅 창을 열어서
-이미 만들어둔 봇이 있다면 /token 명령을 내리고 봇을 선택하면 Token 값이 표시됩니다.
-이미 만들어둔 봇이 없다면 /newbot 명령을 보낸 후 봇을 생성하면 마지막 단계에서 Token 값이 표시됩니다.
-chatID는 알림 메시지를 받을 본인의 텔레그램 계정의 chatID이며 @userinfobot 사용자를 친구 추가한 후 아무 메시지나 보내면 표시됩니다.
아 검색하니 나오네요 ㅎㅎ
좋은 정보 감사합니다.
@userinfobot 사용자
진짜 꿀팁입니다!
여러 방법 중 그 방법이 가장 편하고 다른 사람에게 설명하기도 편하더군요^^
저는 약간 다르게 acme.sh 도커 이미지로 와일드카드 인증서를 발급 받고 있습니다.
도커 쓰면 쓸수록 매력이 넘치네요.
https://www.wsgvet.com/bbs/board.php?bo_table=home&wr_id=653
텔레그램 알림 기능을 연동해봐야겠네요.
음.. 잠깐 생각해봤을때, 갱신이 되거나 안되거나 같은 경로에 인증서 파일이 이미 있을텐데…
갱신되었다고 판단할 수 있는 방법이 어떻게 될지 모르겠네요.
갱신되면 파일 생성 날짜만 바뀔 뿐 파일명도 그대로, 위치도 그대로 있을테니….
머리가 아프네요 ㅎㅎ
예. 맞습니다. 제대로 처리하려면 도커 명령을 내리기 전에 기존 인증서 파일을 백업해두고 도커 명령으로 인증서 파일 생성 시도 후 실패했을 경우 백업본을 다시 되돌리는 작업이 필요합니다.
이 부분은 도커 컨테이너에서 자동으로 판단해서 실패할 경우 기존 인증서 파일은 유지하도록 처리해야 되는데요. 아직 수정을 못했습니다.
알려주셔서 고맙습니다.
#!/bin/bash
COMPOSE=”/usr/local/bin/docker-compose –no-ansi”
cd /home/sammy/gnuboard/
$COMPOSE up –force-recreate –no-deps acme.sh && $COMPOSE kill -s SIGHUP webserver
저는 도커에 acme.sh와 nginx를 쓰고 있어서요.
위 스크립트를 수정하면 될 것 같습니다.
acme.sh는 대략 2달 후에 갱신을 시도하므로,
말씀하신대로 백업 후 돌리는 것을 해볼 수 있겠네요.
저의 경우는 이렇게 할 것 같습니다.
우선 기존에 있던 모든 인증서 파일을 bak 이름으로 변경
mv fullchain.pem fullchain.pem.bak
mv privkey.pem privkey.pem.bak
mv $DOMAIN.pem $DOMAIN.pem.bak
인증서 갱신 시도 -> 인증서가 갱신이 된다면 fullchain.pem 및 다른 파일들이 생김
그리고
-f “$CERTS_PATH/$DOMAIN/fullchain.pem”
이렇게 하면 생겼으니 인증서 갱신이 성공, 기존 bak 파일들은 삭제, 텔레그램에 성공 메세지 보냄, 후 Nginx reload
만약에 없으면 인증서 갱신이 안되었기 때문에 , 기존 bak 파일들을 원래 이름으로 변경, 텔레그램에 not yet 메세지 보냄, nginx reload 하지 않음
저는 이렇게 하면 되겠네요.
감사합니다.
영문으로된 스팸이 많아서 스팸 필터링 플러그인을 적용해서 명령어 사용해서 영문이 좀 들어가면 스팸으로 분류가 되는 문제가 있습니다.
예.. 언급하신 방식으로 해야될 것 같습니다.
제가 만든 도커 이미지도 곧 그렇게 수정하겠습니다.
고맙습니다.
어라 뭔가 많이 적었는데 글이 사라졌네요 ㅠㅠ
다시 적을게요 ㅠㅠ 아까 명령어도 넣었는데 그것 때문에 필터링 된 듯 하네요.
acme.sh는 2달이 되었는지 확인 후 갱신 작업을 합니다.
그러므로 2달이 되지 않으면 인증서 파일이 변하지 않겠죠.
그래서 갱신 직전에 미리 인증서 파일들의 확장자에 .bak을 붙여넣습니다.
갱신을 시도했을때 2달이 안되었다면 갱신이 안될 것이고, fullchain.pem을 찾으면 안보이겠죠.
그러면 텔레그램 메세지에 not yet을 보내고, 다시 인증서 파일들을 돌려놓습니다.
—
만약 2달이 넘어 갱신이 되었을 땐 fullchain.pem을 보면 있기 때문에, 텔레그램에 success를 보내고 기존 백업 인증서를 삭제합니다. 그 후 nginx를 reload 하면 될 것 같습니다.
감사합니다.
코드 초보입니다.
저는 이렇게 구성했습니다.
일단은 잘 되는 것 같습니다.
#!/bin/bash
COMPOSE=”/usr/local/bin/docker-compose –no-ansi”
HUBS_DOMAIN=”example1.com”
CDN_DOMAIN=”example2.com”
CHAT_ID=”1231313132″
TOKEN=”1231321312:ASDGAKSDFLAKJSDLFKJASDLFK”
HUBS_TK=”/home/ubuntu/gnuboard/site/ssl/example1.com”
HUBS_TK_BAK=”/home/ubuntu/gnuboard/site/ssl/example1.com.bak”
CDN=”/home/ubuntu/gnuboard/site/ssl/example2″
CDN_BAK=”/home/ubuntu/gnuboard/site/ssl/example2.bak”
mv $HUBS_TK/* $HUBS_TK_BAK
mv $CDN/* $CDN_BAK
msg=”Renew ‘$HUBS_DOMAIN’ start”
curl -s -F chat_id=$CHAT_ID -F text=”$msg” https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null
msg=”Renew ‘$CDN_DOMAIN’ start”
curl -s -F chat_id=$CHAT_ID -F text=”$msg” https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null
cd /home/ubuntu/gnuboard/
$COMPOSE up –force-recreate –no-deps acme.sh
if [ -f “$HUBS_TK/fullchain.pem” ]; then
msg=”Let’s Encrypt SSL certificate ‘$HUBS_DOMAIN’ updates -> success”
curl -s -F chat_id=$CHAT_ID -F text=”$msg” https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null
rm -f $HUBS_TK_BAK/*
else
msg=”Let’s Encrypt SSL certificate ‘$HUBS_DOMAIN’ updates -> skip”
curl -s -F chat_id=$CHAT_ID -F text=”$msg” https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null
mv $HUBS_TK_BAK/* $HUBS_TK
fi
if [ -f “$CDN/fullchain.pem” ]; then
msg=”Let’s Encrypt SSL certificate ‘$CDN_DOMAIN’ updates -> success”
curl -s -F chat_id=$CHAT_ID -F text=”$msg” https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null
rm -f $CDN_BAK/*
else
msg=”Let’s Encrypt SSL certificate ‘$CDN_DOMAIN’ updates -> skip”
curl -s -F chat_id=$CHAT_ID -F text=”$msg” https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null
mv $CDN_BAK/* $CDN
fi
$COMPOSE kill -s SIGHUP nginx
msg=”Reloading nginx … done”
curl -s -F chat_id=$CHAT_ID -F text=”$msg” https://api.telegram.org/bot$TOKEN/sendMessage > /dev/null
고맙습니다. acme.sh 사용하시는 분들께 많은 도움이 될 듯합니다.
안녕하세요, nas4dual에서 docker를 실행하십시오. 시도해 보셨습니까?
https://download.docker.com/linux/static/stable/armel/
안녕하세요.
현재 nas4dual에 사용하던 디스크가 고장난 후 교체하지 않아서 사용을 못하고 있습니다.
nas4dual에 도커를 올릴 생각은 못해봤습니다.
남겨주신 링크보니 빨리 디스크 구입해서 시도해보고 싶네요.
나중에 디스크 구입하면 시도해보고 결과 남기도록 하겠습니다.