GooApp 백앤드 배포
GooApp 백앤드 배포 과정을 정리해보았다.
GooApp 프로젝트에서는 사용자의 점수를 기록하고 다른 사용자들과 점수 랭킹을 경쟁하는게 가장 중요한 기능이다.
랭킹 기능을 위해서는 백앤드 서버가 필요했고 가장 많이 사용해 익숙했던 Express.js를 선택해 만들었다.
AWS를 사용해본적이 단 한번이 없었기 때문에 이번 기회에 사용해보자 하고 어려운길을 선택하였다.
이번 글에서는 익숙하지 않은 배포과정을 더 기억하고 배우자는 마음으로, Express.js 백앤드 서버를 AWS EC2를 통해 배포하는 과정을 정리해보았다.
프로젝트 구성
사용한 기술 스택
- Express.js : 배포 대상 서버 프레임워크, 가장 익숙한 프레임워크라서 선택했다.
- Node.js : AWS 리눅스와의 버전 호환 문제로 16 버전을 사용했다.
- AWS EC2 : 클라우드 서버 환경, 가장 유명하지만 사용해본 적이 없어서 이번에 사용하기로 했다. (+ 프리티어 무료!)
- Nginx : 리버스 프록시 설정 (포트 노출 X, 로드 밸런싱, 트래픽 관리)
- PM2 : Node.js 프로세스 관리
- MongoDB Atlas : 클라우드 DB (서버 배포 불필요)
- SSL(HTTPS) : 도메인 필요, 이번 프로젝트는 보안 중요도가 낮아 미사용
구조 설명
기본적으로 EC2 클라우드 컴퓨터에 Express.js 서버를 실행하고 요청/응답을 처리한다.
Nginx를 사용하여 포트를 숨겼고, 사용자가 EC2의 Public IP로 요청을 보내면 Nginx가 자동으로 Express.js서버의 포트로 요청을 넘겨준다.
아직 로그인 기능 같은게 없어 보안이 중요하지 않기 때문에 Nginx의 보안적 기능들은 나중에 필요하게 되면 추가할 예정이다.
Node.js는 프로세스를 하나만 돌릴 수 있기 때문에 필요시 프로세스를 추가하기 위해 PM2를 추가해 관리하게 했다.
배포
배포 과정
- EC2 인스턴스 생성 (AWS 계정 생성은 스킵!)
- Node.js 설치(NVM 사용) 및 코드 가져오기 (git pull → npm install → .env 세팅)
- PM2설치 및 앱 실행 (pm2 start app.js)
- Nginx 설치 → 리버스 프록시 설정 → Nginx 시작
- 배포 작동 테스트
EC2 인스턴스 생성
AMI
AMI는 프리티어를 사용하기 위해서 무료 요금제의 모델을 찾아 선택했다.
AWS Marketplace AMI → 요금 모델 : 무료 선택 → Amazon Linux 무료 모델 선택 (요금에서 프리티어 확인)
(모든 AMI가 프리티어로 사용 가능한지도 모르겠다. 초보자 이슈)

(25년 7월부터는 프리티어 방식이 변경되었다고 한다. 이제 $200 크래딧으로 주나보다. AWS Free Tier)
인스턴스 유형
클라우드 컴퓨터의 성능을 선택해주어야 하는데 이번 프로젝트에서 크게 중요하지는 않으니 기본값 t3a.medium을 선택했다.
키 페어
로그인 보안을 위해 키 페어 파일을 생성해주어야 한다.
SSH로 연결해 사용하기 위해 .pem으로 새 키페어를 생성했다.

네트워크 설정
모든 사용자들이 EC2에 요청을 보낼 수 있게 만들기 위해서 HTTP/HTTPS 트래픽을 허용해줘야 한다. 추가로 SSH로도 접속하기 위해 SSH 허용도 해주었다.
보안 그룹 생성 → SSH, HTTP, HTTPS 트래픽 허용

탄력적 IP (고정 IP)
EC2 인스턴스는 기본적으로 시작할 때마다 IP가 변경된다.
인스턴스 재부팅과 상관 없이 IP를 고정해서 사용하기 위해서는 탄력적 IP 설정이 필요하다.
왼쪽 탭에서 탄력적 IP 주소로 들어가 탄력적 IP를 할당해준다.
생성한 IP 주소를 선택해 작업에서 탄력적 IP 주소 연결로 인스턴스와 연결해준다.

인스턴스 연결 테스트
이제 인스턴스를 시작하고 연결 테스트 해보자. 인스턴스 상태를 시작으로 바꾸고 연결에 들어간다.
EC2 인스턴스 연결 기본 상태로 연결을 누르면 터미널 페이지로 이동할 것이다. 👏👏

