SSR 배포 전략 with EC2, CloudFront, pm2, NGINX (1)

이전 글에서 AWS의 S3, CloudFront를 이용해 CSR 프로젝트를 배포하고 Github-Actions를 통해 간단한 자동화를 구축해보았다. 이번에는 Next.js로 만든 프로젝트를 배포하기 위해 S3가 아닌 EC2를 사용하고 NGINX 리버스 프록시로 HTTPS 적용 등의 다양한 기능을 사용해보려 한다 👏.

쓰다보니 길이 너무 길어질 것 같아서 pm2로 무중반 배포까지만 설정하고 다음 글에서 NGINX, 도메인 설정 등을 진행해볼 것이다.

이번 글
1. EC2 인스턴스 생성
2. SSH 인스턴스 연결
3. 인스턴스 기초 세팅 및 pm2 무중반 배포 설정


다음 글
1. 도메인 구입
2. NGINX 설정
3. HTTPS 적용

📝 SSR 배포 전략

CSR은 SPA 방식과 자주 사용된다. SPA 방식은 하나의 index.html을 갖고 JS로 정적 렌더링을 하기 때문에 정적 웹사이트 배포에 최적화 되어 있다. 이와 달리 Next.js는 매번 서버에서 HTML을 생성해 렌더링 하기 때문에 기존의 S3 + CloudFront 방식과는 다른 배포 방식이 필요하다.

EC2 배포는 가상 컴퓨팅 환경에서 서버를 가동시키는 것이므로 로컬에서 할 수 있는 거의 모든 일을 수행할 수 있다. 단순 정적 자원 전달용으로 사용외에도 DB를 직접 구축하거나 네트워크 액세스 권한을 관리하는 등 다양한 작업들이 가능하다. 왜냐면 AWS의 컴퓨터 한 대(인스턴스)를 대여해서 사용하는 것이기 때문에 컴퓨터로 할 수 있는 일들을 거의 다 할 수 있기 때문이다.

AWS EC2에 인스턴스 생성

AWS의 가상 컴퓨터 한 대를 빌리기 위한 작업을 해보자!
AWS에서 EC2 검색한다. 아직 템플릿이 없으므로 인스턴스 시작을 누른다.

AMI 선택

An Amazon Machine Image (AMI) provides the information required to launch an instance. You must specify an AMI when you launch an instance. You can launch multiple instances from a single AMI when you need multiple instances with the same configuration. You can use different AMIs to launch instances when you need instances with different configurations.

Amazon Machine Image(AMI)을 선택해야 한다. AMI란 인스턴스를 시작할 때 정보를 캡쳐하고 이미지화한 템플릿으로 해당 정보를 재사용하고 싶을 때 유용하게 사용할 수 있는 느낌이다. 참고

다양한 AMI가 있지만 연습하기엔 Ubuntu Server 20.04 LTS 혹은 Ubuntu Server 18.04 LTS를 많이 사용하는 것 같다.

인스턴스 유형 선택

AWS에 따르면 인스턴스 유형은 CPU, 메모리, 스토리지 및 네트워크 용량을 조합한 다양한 선택지를 의미한다고 한다. 연습용으로는 굳이 좋은 용량이 필요 없기 때문에 t2.micro를 선택한다.

검토 및 시작이 아닌 다음: 인스턴스 세부 정보 구성을 눌러 다음으로 넘어간다.

인스턴스 세부 정보 구성

[인스턴스 세부 정보 구성]에서는 EC2가 어느 네크워크에 속할 것인지, 해당 네트워크 속의 어느 서브넷에 속할 것인지를 설정하는 파트이다.

  • VPC(Virtual Private Cloud)EC2가 속할 네트워크를 의미한다. 이름 그대로 Private 하기 때문에 정해진 사용자만이 접근할 수 있는 AWS 내부망이라고 이해하면 될 것 같다.
  • 서브넷은 VPC에서 한번 더 나눈 그룹을 의미한다.
  • 외부에서 접근할 IP가 필요하기 때문에 퍼블릭 IP 자동 할당활성화 한다.

검토 및 시작이 아닌 다음: 스토리지 추가 > 다음: 태그 추가 로 넘어간다.

