공작소는 Nginx + Let'sEncrypt를 활용해서 Https를 활용할 수 있도록 구축했다.
구축한 도입기는 링크를 확인하면 된다.
이전 도입기의 큰 문제점은 gongjakso.xyz라는 도메인은 SSL/TLS 인증서가 적용되어 있지 않았다는 점이다. 최초 설정 과정에서, 이 부분을 미쳐 고민하지 않은 채 서버 도메인에 대한 certbot 인증서만을 발급했기 때문이다. 이는, 사용자 입장에서 보안 연결이 아니라는 문구가 뜨게 되어 사용자의 이탈률을 높이는 중요한 포인트 중 하나라고 생각했다.
두 번째로는, 현재 EC2에 설치된 Docker의 overlay2 디렉토리에 불필요한 용량을 차지하고 있는게 많아 서버 다운이 자주 발생하고 있었다는 점이다. 해당 overlay2 디렉토리는 불필요한 파일이 어떤 것인지를 판단하기 굉장히 어렵다 보니, EC2를 새로 구축하면서 Nginx + Certbot을 이용한 인증서 구조도 개선하면 되겠다고 생각했다.
이 결정 이후, 도입까지 총 3가지 방식의 시도를 했으며, 마지막 방식으로 성공했다.
1번 방식과 2번 방식은 경험한 오류만을 정리하며, 3번 방식만 진행한 과정을 자세하게 정리해보고자 한다.
첫 번째로는 기존의 Certbot을 통해 발급하는 방식으로 Netlify로 배포한 프론트의 도메인까지 같은 인증서로 발급받는 방식이다. 해당 과정에서 아래와 같은 오류가 발생했다.
sudo certbot --nginx -d domain.com -d *.domain.com
Client withith the currently selected authenticator does not support any combination of challenges that will satisfy the CA. You may need to user an authenticator plugin that can do challenges over DNS.
위 오류는 Let's Encrypt의 도메인 소유권 인증 방식과 관련된 오류다. Let's Encrypt는 도메인 소유권 검증을 위해 다양한 챌린지 방식을 제공하는데, 소유권 검증을 위한 DNS 인증기 플러그인을 사용해야 가능하다고 알려주는 것이다. HostingKR의 네임 서버를 이용하고 있었는데, 관련된 인증기 플러그인을 설명하는 문서를 제대로 찾지 못해 다른 커맨드를 시도하기로 결정했다.
sudo certbot certonly --manual --preferred-challenges dns -d domain.com -d *.domain.com
다른 문서들과 블로그 글을 수십 개 읽어본 끝에, 위 커맨드를 사용해서 시도했다. 위 방식은 네임 서버에 TXT 레코드를 추가하여 인증하는 방식인데, 레코드 반영에 시간이 걸리므로 1시간 이상을 기다려 봤음에도 불구하고, 아래와 같이 오류가 발생하여 다른 방식을 선택했다.
두 번째로는 네임 서버를 Netlify로 이전하는 것이다. Netlify는 자신들의 네임 서버를 사용하게 될 경우, Let's Encrypt를 활용해서 자동으로 SSL/TLS 인증서를 발급 및 적용해준다. 해당 발급된 인증서를 활용해서, Nginx에 등록하는 방식으로 진행하고자 했으나, Netlify에서 발급된 인증서의 pem 정보를 전달받을 수 있는 방법을 찾지 못해 마지막 3번 방식을 시도했다.
아래와 같은 기능을 가지고 있는 Cloudflare를 활용한다.
Cloudflare는 무료 플랜을 활용했으며, Cloudflare 도메인 생성 및 Nginx 설치 등의 기본적인 작업은 진행했다는 전제이다.
HostingKR에 접속하여, 변경하고자 하는 도메인의 네임 서버를 Cloudflare의 네임 서버로 변경한다.
Cloudflare 네임 서버 확인하는 방법
홈 -> 도메인 -> DNS로 접근, 페이지 하단의 Cloudflare의 네임 서버를 확인
연결하고자 하는 IP 또는 웹페이지의 주소를 레코드로 적용해서 업데이트한다.
프론트 주소와 백엔드 주소를 둘 다 하나의 도메인에서 서브 도메인을 활용해서 관리하므로 나는 총 3개의 레코드를 등록했다.
유형 | 이름 | 콘텐츠 |
---|---|---|
A | backend(예시) | 백엔드 서버 IP |
CNAME | @ | Netlify URL |
CNAME | www | Netlify URL |
순서대로, 백엔드 연결 / 프론트엔드 연결 / 프론트엔드 연결이다. 여기서 주의사항은 HTTPS를 위한 SSL/TLS 인증서를 Cloudflare에서 발급했으므로, 프록시를 활성으로 변경해야 한다.
위 과정에서, DNS 레코드 업데이트 사항은 아래의 사이트를 통해서 지속적으로 반영 여부를 확인했다.
이제 Cloudflare의 SSL/TLS에 접속하여 인증서를 발급하면 된다. SSL/TLS의 원본 서버를 접속하면, 아래와 같은 페이지가 나오는데 여기서 인증서 생성 버튼을 클릭하여 인증서를 생성하면 된다.
인증서를 생성하고 나면, 원본 인증서와 개인 키를 확인할 수 있다.
해당 키 정보를 꼭 개인 PC에 저장해놓아야 한다.
이에 더해, Netlify에 인증서를 등록할 때 root 인증서가 필요하므로 Cloudflare Developers에 접속하여 root 인증서 또한 다운로드해야 한다.
위의 과정을 거친 후에 꼭 SSL/TLS 암호화 모드를 전체(엄격) 으로 변경해야 한다. 기본적으로 가변으로 설정되어 있는데, 이는 Cloudflare를 통과한 이후의 백엔드 서버 사이에서의 인증은 정상적으로 이루어지지 않아, 사이트를 접속하면 certificate가 유효하지 않다는 경고문을 띄우기 때문이다.
프론트는 Netlify로 배포했기에, Netlify 내에서 인증서 정보를 등록해야 한다.
Netlify에서 변경하고자 하는 site의 Domain management로 접속하면 페이지 하단에서 HTTPS를 위한 인증서를 업데이트할 수 있다.
이미지와 같은 화면에서 update custom certificate
를 클릭하여 정보를 입력 후 업데이트를 진행하면 된다. 입력해야 하는 정보는 아래와 같다.
정상적으로 완료하면, Certificate: Custom
으로 변경된 것을 확인할 수 있다.
마지막은 백엔드 서버에 인증서를 반영하는 것이다. 백엔드 서버는 Nginx를 활용하기 때문에, Nginx 설정 파일에서 해당 정보를 등록해야 한다.
먼저 pem키들을 특정 폴더를 만들어 저장했다.
sudo mkdir authentication
cd authentication
sudo vi certificate.pem
sudo vi privatekey.pem
이후, ngixn.conf를 변경했다. 변경된 nginx.conf는 아래와 같다. (주석은 삭제했다.)
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
server {
if ($host = [Server Domain]) {
return 301 https://$host$request_uri;
}
listen 80;
server_name [Server Domain];
return 404;
}
server {
server_name [Server Domain];
listen 443 ssl;
ssl_certificate /etc/nginx/authentication/certificate.pem;
ssl_certificate_key /etc/nginx/authentication/privatekey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
}
변경된 내용
변경된 설정으로 nginx를 재시작하면 성공적으로 반영된다.
sudo service nginx restart
이렇게 공작소는 보안 연결까지 포함되어 다시 태어났다.
후기
전환하는 결정은 쉬웠지만 다운타임은 거진 10시간을 넘겼었기에 앞으로 이런 경우가 발생하지 않도록 처음부터 잘 설계해서 구축해야 한다는 점을 복기할 수 있었고, 마주친 여러 문제들을 통해 네트워크 관련 내용도 학습할 수 있는 재밌는 경험이었다.
참고했던 레퍼런스