Digital Ocean에서 Nginx으로 Node.js-MongoDB 앱 배포하기


이전 글에서 블로그를 플랫폼을 Heroku에서 클라우드 컴퓨팅 서비스 제공업체인 Digital Ocean으로 옮겼는데 그 과정에 사용했던 방법입니다.

Droplet 만들기

우선 Digital Ocean에 가입하면 우측 상단에 Create 버튼이 있습니다. 버튼을 클릭하면 여러 옵션이 나오는데 가장 위에 있는 Droplets을 선택해 줍니다. OS는 Ubuntu 20.04를 선택해주고 가격 정책과 데이터센터 리전은 필요에 따라 선택해 줍니다. 이제 외부에서 서버에 접근하기 위한 방법을 선택해야 하는데 SSH를 사용하는것이 좋습니다. Authentication에서 SSH Key를 선택해줍니다. Public Key를 요구할텐데 Linux/Mac 사용자는 내장 터미널을 사용하면 되고 Windows 사용자는 Putty를 사용하는것을 추천합니다. (윈도우10부터는 Open SSH를 지원하기 때문에 powershell을 쓰는것도 가능합니다.)

내장 터미널을 사용하는 경우 터미널에서 아래 명령어를 실행해줍니다.

ssh-keygen

몇 가지를 물어볼텐데 원하는대로 입력해주면 key를 생성할 수 있습니다. 이후 설정한 위치에 있는 .pub파일에 public key를 Digital Ocean에 입력해주면 됩니다. 설정을 완료한 뒤 Droplet Create를 눌러 droplet을 생성해줍니다. Droplet을 생성하면 해당 Droplet의 ipv4주소가 주어지는데 아래 명령어의 123.123.123 대신 주어진 ip를 입력하면 droplet에 접속할 수 있습니다.

ssh [email protected]

방화벽 설정

허용된 포트를 제외한 접근을 제한하기 위해 우분투 방화벽을 설정해줍니다. 현재 SSH 연결을 하고있으므로 SSH 포트(22)를 허용해야 합니다.

ufw allow OpenSSH
ufw enable

방화벽 설정을 확인하려면 ufw status명령어를 사용하면 아래와같이 허용된 포트를 볼 수 있습니다.

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Superuser 만들기

처음 접속한 root유저는 관리자 계정으로 모든 권한을 갖고 있습니다. 웹앱을 관리자 계정에서 실행시키면 해킹이나 오작동이 일어났을 때 피해가 더 커질수 있기 때문에 좀 더 적은 권한을 갖고 있는 일반 계정을 사용하는 것이 좋습니다. 새로운 일반 계정을 만들기 위해서는 adduser 명령어를 사용하면 됩니다.

adduser new-user

패스워드를 포함해서 몇가지 정보들을 입력하면 새 유저를 생성합니다. 새 유저로 접속하기 위해서는 su(switch user) 명령어를 사용하면 됩니다.

su new-user

이제 일반 권한을 가진 유저로 조금더 안전하게 작업을 할 수 있습니다. 하지만 일반유저는 관리자 권한을 필요로 하는 작업이 필요할 때마다 root유저로 변경해야 하는 번거로움이 있습니다. 이를 해결하기 위해서 새로 만든 계정을 필요할 때에만 관리자 권한을 취득할 수 있는 superuser로 만들어야 합니다. Superuser는 관리자 권한이 필요한 명령어 앞에 sudo를 입력하면 해당 명령어에 한해서 관리자 권한을 갖습니다. 방금 만든 new-user를 superuser로 만들어주기 위해 우선 root계정으로 돌아가서 아래 명령어를 실행해줍니다.

usermod -aG sudo new-user

위 명령어는 new-user계정을 sudo그룹에 추가시켜 new-user가 sudo를 사용할 수 있게 해줍니다. 다시 su new-user를 입력해 새 계정으로 접속해줍니다. 앞으로는 새로 만든 계정으로 진행하기 때문에 관리저 권한이 필요한 명령어 앞에는 sudo가 있습니다.

커스텀 도메인 설정하기

웹앱에 접근할 때마다 브라우저에서 ip주소를 입력해서 접속할 수는 없기 때문에 도메인을 연결해줘야 합니다. 이를 위해서는 우선 도메인 등록 대행업체에서 커스텀 도메인을 구입해야 합니다. 커스텀 도메인을 갖고 있다면 Digital Ocean의 Networking -> Domains에서 구입한 도메인을 추가해 줍니다. 이제 해당 도메인을 Digital Ocean에서 관리할 수 있도록 도메인 등록 대행업체에서 구매한 도메인의 네임서버를 디지털 오션의 네임서버로 바꿔줘야 합니다. 이 과정은 도메인 등록 대행업체에 따라 대동소이하기 때문에 본인이 사용하는 도메인 등록 대행업체에 맞춰서 네임서버를 변경해줘야 합니다. 일부 큰 대행업체들에 대해서는 Digital Ocean의 공식 문서에서 바꾸는 방법을 확인할 수 있습니다. 네임서버를 바꾸고 나서 적용이 되기까지는 일정 시간(15분 이상)이 걸립니다. 마지막으로 디지털 오션에서 도메인 레코드를 2개 생성해줘야 합니다. 우선 A 레코드를 HOSTNAME에는 @를 입력하고 WILL DIRECT TO에는 만들었던 Droplet을 선택해 줍니다. 다음으로 CNAME 레코드를 만들고 HOSTNAME에는 www, WILL DIRECT TO에는 자신의 도메인(cloudless.blog)을 입력한 후 저장해줍니다.