태그 추가


태그는 필수로 하지 않아도 되지만 EC2 인스턴스들이 많아지게 되면 키워드 검색을 통해 더 손쉽게 인스턴스를 찾을 수 있으므로 설정하는 것이 좋다.

다음: 보안 그룹 구성으로 넘어간다.

보안 그룹 구성

보안 그룹 구성은 EC2 인스턴스에 접근할 수 있는 프로토콜과 포트를 정하는 파트이다. 0.0.0.0/0 이라고 지정하면 IP 와 관계 없이 설정한 프로토콜과 포트로 접근하는 모든 사람의 접근을 허용한다는 뜻이다.

새 보안그룹 생성 후 HTTP, HTTPS 는 모든 IP가 접근하도록 하고 SSH만 내 IP를 설정해준다.

인스턴스 시작 검토

인스턴스 시작 검토에서 전체적으로 문제가 없는지 확인하고 시작하기를 누른다.

기존 키 페어 선택 또는 새 키 페어 생성

이제 AWS로부터 키 페어를 발급받는다. 키 페어서버 인스턴스에 SSH 접속을 위해 꼭 필요하다 한다. 한 번밖에 다운받지 못하므로 소중하게 보관하자.

키 페어를 다운받고 인스턴스를 시작했더니 인스턴스가 잘 생성된 것을 확인할 수 있었다.

SSH로 인스턴스 연결하기

SSH (Secure Shell Protocol)

SSH이란 두 컴퓨터 간의 통신을 할 때 보안적으로 안전하게 암호화하여 통신할 수 있는 프로토콜이다. 데이터를 전송하거나 원격 제어 때 주로 사용되는데 여기서는 가상 컴퓨터에 안전하게 접속하여 명령을 내리기 위해 SSH 프로토콜로 연결할 것이다.

생성한 인스턴스를 클릭 후 우측 상단의 연결을 클릭한다.

인스턴스에 연결하는 다양한 방법들 중 [SSH 클라이언트] 탭에서 하라는 대로 해보자.

mac일 경우 터미널을 연다음 다운받은 .pem 파일이 있는 곳으로 이동 후 알려준대로 명령어를 입력한다. 윈도우의 경우 PowerShell을 사용하면 편하다고 한다.

$ chmod 400 키페어 파일 이름.pem
$ ssh -i ...

명령어를 다 입력하면 계속 연결할거냐고 물어본다. yes로 응답한다.

성공적으로 인스턴스와 연결했다.

⚠️ SSH 연결 시 timed out 오류 발생

잘 진행하다가 노트북을 닫고 집으로 와서 다시 연결하려고 했더니 Opration timed out이 발생했다.

ssh: connect to host ec2-....ap-northeast-2.compute.amazonaws.com port 22: Operation timed out

간단한 검색 결과 다양한 원인이 있지만 내 경우 ip 주소가 변경되었기 때문에 접속이 실패했다고 생각되었다.

상단에 보안 그룹 구성에서 이미 SSH에 내 IP 소스를 설정해주었지만, IP주소를 다시 할당했을 때 변경되었다는 것을 알 수 있었다.

[인스턴스] 클릭 -> [보안] 탭에서 [보안 그룹] 클릭

인바운드 규칙 편집 > 내 IP 를 눌러 IP를 다시 설정한다.

이제 똑같은 방법으로 SSH 연결을 시도하면 무사히 접속된다.

다만 이 방법은 임시방편이고 IP는 유동적으로 변하기 때문에 IP를 고정시켜주는 처리를 따로 해야 한다. 이러한 문제점은 EC2 옵션 중 Elastic IPs로 해결할 수 있다고 한다. 자세한 것은 EC2에 고정아이피 Elastic IPs 부여하기를 참고하면 된다. 주의할 점은 EIP 사용은 무료지만 사용하지 않을 경우 요금이 청구되기 때문에 이 부분은 키워드만 얻고 실제 필요할 때 사용해보는 걸로 ㅎㅎ

배포 준비

인스턴스에 프로젝트 세팅하기

