AWS EC2로 Next.js 배포하기

JoonPark·2023년 12월 21일
15
post-thumbnail

서론

Next.js는 Vercel이 개발하고 있고, 당연히 Vercel에 배포하는 것이 가장 효율적이라 믿어 의심치 않으며 다른 배포 방식은 생각치도 않았다.
그런 오만한 생각을 '효율' 또는 '선택과 집중' 이라는 키워드로 합리화 해왔을지도 모르겠다. 결국 Next.js 배포를 AWS로 배포를 해야만하는 상황이 벌어졌는데, 이 배워야 하는 과정이 멀고 험했다.
첫 배포 과정은 존경하는(?) 회사 팀장님의 도움으로 어렵지 않게 술술 진행하며 배포할 수 있었는데, 이 과정을 혼자 다시 시도해보며 복습하고, 또 블로그에 정리해 완전히 내 것으로 만드려 한다.

배포를 못하는 개발자가 동네에서만 축구하는 축구선수와 무엇이 다른가?

본론

요구 사항

  • 서버 컴포넌트, SSR기술이 적용된 Next.js를 AWS를 통해 배포해야한다.
  • 서버는 프리티어인 t2.micro, OS는 Linux Ubuntu를 사용한다.
  • SSH파일 .pem(Privacy Enhanced Mail) 파일을 사용해 원격으로 로그인 할 수 있어야 한다.
  • 따라서 보안 그룹은 80(http), 443(https), 22(ssh) 포트만 개방하여야 한다.
  • nginx를 설치하고 리버스 프록시 설정을 추가하여 지정된 도메인에 Next.js를 배포한다.

AWS EC2 인스턴스 생성

EC2란, 클라우드에서 OS를 가진 하나의 서버용 컴퓨터 시스템을 만드는 것이다.
말 그대로 물리적인 서버 컴퓨터를 갖거나 VMware로 서버용 OS를 설치하는 것과 다른게 없지만,
AWS에서는 '온디맨드 확장 가능'을 특징으로 수요자에게 초점을 맞추어 용량이 자동으로 늘어나고, 그만큼 요금 청구를 더 시켜준다는 부분에서 차이가 있다.
물론 더 깊게 공부하여 이해를 할 수도 있지만, 내가 정한 로드맵 목표까지만 이해하는 것으로 하자.

1. 먼저 AWS 계정으로 EC2 서비스를 생성

EC2 서비스 생성 자체는 전혀 어렵지 않다. 다만 리전은 우리가 사는 서울로 하는게 좋다.

2. 보안 그룹 추가

보안 그룹을 추가하여 어떤 클라이언트가 들어올 수 있고, 어떤 데이터가 나갈 수 있는지 정한다. 여기서는 일단 인 바운드 그룹만 규칙을 설정하도록 한다

  • 인 바운드 그룹 : 클라이언트가 자신의 서버 데이터에 들어올 수 있는 규칙
  • 아웃 바운드 규칙 : 서버에서 외부로 나가는 규칙

다음과 같이 SSH를 위한 22포트, http를 위한 80포트, https를 위한 443포트를 추가해준다.

3. 인스턴스 생성

  • 설정 시 OS는 Ubuntu로 하고 ssh 원격 접속을 위한 키페어만 설정하여 다운로드 해 준다.
  • AWS 가입 후 1년동안 t2.micro를 사용하면 30GB 스토리지까지 무료로 사용할 수 있다.
  • 최신이 좋으니까 22.04 버전의 우분투 서버를 선택한다.

4. 인스턴스 연결

  • 콘솔에서 내가 생성한 인스턴스로 들어가 연결 버튼을 클릭한다 (생성 직후 약간의 시간 소요)
  • 'ssh 클라이언트' 탭에서 퍼블릭 DNS를 사용해 인스턴스에 연결한다. 명령어는 예시에 있는 것을 그대로 사용해도 좋다.
  • 키페어가 있는 위치에서 아래 명령어를 사용해야 한다.

5. 인스턴스 연결 완료!

본격적으로 이제 나는 서버용 리눅스 컴퓨터를 갖게 된 것이나 다름 없다. 이제 여기서 서버를 24시간 돌아가도록 해놓고, 외부 클라이언트의 네트워크 요청을 nginx를 사용해 적절히 프로젝트를 바라보게 하면 된다.

서버용 컴퓨터 세팅하기

이제 이 컴퓨터를 서버용 컴퓨터로 만들어야 하는데, 뭔가 처음 개발을 배울때 컴퓨터 세팅을 했던 기억도 새록새록 나면서 아주 재미있었다.

1. 초기 설정

# 관리자 계정 패스워드 생성
sudo passwd

# 우분투 시간대 설정
sudo timedatectl set-timezone Asia/Seoul

# 패키지 매니저 최신으로 업데이트
sudo apt update

# 필수 패키지 설치
sudo apt install nginx net-tools htop

# nvm 설치
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
source ~/.bashrc
nvm install [version]
  • node와 npm 버전이 출력되어야 한다.
  • 퍼블릭 IP, 퍼블릭 IP DNS를 요청하면 nginx 디폴트 페이지가 표시되어야 한다.

2. 프로젝트 clone 해서 가져오기

보통 프로젝트들은 /var/www 경로에 위치해 있다. AWS ubuntu는 git을 기본으로 설치해두기 때문에 따로 깃은 설치할 필요가 없지만, clone을 위해서 ssh 키를 먼저 만들어야 할 필요가 있다.

  • ssh-keygen 명령어로 ssh키를 생성한다.
  • ssh public 키는 보통 /root/.ssh/id_rsa.pub 경로에 생성된다.
  • cat ~/.ssh/id_rsa.pub 명령어로 퍼블릭키를 복사해서 깃 계정에 등록하고 클론