Node.js 앱 실행하기

앱이 Node.js와 MongoDB를 사용하므로 둘을 먼저 설치해줘야 합니다.

Node.js 설치

Node.js v14는 아래 명령어로 설치합니다. 만약 다른 버전 설치가 필요하면 여기에서 원하는 버전을 찾을 수 있습니다.

curl -fsSL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt install build-essential

아래 명령어를 실행했을 때 설치한 버전이 나오면 정상적으로 설치된 것입니다.

node --version

MongoDB 설치

이제 mongoDB 커뮤니티 버전을 설치해줍니다. 아래 명령어는 Ubuntu 20.04에 MongoDB 4.4를 설치하는 명령어입니다. OS나 MongoDB의 버전이 다르다면 공식 매뉴얼에서 해당되는 내용을 찾을 수 있습니다.

wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
sudo apt-get update

sudo apt-get install -y mongodb-org

# 아래 명령어들은 의도적이지 않은 업그레이드를 방지하기 위한 것입니다.
echo "mongodb-org hold" | sudo dpkg --set-selections
echo "mongodb-org-server hold" | sudo dpkg --set-selections
echo "mongodb-org-shell hold" | sudo dpkg --set-selections
echo "mongodb-org-mongos hold" | sudo dpkg --set-selections
echo "mongodb-org-tools hold" | sudo dpkg --set-selections

아래 명령어를 실행했을 때 설치한 버전이 나오면 정상적으로 설치된 것입니다.

mongod --version

설치한 버전이 제대로 나왔다면 아래 명령어로 mongoDB를 실행시켜줍니다.

sudo systemctl start mongod

PM2

이제 배포하려는 앱을 원격 깃 저장소에서 clone해줍니다.

cd /~
git clone https://github.com/Cloudless67/MyBlogNodeExpress.git

프로젝트 폴더에 cd명령어를 이용해 들어간 뒤 npm install 명령어로 필요한 의존성을 설치해줍니다. 의존성 설치가 완료되면 npm start명령어로 Node.js 앱을 실행할 수 있습니다. 하지만 이렇게 실행했을 때는 콘솔을 쓸 수 없기 때문에 PM2 패키지를 통해 백그라운드로 앱을 실행시켜 줍니다.

sudo npm -g pm2

이제 pm2로 앱을 실행하면 앱이 백그라운드에서 돌아갑니다.

pm2 app.js # 또는 index.js ...

Nginx 리버스 프록시 설정

하지만 외부에서는 아직 접근할 수 없기 때문에 Nginx를 이용해 외부에서 들어오는 요청을 내부 포트로 넘겨줘야 합니다. 우선 아래 명령어로 Nginx를 설치해 줍니다.

sudo apt install nginx

이제 root 계정에서 방화벽에서 80번과 443번 포트를 열어줍니다.

ufw allow 'Nginx Full'

만약 설치가 성공적으로 완료됐다면 웹브라우저에서 서버의 IP만 입력했을 때 기본적인 Nginx의 fallback페이지를 볼 수 있어야 합니다.

Nginx는 기본적으로 1개의 서버 블록을 가지고 있는데 확장을 고려해서 새로운 서버 블록을 만드는 것을 권장합니다. /etc/nginx/sites-available/폴더 아래에 설정파일을 새로 만들어줍니다. example.com 대신 본인이 갖고있는 도메인으로 바꿔주면 됩니다. nano 대신 vim을 써도 상관 없습니다.

sudo nano /etc/nginx/sites-available/example.com

그러면 텍스트 파일을 편집할 수 있을텐데 아래 내용을 입력해줍니다.

server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        proxy_pass http://localhost:3000;    # 3000을 앱이 사용하는 포트로 바꿔주면 됩니다.
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

파일을 저장하고 (nano의 경우 ctrl+x, y, Enter를 입력하면 됩니다)sites-enabled폴더에 소프트 링크를 만들어줍니다.

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

이제 sudo systemctl reload nginx로 Nginx를 다시 로드하면 설정이 정상적으로 적용됩니다. 드디어 브라우저에서 도메인으로 웹앱에 접속이 가능해집니다!

HTTPS

마지막으로 https를 사용하기 위해 certbot으로 Let's Encrypt의 SSL 보안 인증서를 설치해 줍니다. 아래 명령어로 certbot을 설치해 줍니다.

sudo apt install certbot python3-certbot-nginx

certbot의 Nginx플러그인을 사용하면 쉽게 SSL 인증서를 취득할 수 있습니다.

sudo certbot --nginx -d example.com -d www.example.com

이후 certbot이 시키는대로 진행하면 됩니다. 중간에 certbot이 http연결을 자동으로 https로 리다이렉트 할지 물어보는데 원하는 설정을 선택하면 됩니다. 과정이 완료되면 이제 https://www.example.com 으로 웹에서 접근이 가능해집니다.

참고 문서

Digital Ocean 공식 문서