-
네이버클라우드 서비스를 활용한 알림(PUSH) 앱 배포하기Infra/ncloud 2023. 11. 19. 15:10
프론트엔드 개발자라면 필수로 알아야 하는 지식 중 하나가 웹 서버를 통해 구현한 서비스를 직접 배포하는 방법인데요. AWS를 이용하면 CloudFront, S3 또는 EC2를 통해 배포를 진행하는데 과연 네이버클라우드에서는 어떻게 프론트 서버를 구축하는지? 한번 알아보는 시간을 가져보도록 하겠습니다.
사실 이미 많은 분들이 네이버클라우드를 통해 React에서 개발한 프로젝트를 빌드해서 배포하는 방법을 경험하셨기 때문에 해당 내용을 검색하시면 쉽게 원하는 내용을 찾으실 수 있습니다. 대신 저는 이 글에서 네이버클라우드의 또 다른 서비스인 SENS(Simple & Easy Notification Server)를 활용해서 PUSH 알림을 받을 수 있는 앱을 PWA를 이용해 배포하는 방법에 소개해드리도록 하겠습니다.
🛒 서버 선택하기
가장 먼저 네이버클라우드 콘솔에 접속하여서 앱 서버로 이용할 서버를 선택해야 하는데요. 당연한 말이지만 메모리가 높고 CPU 코어수가 높을 수록 비용이 비싸집니다. 어떤 서버를 선택해야 할지에 대한 글은 아래 링크를 통해 확인하실 수 있습니다.
저는 간단하게 가입시 무료로 1년 동안 사용할 수 있는 micro 서버를 이용하였습니다.
📦 웹 서버(Nginx) 설치하기
서버를 선택하고 생성까지 완료하셨다면 SSH 도구를 통해 서버에 접근할 수 있도록 포트포워딩을 진행합니다. 포트포워딩 및 SSH 접속방법에 대한 글은 아래 링크를 통해 확인하실 수 있습니다.(도커까지는 설치 안 하셔도 됩니다)
접속까지 완료하셨다면 이제 저희가 앱을 실시간으로 구동시킬 웹 서버를 설치해야 하는데요. 그 전에 외부에서 접속 가능하도록 포트번호를 개방하도록 하겠습니다. Nginx에서는 80, 443 포트번호를 각각 http, https 프로토콜의 기본 포트번호로 사용하고 있는데 저희는 PWA의 서비스워커 기능을 사용해야 하기 때문에 80번 뿐만 아니라 443 포트번호를 허용해주셔야 합니다.
네이버클라우드에서 외부IP로 접속 가능한 포트를 허용해 주는 방법은 다음과 같습니다. 먼저 네이버클라우드 콘솔에 접속해서 사용할 서버를 선택해 준 뒤 ACG 이동 아이콘을 클릭합니다.
ACG로 이동하면 서버를 생성할 때 적용한 ACG를 선택하여 [ACG 설정] 버튼을 클릭합니다.
그 후에는 다음과 같이 ACG에 규칙을 추가해주시고 [+추가] 버튼을 클릭한 뒤 [적용] 버튼을 클릭하시면 방화벽 설정이 완료됩니다. 저는 모든 IP에 대해 접근 가능하도록 허용해 놓았는데 상황에 따라 좀 더 보안을 강화하셔도 좋습니다.
마찬가지로 80번 포트번호도 개방이 안되있다면 추가해주시면 됩니다. 80번 포트를 개방하는 이유는 아래서 설치할 certbot 때문인데요. certbot이 제대로 동작할 수 있도록 하려면 80번 포트 역시 마찬가지로 개방해주셔야 합니다. 이제 새로운 네트워크 및 방화벽 규칙이 적용되었으므로 서버를 재시작 해줍니다. 재시작하는 데 걸리는 시간은 서버를 새로 생성하는 시간만큼은 아니지만 상황에 따라 어느 정도의 대기시간이 소요됩니다.
재시작이 완료되면 이제 모든 준비가 끝났으므로 Nginx를 설치해보도록 하겠습니다. Nginx는 다음과 같은 명령어로 쉽게 설치할 수 있습니다. 저는 우분투 환경이므로 우분투 명령어로 설치를 진행하였습니다.
sudo apt-get update sudo apt-get install nginx
root 계정으로 접속하시면 sudo 명령어 없이 실행 가능하므로 가능하면 root 계정으로 진행해서 좀 더 편리하게 작업하시면 좋습니다. nginx는 현재 시간 기준 1.14.0 버전으로 설치됩니다. 뒤에 나올 환경 설정들이 버전에 따라 조금씩 다를 수 있으므로 주의하시면 좋을 것 같습니다.
🔐 SSL 인증서 발급받기
PWA의 기능들을 온전히 사용하려면 https 프로토콜로 접속가능하도록 만들어야 한다고 앞서 말씀드렸었는데요. https 프로토콜을 사용하려면 먼저 다음과 같은 절차가 필요합니다.
공인 IP 발급받기 > 도메인 주소 만들기 > SSL 인증서 발급받기 > https 프로토콜 사용하기
그럼 https 프로토콜을 사용하기 위한 첫 번째 순서인 공인 IP 발급받는 방법부터 차근차근 알아보도록 하겠습니다.
1. 공인 IP 발급받기
먼저 첫번째 순서인 공인 IP 발급받기입니다. 공인 IP는 네이버클라우드 콘솔에서 클릭 몇 번 만으로 손쉽게 발급받으실 수 있습니다. 다시 네이버클라우드 콘솔로 이동해서 왼쪽의 메뉴바에서 Public IP 메뉴를 선택하셔서 공인 IP 발급 페이지로 이동합니다.
그 이후에는 다음과 같이 [+ 공인 IP 신청] 버튼을 클릭해서 서버를 선택하신 뒤 [다음 >] 버튼을 클릭합니다.
마지막으로 공인 IP를 발급받으려는 서버를 확인하시고 [생성] 버튼을 클릭하시면 공인 IP 발급이 완료됩니다. 여기서 주의할 점은 공인 IP 사용시 월 이용료가 발생한다는 점입니다. 네이버클라우드에서 친절하게 월 이용료에 대한 안내를 제공해주고 있어서 놓치지 않고 주의할 수 있다는 장점이 있습니다.
2. 도메인 주소 만들기
공인 IP를 발급받은 뒤에는 도메인 주소를 만들어야 합니다. 도메인 주소는 여러 호스팅 서비스 업체에서 발급받을 수 있는데 대표적인 업체로는 가비아, 카페 24 등이 있습니다.
만약 무료로 사용하고 싶으시다면 noip라는 사이트를 이용하시면 됩니다. noip 사이트를 이용하면 하나의 호스트에 대해 무료로 사용하실 수 있습니다. 대신 30일 주기로 계속 사이트로 접속해서 업데이트해줘야 한다는 단점이 있습니다.
🤔 잠깐, 무료 호스팅을 사용해도 괜찮을까?
사실 왠만하면 무료 호스팅 서버는 대부분 사기이므로 사용하지 않는 것이 좋습니다. 도메인 주소를 발급받으려면 네이버클라우드에서 발급받은 공인 IP를 업체에 제공해야 하는데 이때 불법적인 호스팅 서버에 제공한다면 네트워크 스캐닝이 일어나서 서버가 해킹당할 위험이 있습니다.
네이버클라우드에서 실시간으로 서버에 대한 모니터링을 하고 있기 때문에 크게 위험할 일은 없지만 이런 리스크에 대한건 미리미리 예방하는 것이 좋습니다. 만약 이러한 불법적인 네트워크 스캐닝이 일어난다면 네이버클라우드 측에서 서버 보호를 위해 서버를 강제로 중지시키고 서버 반납 요청에 대한 연락을 받게 됩니다.3. SSL 인증서 발급받기
도메인까지 생성했다면 다음으로는 SSL 인증서를 발급받으면 됩니다. SSL 인증서를 발급받는 방법은 다양한데 저는 certbot이라는 프로그램을 이용해서 간편하게 발급받는 방법에 대해 소개해 드리도록 하겠습니다.
certbot은 인증서를 쉽게 발급받고 설정파일까지 변경해주는 파이썬으로 개발된 간편한 모듈입니다. 리눅스 커널 정보에 따라 설치 방법이 다르기 때문에 각 환경에 맞게 검색해서 설치해 주시면 됩니다. 저는 우분투 환경이기 때문에 우분투 명령어로 설치를 진행하도록 하겠습니다. certbot은 다음과 같이 설치할 수 있습니다.
sudo add-apt-repository ppa:certbot/certbot sudo apt-get install python-certbot-nginx
certbot 설치가 완료되었다면 certbot이 동작할 수 있도록 Nginx의 기본 설정들을 변경해주도록 합니다. 설정 파일의 위치는 다음과 같습니다.
$ sudo cd /etc/nginx/sites-available
해당 경로로 이동했을 때 만약 default 파일이 있다면 해당 파일을 사용해주시면 되는데 저는 그냥 깔끔하게 지우고 myapp.conf라는 파일을 새로 만들어서 사용하도록 하겠습니다.
$ sudo rm default $ sudo vi myapp.conf
myapp.conf의 파일내용은 다음과 같이 입력해줍니다.
server { server_name 도메인 주소 입력; location / { root 프로젝트 경로 입력; index index.html; try_files $uri $uri/ =404; } }
그 이후에는 심볼릭링크로 연결하여 추후에 활성화 여부를 확인할 수 있도록 해주고 nginx를 재시작합니다.
$ sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/myapp.conf $ systemctl restart nginx
모든 설정이 끝났으므로 certbot을 실행해 보겠습니다. 파일을 닫고 아래와 같이 명령어를 입력해 주시면 됩니다.
$ sudo certbot --nginx -d 도메인 주소
해당 명령어만 실행해 주면 자동으로 인증서를 발급받게 되어 빠르고 쉽게 https로 도메인 주소에 접속할 수 있게 됩니다.
📲 PUSH 알림을 받기 위한 디바이스 토큰 등록 로직 삽입하기
다음으로는 PUSH 알림을 받기 위한 디바이스 토큰 등록 로직 삽입하는 방법에 대해 알려드리겠습니다. 디바이스 토큰 등록하는 API는 네이버클라우드에서 제공하고 있는데 백엔드 로직에서 푸는 것이 안전하지만 여기서는 살짝 편법으로 사용할 수 있는 방법을 알려드리겠습니다.
먼저 저희는 이전에 설치한 리액트 CRA의 PWA 템플릿을 이용할 예정인데요. 만약 준비되지 않았다면 아래 링크를 참고해서 준비해 주시기 바랍니다.
세팅이 완료돼있다면 App.js 파일을 찾아 상단에 다음과 같이 입력해 줍니다.
import setupAlarm from './setupAlarm'; function App() { const isInStandaloneMode = () => window.matchMedia('(display-mode: standalone)').matches; if (isInStandaloneMode()) { setupAlarm(); } ... }
코드에 대해 설명드리자면 먼저 isInStandaloneMode 함수는 웹 앱이 standalone 모드로 실행될 때 setupAlarm()을 실행하도록 합니다.
Standalone 모드는 Progressive Web App (PWA) 또는 웹 앱이 실행되는 모드를 나타냅니다. 사용자가 앱을 설치한 후 웹 앱을 홈 화면이나 앱 목록에서 시작할 때, 일반적으로 브라우저 창이 아닌 독립적인 창에서 웹 앱이 실행됩니다. 이 독립적인 실행 모드를 "standalone" 모드라고 합니다.
Standalone 모드에서만 실행되게 하는 이유는 앱을 설치한 후에 standalone 모드로 실행했을 때 디바이스토큰이 달라지기 때문입니다. 따라서 크롬 앱으로 사이트에 접속했을 때와 설치 후 standalone 모드로 실행했을 때는 서로 다른 디바이스 토큰을 얻게 되므로 저희가 사용하는 스마트폰에서 알람이 발생시키도록 하려면 standalone 모드일 때의 디바이스 토큰을 획득해야 합니다.
setupAlarm() 함수는 제가 만들어놓은 setupAlarm.js모듈파일의 함수인데요. 이 파일 역시 이전 포스팅 링크에 설명되어 있지만 저는 여기서 조금 더 심화된 코드로 작성해 볼 예정이므로 아래 코드로 다시 참고하시면 좋을 것 같습니다.
// firebase 초기화 코드 생략... 이 부분은 지난 포스팅 참조. export default async function setupAlarm() { const permission = await Notification.requestPermission(); if (permission === "denied") { console.log("알림 권한 허용 안됨"); return; } const token = await getToken(messaging, { vapidKey: process.env.REACT_APP_VAPID_KEY, }); if (localStorage.getItem("token") === token) return; await removeDeviceToken(process.env.REACT_APP_USER_ID); const isOk = await registerDeviceToken(process.env.REACT_APP_USER_ID, token); if (isOk) { registerSchedule(process.env.REACT_APP_SCHEDULE_CODE); localStorage.setItem("token",token); } };
지난 포스팅에서는 setupAlarm() 함수에서 알람 허용 팝업 띄우기 그리고 디바이스 토큰 등록 로직만 있었다면 이번에는 로컬 스토리지에 토큰을 저장하였습니다. 이렇게 하면 네이버클라우드로 계속해서 API호출하는 것이 아닌 앱 설치 후 처음 실행할 때만 API를 호출하므로 조금 더 효율적으로 코드를 작성할 수 있어서 좋습니다.
또한 디바이스토큰이 성공적으로 등록된다면 스케줄 코드까지 자동으로 등록되도록 수정하였습니다. 스케줄코드를 바깥에서 API로 호출하는 것이 아닌 앱을 실행할 때 자동으로 등록해 준다면 네이버클라우드 콘솔에서 시간만 바꿔주면 훨씬 더 편리하게 사용하실 수 있게 됩니다.
단, 이 코드는 하나의 디바이스에서만 동작하도록 설계했는데요. 저는 다른 누군가가 제 서버에 접속해 알람을 받는 일이 없도록 디바이스 토큰을 하나만 저장할 수 있도록 수정했습니다. 만약 제 디바이스로 알람이 안 온다면 누군가가 인터셉터했다는 의미로 볼 수 있습니다. 여러 디바이스에서 받고 싶도록 하고 싶으시다면 이전 포스팅에서 구현한 것처럼 계속 디바이스 토큰을 저장하도록 구현하는 것도 하나의 방법입니다.
removeDeviceToken, registerDeviceToken, registerSchedule 함수들은 전부 네이버클라우드 SENS 서비스의 PUSH API 스펙을 참고하여 만든 내용이므로 이곳에서 자세히 다루지는 않겠습니다. 만약 코드를 참고하고 싶으시다면 제 레포지토리를 참조하셔도 좋습니다.
📱 앱 빌드 및 배포하기
코드까지 완성했다면 이제 빌드하고 배포해야 할 차례인데요. React CRA에서는 다음과 같이 빌드할 수 있습니다.
> npm script-run build
프로젝트 루트 경로에서 실행해 주시면 빌드가 실행되고 프로젝트 바로 아래 build 폴더가 생성된 것을 확인할 수 있습니다. 이 폴더를 nginx가 설치된 서버로 옮기도록 하겠습니다. 폴더를 서버로 옮길 때는 파일질라나 MobaXterm을 이용하시면 됩니다.
앞서 Nginx의 myapp.conf 파일을 수정할 때 프로젝트 경로를 입력하게 되어있었는데요. 이 경로에 build 폴더를 넣어주시면 됩니다. 저는 이런 식으로 만들어서 넣어주었습니다. today-i-learned-alarm이 제 프로젝트 이름입니다.
location / { root /home/chucoding/today-i-learned-alarm/build; index index.html; try_files $uri $uri/ =404; }
그리고 myapp.conf 파일을 다시 열었을 때 뭔가 바뀌어있는 것을 확인할 수 있는데 저희가 certbot을 이용해 인증서를 발급받을 때 certbot이 자동으로 myapp.conf 파일을 수정한 것을 확인하실 수 있습니다.
이제 Nginx 서비스를 다시 재시작하시면 되는데 그전에 CORS 에러를 해결해야 합니다. 자바스크립트에서 fetch를 통해 네이버클라우드로 곧바로 API 요청을 보내면 CORS 오류가 발생하는데 이는 브라우저 정책에 의해 서로 같은 서버 내에 위치하지 않으면 아니면 호출이 불가능하도록 막아놓은 정책입니다.
쉽게 얘기해서 네이버클라우드 서버와 Nginx로 띄운 프로젝트 서버가 같은 서버가 아니기 때문에 보안적으로 연결이 불가능합니다. 하지만 이를 우회하는 방법이 있습니다. 바로 Nginx의 리버스 프록시 기능을 사용하는 것인데요.
리버스 프록시란 클라이언트와 웹 서버 간의 중개자 역할을 하는 서버로, 클라이언트로부터의 요청을 대신 받아 웹 서버에 전달하고, 웹 서버의 응답을 클라이언트에게 전달하는 역할을 합니다. 따라서 저희가 배포할 앱에서 요청이 발생하면 바로 네이버클라우드로 전달하는 것이 아니라 Nginx에서 대신 받아서 네이버클라우드에게 전달하도록 우회하도록 만듭니다. 이렇게 되면 CORS오류를 우회적으로 피할 수 있게 됩니다.
그래서 특정 경로로 접속하면 해당 경로에 대해 리버스 프록시가 발생하도록 myapp.conf 파일에서 location을 다음과 같이 추가합니다.
server { server_name 도메인 주소 입력; location / { root /home/chucoding/today-i-learned-alarm/build; index index.html; try_files $uri $uri/ =404; } location /push/v2/services/서비스 ID { # 네이버클라우드 SENS API 엔드포인트 proxy_pass https://sens.apigw.ntruss.com; } }
이렇게 설정하면 /push/v2/services/서비스 ID 경로로 호출하는 모든 요청은 리버스 프록시를 통해 네이버클라우드의 SENS 서버로 요청이 들어가게 되어서 CORS오류가 발생하지 않게 됩니다. 이제 정말로 모든 설정이 끝났으므로 서비스를 재시작하고 실제 동작을 테스트 해보도록 하겠습니다.
systemctl restart nginx
이제 앱을 직접 설치해서 접속해 보시면 됩니다. 만약 잘 안되시거나 하시면 /var/log/nginx/access.log 파일을 통해 API가 제대로 호출이 되고 있는지 등을 트러블슈팅 해보시면 됩니다. 그럼 제가 만든 앱을 간단하게 보여드리고 마무리하도록 하겠습니다.
🌠 회고하기
이번에 네이버클라우드 서비스들을 이용해서 안드로이드, IOS 그리고 백엔드까지 모조리 없애고 오로지 자바스크립트와 웹 서버 만으로 알람 PUSH 기능을 가진 앱을 개발해 보는 것을 도전해 보았는데요.
이전까지는 웹앱에 대한 개념을 막연히만 알고 있었더니 PWA와 Standalone을 이번 경험을 통해 새로 접했기 때문에 다소 시간이 걸렸었던 점이 아쉬웠습니다. 하지만 이번 기회에 더 자세하게 공부할 수 있어서 좋았습니다.
그리고 확실히 백엔드가 없으니까 보안적으로 많이 취약함을 느낄 수 있었습니다. 이렇게 만든 앱은 URL이 노출되면 누구나 접속해서 쉽게 정보를 얻을 수 있다는 점이 아쉬웠습니다. 그래서 이번 경험을 통해 백엔드의 필요성을 다시 한번 실감하게 되었고 다음에 만약 서비스를 발전시키거나 한다면 로그인 기능을 추가하고 안전하게 백엔드 서버에서 네이버클라우드 API를 호출해야겠다는 생각이 듭니다.
'Infra > ncloud' 카테고리의 다른 글
Streamlit 챗봇 외부접속 가능하도록 배포하기 - 네이버클라우드 활용 (2) 2024.08.12 CLOVA OCR을 활용한 타임트래커 수집 (70) 2024.01.28 안드로이드, IOS 지식 없이 SENS로 알림(PUSH) 서비스 개발하기 (84) 2023.10.15 CLOVA Chatbot 카카오톡 연동하기 (18) 2023.08.30 CLOVA Chatbot으로 간단한 자기소개봇 만들기 (46) 2023.08.19