# ssh키 생성
ssh-keygen

# 생성된 퍼블릭 키 열기
cat ~/.ssh/id_rsa.pub

# 원하는 레포지토리 클론 (/var/www/ 경로)
git clone git@github.com:Joonpark4/portfolio.git

# yarn, pm2 글로벌 설치
npm install -g yarn

3. 편의성을 위한 세팅1 - 메모리 스왑

일단 서버에서 Next.js를 실행하고, 외부 클라이언트 요청에 따라 리버스 프록시로 프로젝트를 보여줄 준비는 마쳤다.
다만 clone 받은 프로젝트의 모듈을 설치하고 빌드하는 과정에서 시스템이 자주 멈추어버리는 현상이 발생하는데, 이를 위해 메모리 스왑부터 하려 한다.

  • 2gb의 스토리지 용량을 메모리로 사용할 수 있도록 아래 명령어 실행
  • 실제 메모리처럼 빠른 속도는 아니지만 작업에 도움이 될 수 있다.
sudo dd if=/dev/zero of=/swapfile bs=128M count=16
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 성공했는지 확인
swapon -s

# 재시작 할 때마다 메모리 할당
sudo vim /etc/fstab
/swapfile swap swap defaults 0 0

# 메모리 적용 확인
free

4. Next.js 프로젝트 빌드하고 시작하기

일반적으로 하던 것처럼 yarn, yarn build 명령어로 패키지를 설치하고 프로젝트를 빌드해주면 된다.
단, yarn start의 경우에는 pm2를 사용해서 프로젝트를 오픈하는 것을 추천한다.

  • pm2로 프로젝트 서버를 가동할 경우 어플리케이션 충돌 등 프로젝트 서버가 종료되더라도 자동으로 지정된 어플리케이션을 재시작
  • 그 외에 로깅, 모니터링, 프로세스 관리, 구성 관리 등 여러 이점이 있으나 다음에 상세 기술
pm2 start "yarn start"

5. nginx로 리버스 프록시 설정

nginx를 완전히 이해하기는 너무도 어렵다. 하지만, 적어도 이를 활용해서 동작하도록 하는 것은 내 몫이라고 생각한다.
먼저 nginx 설정파일을 만들어주기 위해 다음 명령어를 실행한다.

  • 내가 가진 도메인 네임이 joon.nimarketing.kr 이라고 가정하면 아래와 같은 코드로 따라갈 수 있다.
# nginx 설정 폴더로 이동
cd /etc/nginx/conf.d

# nginx 설정 파일 생성
vi joon.nimarketing.kr.conf

# 아래 코드를 붙여넣기
server {
    listen 80;
    server_name joon.nimarketing.kr;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name joon.nimarketing.kr;

    ssl_certificate /etc/letsencrypt/live/joon.nimarketing.kr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/joon.nimarketing.kr/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # TLS 설정
    ssl_protocols TLSv1.2;

    location / {
        proxy_pass http://localhost: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;
    }
}

6. nginx 재시작

nginx 설정을 변경한 후에는 반드시 다음 명령어를 입력해서 재시작하거나 리로드를 해야한다.

# nginx 설정에 문제가 있는지 확인
nginx -t

# nginx 재시작
systemctl restart nginx

7. 테스트 접속

위 도메인 네임으로 http 접속을 하면 페이지가 잘 출력되어 나와야 한다.
사실 http는 https에 비해 보안 계층이 부족해 권장되지 않지만, 일단 먼저 http로 접속 테스트를 한 후에 https 인증을 받으려 한다.

  • 다행히 의도한대로 http 접속 시 미완성인 개인 포폴사이트가 잘 보여진다.

8. https 인증 및 갱신 설정

'certbot'과 'python3-certbot-nginx'이라는 이름의 패키지를 설치하면 https 인증을 무료로 받을 수 있다. 과거에는 돈을 주고 인증을 받는 사례도 있었다고는 하는데, 가능하면 무료로 하는게 제일 좋다. 무슨 원리인지는 사실 깊게 알면 좋겠지만, 나중을 위해 깊은 공부는 미루어 두자.

# 설치
apt install certbot python3-certbot-nginx
# 인증 받기
certbot --nginx

# nginx 재시작
nginx -t
systemctl restart nginx

# 매월 1일 오후 6시 인증서 갱신 후 nginx재시작 (크론탭:자동 실행 명령)
crontab -e

# 최하단에 아래 구문 추가
0 18 1 * * certbot renew --renew-hook="sudo systemctl restart nginx"

9. 최종 접속

  • https 요청으로도 잘 적용이 된다 :)

결론

한꺼번에 너무 많은 지식들이 머리에 담기니 정리조차 어렵다...
하지만 Vercel에만 기대어 배포했던 Next.js를 AWS에서 배포할 수 있게 되어서 조금 더 선택의 범위가 넓어진 느낌이다.
구현에 집중해서 원리를 깊게 파지는 못했지만 그래도 또 네트워크에 대한 공부가 확실히 되었다.

다음 도전은?

  • React와 Express를 연결해 nginx로 띄우는 방식도 도전해보자.
  • Docker로 프로젝트를 이미지하여 AWS EC2로 배포하고, GitHub Action으로 CI/CD를 구현해보자.
  • 개인 포폴사이트... 언제 만들거냐고 제발 미루지말고 일좀 해 😫
profile
FE Developer

0개의 댓글