AWS로부터 가상 컴퓨터 한 대를 소중히 빌려왔으니 우리의 Next.js 프로젝트를 인스턴스에 clone, build 까지 해보자.

그 전에 우리 프로젝트에서 사용한 다양한 프로젝트 세팅을 맞춰줘야 한다.

Node.js를 설치하기 전에 버전 관리를 위해 nvm을 먼저 설치한다.

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash

nvm 설치 후 Command "nvm" not found 오류가 발생했고 nvm 설정을 추가하지 않아서 나타나는 오류라 한다.

$ source ~/.bashrc

확인

$ nvm -v

nvm을 통해 node를 설치하자. clone할 프로젝트가 특정 Node 버전을 사용한다면 해당 버전으로 use 해주자.

$ nvm install node
  • yarn 설치
    yarn으로 dependency를 관리하기 때문에 추가로 설치해주었다.
$ npm i -g yarn
  • 레포지토리 clone
$ git clone 레포지토리 클론 주소

ls로 현재 위치의 파일/폴더를 확인해보면 방금 받은 레포지토리의 이름이 있을 것이다.

$ cd 레포지토리 # 해당 레포지토리로 이동

패키지 다운받고 build 한다.
-> 이 부분은 본인 프로젝트의 package.json을 참고하자.

$ yarn install
$ yarn build
$ yarn dev

여기까지 문제없이 잘 진행된 것을 확인할 수 있다!!!! 🎉🎉🎉🎉

pm2로 무중단 배포 설정

pm2는 Node.js의 프로세스 매니저이며 아래와 같은 장점이 있다. (참고)

  • 프로세스를 관찰하다 프로세스가 종료되면 다시 실행
  • 파일 수정 시, 자동으로 재시작
  • cluster라는 기능으로 CPU 코어 수만큼 프로세스 동시 지원.
  • 백그라운드에서도 실행 유지
  • 오류가 나도 자동으로 다시 시작

yarn global add로 pm2를 설치하면 별도의 PATH 설정을 해주어야 한다고 해서 npm으로 pm2를 설치했다.

$ npm i -g pm2

pm2로 배포한다.

$ pm2 start yarn  -w -i 0 --name "next" -- start
  • -w: 파일 변경 시 자동으로 재시작
  • -i 0: CPU 코어 수만큼 프로세스를 생성, ex) -i max: 모든 CPU 확장
  • --name "next": 이름을 next로 하겠다~

여기까지 하더라도 Public IPv4 DNS 주소로 접속했을 때 배포가 제대로 안되어 있을 것이다. 왜냐면 http 프로토콜로 배포했을 때 포트번호는 80번이어야 되는데 현재 3000번 포트에서 실행되고 있기 때문이다. 이 부분은 Reverse Proxy라는 것을 통해 해결할 수 있다.

Reverse Proxy

Reverse Proxy는 간단히 말해 client에게 전송된 응답을 중간에 가로채서 Proxy가 응답을 해주는 것과 같이 작동한다. client는 Proxy를 통해 응답을 받기 때문에 서버의 정보를 알 수 없게 된다. 즉 서버가 노출되지 않도록 도와준다.

이러한 Reverse Proxy를 이용해 3000 포트를 80번으로 돌릴 것이다. 인스턴스 AMI를 Ubuntu로 설정하면 기본적으로 Redirect를 지원해주기 때문에 별도의 NGINX를 사용하지 않아도 된다고 하지만, 도메인 설정이나 https 설정을 위해 NGINX를 사용할 것이다.

단순히 3000포트를 80번으로 배포처리만 할 거라면 아래와 같이 Reverse Proxy를 설정한다.

$ sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000

여기까지만 하더라도 http로 퍼블릭 IPv4 DNS에 접속할 수 있다.

⚠️ 다만 NGINX 사용법이나 SSL 설정들을 알고 싶다면 위와 같이 Reverse Proxy를 설정하지 말고 다음에 이어질 글을 참고한다.

💡 참고

ec2의 ubuntu에서 nvm 설치하기
React 앱에 Next.js 끼얹기 + EC2 배포하기
AWS EC2로 Next.js 배포하기

좋은 웹페이지 즐겨찾기