SSH 연결 및 설정 (옵션)
iTerm을 통해서 SSH의 별칭을 설정해 간편하게 EC2에 접속할 수 있다.
1. 권한 설정
생성한 키페어 파일을 소유자만 읽을 수 있도록 권한 변경한다.
chmod 400 my-key.pem
2. 일반 접속
ssh -i <'.pem' FilePath> <EC2_UserName>@<EC2_PUBLIC_IP>
- 인스턴스를 생성하며 만들었던 키페어 파일 경로 (.pem)
- EC2_UserName : 인스턴스 연결을 선택하면 설정할 수 있는 유저명 (기본
ec2-user) - EC2_Public_IP : 탄력적 IP에서 설정한 IP 주소 혹은 퍼블릭 DNS
3. SSH 별칭 설정
.ssh/config 파일에 별칭 설정을 한다.
vim ~/.ssh/config
Host <별칭>
HostName <EC2_PUBLIC_IP>
User <EC2_UserName>
IdentityFile <'.pem' FilePath>
- Host : 별칭으로 사용할 이름
- HostName : EC2에서 설정한 퍼블릭 IP or DNS
- User : EC2에서 설정한 유저명 (기본
ec2-user) - IdentityFile : 키페어 파일 경로 (.pem)
SSH 접속
ssh <별칭>

Node.js 설치 (NVM)
Node.js를 설치해야 하는데 버전 관리의 편의성을 위해서 NVM(Node Version Manager)를 사용했다.
(설치 후 터미널 재시작이 필요하다.)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
nvm --version
프리티어 AWS Linux 2버전에서는 상위 버전의 Node를 설치하지 못하는 문제가 있어서 16버전으로 설치했다.
(상위 버전이 필요하다면 AL2023 버전이나 도커를 사용해야 할 것 같다.)
항상 동일한 Node 버전으로 사용하기 위해서 설치한 Node 버전을 기본값으로 고정해줘야 한다.
nvm install 16
nvm use 16 # 현재 터미널 세션의 node 버전 설정
nvm alias default 16 # 터미널이 열릴 때 기본값 설정
코드 가져오기, 환경변수 설정
깃을 설치하고 깃허브에 올려놓은 프로젝트 파일을 불러오자.
# GIT 설치
sudo yum update -y
sudo yum install -y git
git --version
# 프로젝트 클론
git clone https://github.com/itismilob/GooApp.git
.env 파일을 생성하고 환경변수를 추가해주었다.
vim .env
이제 npm install 한 번 때려주고 테스트로 실행해보자.
퍼블릭 DNS:서버 포트로 접속하면 잘 작동 할 것이다.
PM2 설치 & 실행
Node를 멀티프로세스로 돌려주고 로그도 편리하게 확인 가능한 기능들을 가진 PM2를 설치해 사용했다.
지금은 사용자가 매우 적으니 프로세스는 당연히 하나만 돌리고있다.
npm install -g pm2 # pm2 글로벌 설치
$ pm2 -version # pm2 버전 확인
$ pm2 update # pm2 업데이트
pm2 start build/app.js # 프로젝트 시작
이제 우리는 프로세스 CPU, 메모리 사용 상태 등을 볼 수 있고 로그도 에러와 정상 로그로 분리해서 확인할 수 있게 되었다.
pm2 monit # 프로세스 상태 보기
pm2 log # 로그 확인
Nginx 설치 & 리버스 프록시 설정
마지막으로 Nginx를 추가해 리버스 프록시로 포트를 감추고 그냥 DNS 주소로 접속할 수 있도록 만들었다.
(설치 후 nginx를 한 번 실행해 정상적으로 연결되는지 확인하자.)
sudo amazon-linux-extras install -y nginx1 # nginx 설치
nginx -v # nginx 버전 확인
Nginx 설정 파일을 생성해서 포트가 없는 기본 요청에 리버스 프록시 설정을 해주었다.
/etc/nginx/conf.d/default.conf 커스텀 설정 파일 생성
server {
listen 80;
listen [::]:80;
access_log /var/log/nginx/reverse-access.log;
error_log /var/log/nginx/reverse-error.log;
location / {
proxy_pass http://127.0.0.1:<PORT>;
}
}
기본 설정 파일 /etc/nginx/nginx.conf에서 커스텀 설정 파일 include
http {
include /etc/nginx/conf.d/*.conf;
}
이렇게 해주면 EC2로 들어가는 기본 요청이 Nginx를 통해 localhost:서버 포트로 전달된다.
sudo systemctl start nginx
배포 후 점검
Postman을 사용해서 EC2 퍼블릭 DNS로 요청을 보내서 제대로 처리되는지 확인했다.

배포 성공 👏👏

