만약 TLS를 적용하지 않는다면 http로 서비스 배포를 할 수 있지만 http로 배포를 하게 되면 유저의 데이터가 네트워크 상에 평문으로 노출되기에 보안이 좋지 않기도 하며, 아래 사진과 같이 chrome으로 접속하면 경고창을 보여준다.
그리고 현재 배포하려는 앱이 PWA로 만들어졌기에 https 배포가 필수이다.
이전 포스팅에서 한 것처럼 80, 443번 포트를 홈 서버로 포워딩을 시켜줘야한다.
이때 80번 포트는 http, 443번 포트는 https로 약속되어 있다.
Let's Encrypt는 사용자에게 무료로 TLS 인증서를 발급해주는 비영리기관이다. 홈페이지로 들어가보면 aws, mozilla, cisco, meta 같은 대기업들이 후원해주고 있는것을 알 수 있다.
발급된 인증서는 유효기간이 90일이며 만료 30일 전부터 갱신할 수 있다. 갱신 가능 횟수는 무제한이다.
대부분 인증서를 발급받을 때 certbot을 많이 사용하는데, certbot은 TLS/SSL 인증서를 자동으로 발급하고 갱신할 수 있도록 도와주는 오픈소스 도구이다.
대부분 해당 링크를 참조를 하고 있어서 봤는데 docker를 이용하여 쉽게 TLS 인증을 받아 사용할 수 있도록 만들어줬다. 인증서를 발급할 때 해당 글을 따라하면 쉽게 발급이 가능하다.
발급 받은 후 프로젝트를 도커 컴포즈로 모두 연결하면 https로 앱 배포가 완료된다!
나는 프론트엔드는 React를 이용하였기에 html, css, javascript 정적 파일로 반환이 되었다.
그렇다면 아키텍처를 생각해보면 도커 컨테이너에는 nginx
, certbot
, server
, database
이렇게 4개의 컨테이너가 컴포즈로 묶여있고, nginx를 이용하여 프론트엔드의 정적 파일을 서빙해주고 있다.
그래서 도커로 애플리케이션까지 연결하여 배포하면 아래와 같이 외부에서 홈 서버에 배포된 앱에 접속할 수 있게 된다!
위의 링크에서 적힌대로 진행하다보면 init-letsencrypt.sh
파일이 있는데 테스트할 때는 staging값을 1로 설정하고, staging 값을 1로 설정했을때 잘 된다면 그때 만들어진 폴더는 모두 제거하고 staging을 0으로 바꿔서 실행하는게 좋다.
staging 1은 테스트로 발급해보는 과정인데 왜 테스트를 하냐면 도메인 당 발급 제한 횟수가 있기에 잘못하다가 며칠동안 손도 못쓰는 수가 있다.
만약 staging을 0으로 계속 시도한다면 아래와 같은 에러를 만날수도 있다.. 😢
- iptime 공유기를 사용하는 경우
해당 내용은 이전 포스팅 홈 서버 구축 일대기 (2) - 공유기 변경에서 다뤘던 내용인데 iptime 공유기는 CAA 레코드로 인해 DDNS에 TLS 인증서 발급이 불가하다.
iptime 공유기의 DDNS로 TLS 인증서를 발급하려고 시도하는 경우
정상적으로 TLS 인증서가 발급되는 경우
- TLS 인증서 발급이 실패하는 경우
만약 제공된 링크를 잘 따라했다면 문제가 없을것이지만 그래도 이런 비슷한 에러가 뜬다면 아마 app.conf
파일 위치를 잘못 배치했거나 오타가 있을 확률이 크다. 나는 _(언더바), ;(세미콜론)을 빼먹어서 에러가 발생했었다.
해당 문제의 원인과 해결책은 다양하게 있을 수 있겠지만 나의 경우를 공유해보면 인증서는 정상적으로 발급이 되었지만 https 접속이 실패처리가 됐다.
- 발급이 되었을 때 도커의 volume mount된 폴더 확인
아마 staging=1로 설정하여 인증서 테스트 발급하면 data/certbot/conf/live/{도메인명}
으로 폴더가 생성이 된다.
이떄 해당 폴더를 삭제를 안하고 staging=0으로 변경하여 다시 인증서 발급을 한다면 data/certbot/conf/live/{도메인명-001}
폴더에 인증서가 발급이 된다.
docker에서 volume mount를 data/certbot/conf/live/{도메인명}
으로 해뒀기에 테스트 인증서로 인증을 시도한다면 실패하게 된다.
- 포트 포워딩 문제
문제없이 설정을 완료했는데도 HTTPS 접속이 안됐었다. 그래서 클라이언트에서는 wireshark
를 이용하여 패킷을 확인해보았고, 서버는 tcpdump
툴을 이용하여 패킷을 검사해봤다.
클라이언트 패킷
패킷을 직접 확인해보니 Client Hello
에서 멈춘것을 확인할 수 있었다. 그렇다면 서버측에 제대로 전달이 안됐거나, TLS 처리가 제대로 안됐거나 둘 중 하나가 원인임을 예상할 수 있다.
그리고 서버의 tcpdump
로그를 확인해보니 아무런 패킷을 감지하지 못했었다.
그렇다면 서버까지 제대로 패킷이 전달이 안됐다는 뜻이니 라우터(공유기)를 확인해보니 80, 443포트가 모두 80번 포트로 포워딩이 되고있었다.. 🤣
80번 포트는 정상적으로 80번 포트로 포워딩이 되기에 도메인 소유권 확인을 HTTP로 검증하니 정상적으로 처리가 되었었지만 443 포트는 정상적으로 포워딩이 안되어 외부에서 접근이 안됐었다.
그래서 443포트를 80번이 아닌 443포트로 포워딩을 시켜주니 문제가 해결됐다!
홈 서버를 구축하는 작업을 해보기 전에는 생각보다 막연했던 부분이 있었다. 우선 도메인에 대한 처리였고, 그 다음은 보안 문제에 대한 고민이었다.
DDNS 개념에 대해 최근에 알게 되었지만 해당 DDNS로 TLS 인증서 발급이 가능할지에 대해 잘 몰랐고, CA에서 도메인의 소유권을 어떻게 인증하는지도 몰랐기에 여차하면 bind9
을 이용하여 직접 DNS를 구축하여 TLS 인증 처리를 해야하나 고민도 했었다.
하지만 ASUS 공유기에서 잘 처리를 해주어 일이 수월하게 해결되었다.
그리고 홈 서버를 구축하며 마주한 문제를 해결하는 과정에서 학부생때 배웠던 CS 지식들과 툴을 활용해보며 부족했던 지식들을 채울 수 있었고 나름 재미도 찾을 수 있었다 ㅎㅎ
가장 좋은건 이제 저전력 PC의 전기요금만 납부하여 애플리케이션을 배포할 수 있게 되었다. 이때까지 앱을 배포하며 가장 부담이 되었던건 매달 유지할 비용이 문제였는데 그런 고민이 사라졌다. 😁
이제는 배포를 성공했지만 부족한 애플리케이션 개발을 마저하며 홈 서버는 추가적인 보안과 모니터링을 도입할 예정이다.
굉장히 흥미로은 일을 하고계시는 군요...!! 홈서버 낭만있는 것 같아요. 멋집니다..! 그런데 다시보니 노트북들고 앉아있는 피규어... 저희 집에도 있는 친구네요 신기신기