YOGYUI

Let's Encrypt로 발급받은 SSL 인증서 갱신하기 본문

홈네트워크(IoT)/일반

Let's Encrypt로 발급받은 SSL 인증서 갱신하기

요겨 2022. 5. 28. 21:36
반응형

Renew SSL Certificate (Let's Encrypt)

 

평소에 홈 IoT 음성 제어를 할 때 왠만하면 아이폰의 시리를 활용하고 간혹 구글 홈 미니 스피커를 사용하는데, 얼마전부터 홈 네트워크에 접속할 수 없다는 안내 멘트만 흘러나오고 제어가 되지를 않게 되었다

 

혹시나 싶어 Home Assistant(HA) 페이지로 접속을 시도해보니 "Unable to connect to Home Assistant." 문구만 덩그러니 뜬 채 접속이 되지 않았다

 

구글 어시스턴트가 HA와 연동되기 위해서는 HA에 HTTPS 보안 접속이 되는 환경을 꾸며야되는데, 지난 2월 쯤에 안드로이드랑 연동하기 위해 라즈베리파이에 HA 컨테이너랑 Nginx를 설치하고, duckdns에서 무료 도메인을 발급받은 뒤 Let's Encrypt로 SSL 인증서를 발급받아 사용하고 있었다

관련글: ipTime 공유기 시스템에서 SSL 인증서 발급하기 (Let's Encrypt)

 

ipTime 공유기 시스템에서 SSL 인증서 발급하기 (Let's Encrypt)

ipTime 공유기에 연결된 웹서버에 HTTPS (HTTP Secure) 연동을 위해 SSL(Secure Sockets Layer) 인증서를 발급받아보자 ※ Home Assistant와 Google Assistant 연동할 때 반드시 필요한 작업 Synology 계열 제품..

yogyui.tistory.com

 

그 때 기록을 뒤져보니 2022년 5월 20일에 발급받은 키가 만료된다고 명시되어 있었다 ㅎㅎ...

구글 홈어시스턴트 연동 성공에 취한 나머지 갱신해야 한다는 사실을 까맣게 잊어먹고 있었다

어차피 곧 이사갈거라 굳이 지금 당장 갱신해야 할 필요가 없긴 하지만, 그래도 주말에 뒹굴뒹굴 노느니 미리 작업해두면 나중에 따로 신경써야할 일이 줄어들 것 같으니 미리미리 작업해두도록 한다

 

1. 라즈베리파이 할당 IP로 80번 포트 포트포워딩하기

Let's Encrypt는 SSL 인증서를 발급받고자 하는 도메인 (http://domain)의 ./well-known/acme-challenge/ URL로 파일을 주고받는 과정 (GET 프로토콜)을 거치기 때문에, 해당 URL로 접근할 수 있는 경로를 열어줘야 한다

만약 해당 URL에 대한 접근 경로를 열어두지 않는다면 Let's Encrypt 인증을 시도하면 다음과 같이 404 에러(Not Found)로 인해 인증이 진행되지 않게 된다

Let's Encrypt 404 에러 로그

 

어차피 Homebridge, HA, Mosquitto, Nginx 등 홈네트워크 관련 플랫폼은 모두 단일 라즈베리파이에서 구동하고 있기 때문에, 80번 포트를 라즈베리파이에 할당된 IP의 80번 포트로 포트포워딩해주기로 한다

 

※ 나처럼 ipTime 공유기를 사용하고 있다면, 관리자 설정 포트가 default로 80으로 설정되어 있으면 80번 포트 포워딩 시 관리자 설정창으로 이동할 수가 없으므로, 관리자 설정 포트를 다르게 설정해주도록 한다

공유기 관리 포트 변경

 

만약 원격 관리 포트를 사용중이라면, 해제하거나 포트번호를 바꿔줘야 한다

원격 관리 포트 설정

 

HTTP로 도메인에 접속했을 때, "Welcome to nginx!" 메시지가 출력되면 정상적으로 설정된 것이다

※ 라즈베리파이에 Nginx 설치하는 방법은 다음 글을 참고

Bestin 홈네트워크 Flask 웹서버 - Nginx 연동

 

Bestin 홈네트워크 Flask 웹서버 - Nginx 연동

기존에 내가 구현해둔 Bestin 홈네트워크 - Homebridge 연동 코드는 Python의 Flask 패키지를 활용해 웹서버를 구동하게 된다 https://github.com/YOGYUI/HomeNetwork/tree/main/IPark-Gwanggyo GitHub - YOGYUI/..

yogyui.tistory.com

 

2. Nginx 설정

이제 외부에서 도메인의 80번 포트로 접속 시 라즈베리파이의 80번 포트로 라우팅되는데, 앞서 말했듯이  ./well-known/acme-challenge/ 호출 시 Nginx가 열어둔 80번 포트 서버를 통해 라즈베리파이 로컬 디스크에 파일을 저장할 수 있도록 설정해주자

(/etc/nginx/sites-available/ 경로 내 생성해둔 설정파일 변경)

server{
    listen 80 default_server;
    listen [::]:80 default_server;
    
    root /var/www/html;
    
    index index.html index.htm index.nginx-debian.html;
    
    server_name _;
    
    location / {
        try files $uri $uri/ = 404;
    }
    
    # 아래 3줄 추가
    location ~ /\.well-known/acme-challenge/ {
        allow all;
        root /var/www/letsencrypt;   
    }
}

이제 ./well-known/acme-challenge/ 호출 시 로컬의 /var/ww/letsencrypt 경로로 접근할 수 있게 되었다

 

전체적인 흐름을 schematic으로 정리해봤다

 

3. SSL 인증서 갱신

앞의 1~2번 과정은 SSL 인증서 초기 발급 시 한번 작업했던 내역이라 리마인드 차원에서 다시 한번 기록해봤다 ㅎㅎ

라즈베리파이에 설치해둔 certbot 으로 다음과 같이 인증서 갱신 명령 스크립트를 호출해보자 (renew 인자)

$ sudo certbot renew

정상적으로 진행되면 위와 같이 fullchain.pem 파일이 갱신된다

renew로 갱신되는 저장 경로는 /etc/letsencrypt/archive/{domain}이다 
이는 /etc/letsencrypt/renewal/{domain}.conf 파일을 통해 확인할 수 있다
# renew_before_expiry = 30 days
version = 0.31.0
archive_dir = /etc/letsencrypt/archive/xxxx.duckdns.org
cert = /etc/letsencrypt/live/xxxx.duckdns.org/cert.pem
privkey = /etc/letsencrypt/live/xxxx.duckdns.org/privkey.pem
chain = /etc/letsencrypt/live/xxxx.duckdns.org/chain.pem
fullchain = /etc/letsencrypt/live/xxxx.duckdns.org/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = ----------------------------------
authenticator = webroot
server = https://acme-v02.api.letsencrypt.org/directory
[[webroot_map]]
xxxx.duckdns.org = /var/www/letsencrypt​

renew_before_expiry 항목의 주석은 왠지 자동으로 갱신되는 옵션같긴 한데, certbot 문서를 좀 더 읽어봐야겠다 

갱신된 fullchain.pem 파일을 HA 설치경로의 ssl/ 디렉터리로 복사해주자

(configuration.yaml 파일의 ssl 관련 설정을 ssl/ 경로로 설정해뒀었다)

※ fullchain1.pem과 같이, 갱신이 진행됨에 따라 번호가 붙는 것 같다.. 나중에 한번 더 갱신할 때 확인 필요~

$ sudo cp /letsencrypt/live/xxxx.duckdns.org/fullchain1.pem ~/homeassistant/ssl/fullchain.pem

이제 HA를 재시작해줘야되는데, 라즈베리파이로 원격접속(VNC, SSL 등)해서 docker 컨테이너를 재시작하거나, 페이지로 접속해서 재시작하거나, 라즈베리파이를 재부팅하거나 등등 다양한 방법이 있으니 편한 방법을 택하면 된다

 

그리고 외부에서 HTTPS로 접속해보니 정상적으로 접속된다

 

구글 홈 미니 음성명령도 다시 잘 인식된다~

굳굳!

 

만약 renew 명령을 한번 더 날리면, 아직 유효기간이 남아있으니 갱신이 진행되지 않는 것을 알 수 있다

유효기간이 남아 갱신되지 않음

 

4. 정리

Let's Encrypt로 발급받은 SSL 인증서는 유효기간이 3개월이라, 일정 기간마다 갱신해줘야 한다 (유효기간이 남은 상태에서는 갱신되지 않는다)

또한, 나같은 경우는 갱신된 인증서에 HA가 접근할 수 있어야 하기 때문에 인증서를 다른 경로로 복사해줘야 하는 시퀀스가 추가로 필요하다

갱신된 발급서는 /etc/letsencrypt/archive/{domain}/fullchain1.pem과 같이 숫자가 붙는 것 같은데, 이는 3개월 뒤에 정확히 확인해본 뒤 자동 갱신 스크립트를 만들어보기로 한다 (다음 갱신 때 파일이 fullchain2.pem로 저장된다면 가장 큰 숫자가 담긴 파일을 가져오는 로직을 추가해야 되기 때문에 ㅎㅎ...)

 

certbot은 처음 발급받을 때 설정이 다소 번거로워서 그렇지, 한번 세팅만 해두면 그다음부터 갱신 과정은 명령어 한줄(sudo certbot renew)만 호출하면 되기 때문에 상당히 편하다!

 

[참고]

https://docs.digitalocean.com/support/how-can-i-renew-lets-encrypt-certificates/

반응형