이 포스팅은 꽤나 턱별한
포스팅이다.
http://chat-app-backend.online:3000
에 배포된 백엔드 서버에 ssl을 적용하여 https로 만들어야 했다.
프론트가 https에 배포되었기 때문에 백엔드도 동일하게 https에서 요청을 받지 않으면 mixed content CORS
에러가 나기 때문.
거의 장장 2주간에 걸친 삽질끝에 해내었다. 이렇게 오랜기간 삽질하고 무언가를 뚫어낸 경험이 이번이 처음이다.
이때까지 프론트만 하다가 네트워크와 ssh를 다뤄야해서 더 힘들었었던 것도 있다.
또한, ssl을 적용할 수 있는 방법이 매우 다양해서 더 길을 헤맨것도 있는 것 같다.
그럼 일단 거두절미하고 바로 가보자.
먼저 ssh를 이용해 원격으로 vm에 접속하기 위해 아래 명령어를 입력해주자
sudo ssh ubuntu@{"ip_address"} -i {"private_key"}
우선 nginx를 reverse proxy로 이용해서 http://chat-app-backend.online:3000
으로 들어오는 요청을 https://chat-app-backend.online
으로 만든다음 서버로 요청을 흘려보낼것이다.
그리고 ssl에 필요한 공개키와 암호키를 만들고 그것을 적용할 certbot을 설치해야한다.
즉 nginx
와 certbot
두개를 다운받아야 한다.
$ sudo apt-get install letsencrypt
$ sudo apt-get install python3-certbot-nginx // nginx plugin for certbot
$ sudo apt install nginx
이제 certbot이 자동으로 ssl을 적용하고 nginx를 이용해 http요청을 https요청으로 바꾸는 작업까지 할것이다.
일단 서버 코드를 github에서 다운받고 아래 순서를 따라 환경구축해주자
git clone
으로 코드 복사하기.env
파일 설정npm install
실행하여 라이브러리 다운npm install pm2 -g
를 실행하여 pm2를 다운받고 pm2로 최초진입파일(ex> app.js) 를 start참고로 , ec2가 포트를 열어놓아야 nginx에서 그 포트로 요청을 보낸다.
location / {
proxy_pass http://127.0.0.1:3300; # 백엔드 서버로 요청 전달
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
proxy_pass http://127.0.0.1:3300;
바로 요 코드가 그러한 역할을 한다.
server - location 블록안에서 해당 location(도메인)으로 요청이 들어오면 proxy_pass로 요청을 넘겨주는 것이다. 이걸로 ip주소를 노출하지 않아도 되서 보안강화도 돼고 로드밸런싱도 가능하다.
그러기 전에 nginx config파일에 proxy 할 대상과 목적지를 명시해줘야한다.
아래 명령어를 입력하여 config파일에 들어가자
$ sudo vim /etc/nginx/nginx.conf
sudo를 안쓰면 read-only로 접속됨
그리고 아래 서버블록을 http블록안에 적어주고 저장해주자
server {
server_name chat-app-backend.online; // proxy할 도메인
listen 80;
location / {
proxy_set_header HOST $host;
proxy_pass http://127.0.0.1:3000; // proxy의 목적지
proxy_set_header X-Forwarded-Proto $scheme; // 쿠키 허용
add_header 'Access-Control-Allow-Origin' '*';
proxy_redirect off;
}
}
nginx에서 해당 서버로 통신가능하도록 포트를 열어주자.(아래 링크 참고)
그러고 아래 명령어를 입력하여 certbot을 실행시키자
$ sudo certbot --nginx
마지막으로 express.js를 사용한다면 proxy를 허용해주어야한다.
app.set("trust proxy", true); // trust first proxy
그럼 congratulation
이라고 ssh창에 뜨면서 ssl이 성공적으로 적용된것을 볼 수 있다.
생각보다 매우 간단해서 허탈하다.
감격의 도가니 😭🎊
그리고 nginx config파일에 다시 들어가보면 certbot이 알아서 ssl설정을 한것을 확인할 수 있다.
server {
server_name chat-app-backend.online;
location / {
proxy_set_header HOST $host;
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Forwarded-Proto $scheme;
add_header 'Access-Control-Allow-Origin' '*';
proxy_redirect off;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/chat-app-backend.online/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/chat-app-backend.online/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = chat-app-backend.online) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name chat-app-backend.online;
listen 80;
return 404; # managed by Certbot
다만 , certbot을 통해 설치된 ssl은 90일까지만 유효하다. 이후 에는 sudo certbot renew
를 통해 수동으로 갱신해줘야한다.
그러나 개발자는 항상 자동화 하는 법!
crontab이라는 툴이 있다. 리눅스 기반시스템에 자동으로 깔려있는 툴인데 스케쥴링을 해준다.
crontab -e
를 입력해서 들어가고 난 다음 아래 코드를 추가한후 저장해주었다.
30 1 1,15 * * certbot renew --post-hook "systemctl reload nginx"
해석하면 아래와 같다.
"매달 1일과 15일, 01:15 에 certbot을 리뉴한다."
혹시 제대로 설정했는데도 welcome to nginx 가 뜬다면 default를 제거해주자
sudo rm /etc/nginx/sites-enabled/default
Domain: budifygasstaging.duckdns.org
Type: connection
Detail: 1.225.87.193: Fetching http://budifygasstaging.duckdns.org/.well-known/acme-challenge/FenqsBgeZmkpwxvWA8QpUf0WIMholz0KLLm6M4hsvJo: Timeout during connect (likely firewall problem)
80포트가 열리지 않아서 그렇다.
duckdns에서 도메인발급받은후에 ec2 public ip를 duckdns current ip에 입력하고 update 하면 된다. 이걸 몰라서 2일이나 삽질했다....(스테이징 환경 구축 중에...)
혹시 그래도 안되면 manual하게 인증서를 발급받아도 된다. 요 명령어를 입력하자 certbot certonly -d “*.도메인이름” —manual —preferred-challenges dns
삽질을 이제 더이상 삽질이라고 생각하지 않기로 했다. 그 과정에서 얻은 모든 정보가 사실 하나로 합쳐져서 큰 그림을 이해할 수 있게 해준다.
참고자료