[AWS] EC2에 React + Node.js + Express + NGINX 앱 배포 (2) - Express 설정 및 NGINX를 이용한 배포

jybaek96·2022년 8월 23일
0

이번엔 React 프로젝트에 Express를 이용한 서버 설정 및 EC2에 NGINX를 이용한 배포를 하며 삽질 및 오류 해결을 정리한 글이다.

1. React 프로젝트 Express 설정

  • 먼저 express, cors를 설치한다.
  • root 경로에 server.js 파일 생성 후 작성한 코드다. 참고 링크
const express = require('express')
const path = require('path')
const app = express()

app.use(express.json())
const cors = require('cors')
app.use(cors())

app.use(express.static(path.join(__dirname, './build')))
app.get('/', (res, req) => {
  req.sendFile(path.join(__dirname, './build/index.html'))
})

app.get('*', (res, req) => {
  req.sendFile(path.join(__dirname, './build/index.html'))
})

app.listen(8000, () => {
  console.log('Listening on 8000')
})

2. Nginx 설치

  • AWS EC2 인스턴스 환경에 따라 Nginx를 설치한다.
$ sudo yum install nginx // Amazon Linux 1 환경
$ sudo amazon-linux-extras install nginx1.12 // Amazon Linux 2 환경

3. React 앱 build

  • 프로젝트 내부 root에서 yarn installbuild를 생성한다. (두 과정은 새로운 버전 배포할 때마다 이뤄져야 한다.)
$ yarn install
$ yarn run build

사실 여기서부터 삽질의 연속이었다...

오류와 삽질의 연속...

build를 하면 Creating an optimized production build..에서 멈추고 진행이 끝나지 않았다. 꽤나 큰 규모의 플젝이라면 빌드시 소스맵을 생성하게 되면 메모리 부족 현상일 일어날 수 있다고 해서 소스맵 관련 설정을 추가했다.

빌드시 GENERATE_SOURCEMAP 옵션 off

하지만 이 방법도 해결되진 않았다. 그래도 나중에 참고할 일이 있을 것 같아 기록한다.
소스맵이란?
스택오버플로우
관련 링크

// GENERATE_SOURCEMAP=false 추가
"scripts": {
    "start": "node server.js",
    "build": "GENERATE_SOURCEMAP=false react-app-rewired build",
	... 중략
  },

메모리 스왑을 통한 메모리 부족 현상 처리

aws ec2 프리티어의 t2.micro를 사용하는데 이건 RAM이 1GB밖에 안돼서 빌드 규모가 커져도 진행이 안된다고 한다. 그래서 부족한 부분을 디스크의 일부를 대신 사용하도록 설정해줬다.

1. sudo dd if=/dev/zero of=/mnt/swapfile bs=1M count=2048
2. sudo mkswap /mnt/swapfile
3. sudo swapon /mnt/swapfile

그러고 build 실행하니 아래 에러 발생…

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

heap size 때문에 문제가 발생해 리눅스 서버에서 bashrc에 아래 코드로 설정을 추가했다.

vi ~/.bashrc

// bashrc에 아래 설정 추가
export NODE_OPTIONS="--max-old-space-size=8192"

source ~/.bashrc

filezilla로 build 파일 전송

위의 방법으로도 해결이 안되어서 생각해낸 방법이 build 파일만 filezilla를 통해 ec2에 전송하는 것이었다. filezilla 다운로드 및 접속은 링크를 통해 설치했다.

근데 react 플젝 폴더 권한이 root여서 filezilla에서 root로 로그인해야했다. (터미널에서 해당 폴더 권한을 711로 바꿔줘도 ec2-user로 변경되지 않았음)

filezilla에서 root 로그인을 위한 설정을 터미널에서 하다가 에러를 만났다.

$ service sshd restart
Error: No space left on device

그래서 링크를 참고해 볼륨을 수정해줬다.
그런데 리사이즈하다가 또 에러를 만났다...

$ sudo resize2fs /dev/xvda 1
resize2fs: Device or resource busy while trying to open /dev/xvda

그래서 아래의 방법으로 변경해줬다. 관련 링크

$ sudo resize2fs /dev/xvda 1
resize2fs: Device or resource busy while trying to open /dev/xvda

드디어 해결!

아까 막혔던 filezilla에서 root 로그인을 위한 설정을 다시 했다.

$ service sshd restart

근데 웬걸? root 계정에서 쉽게 ec2-user로 권한 설정 변경이 되는 것 아닌가?

$ sudo chown -R ec2-user /home/ec2-user/kollus-analytics-portal-sample

그 후 로컬에서 프로젝트 build 후 build된 파일은 filezilla를 통해 ec2에 옮겼다.

로컬에서 build시 제대로 안되는 경우

npm run build시 어떤 지시사항이 나오는 경우가 있다.

그래서 위 사진처럼 serve -s build명령어를 입력했다.
만약 안되는 경우 serve 패키지가 없는 거라 npm i -g serve로 먼저 설치한다.
따라해보니 Serving이라는 메세지와 함께 5000번 포트에서 제대로 동작한다.


4. NginX 설정

Nginx와 관련된 설정 파일들은 /etc 하위에 존재하므로, sudo 권한을 이용해서 파일 생성과 수정 등을 해야 한다.

nginx.conf 수정

  • nginx.conf 내에서 React 프로젝트의 build로 바로 이어지게 설정할 수도 있지만, 설정들을 깔끔하게 관리하기 위해서 일반적으로 선호되는 방식은 /etc/nginx 내에 sites-enabled 디렉토리를 생성하여 여기에 각 서비스의 설정을 넣고 nginx.conf가 이들을 확인하도록 하는 것이다.
  • 지금은 앞서 말한 대로 sites-enabled 디렉토리에 따로 설정을 만들어줄 것이므로, server 블럭 행들은 모두 주석 처리(행 앞에 #) 하도록 한다. 그리고 server 블럭 바로 위에 아래와 같이 include /etc/nginx/sites-enabled/*.conf;를 추가함으로써 sites-enabled 하위의 설정 파일들을 포함하도록 한다.
$ sudo vi /etc/nginx/nginx.conf

// /etc/nginx/nginx.conf 파일 수정
...

include /etc/nginx/conf.d/*.conf;
(✨ 코드 추가) include /etc/nginx/sites-enabled/*.conf;

# server {
#    listen       80 default_server;
#    listen       [::]:80 default_server;
#    server_name  _;
#    root         /usr/share/nginx/html;
    # Load configuration files for the default server block.
#    include /etc/nginx/default.d/*.conf;
#    location / {
#    }
#    error_page 404 /404.html;
#        location = /40x.html {
#    }
#    error_page 500 502 503 504 /50x.html;
#        location = /50x.html {
#    }
# }

...

sites-available, sites-enabled 설정

일반적인 방식은 sites-available 디렉토리에 필요한 파일들을 작성한 후 이들과 연결되는 symbolic link(symlink)를 sites-enabled에 추가하는 것이다. 때문에 /etc/nginx 내부에 두 디렉토리를 모두 생성해 준다. 그리고 sites-available 내에 원하는 이름으로 설정 파일을 생성해 열도록 한다.

$ sudo mkdir /etc/nginx/sites-available
$ sudo mkdir /etc/nginx/sites-enabled
$ sudo vi /etc/nginx/sites-available/원하는 파일명.conf

지금은 도메인 등록도 되어있지 않고, HTTPS를 위한 준비도 되어있지 않으므로, HTTP에 해당하는 port 80에 대해서 아주 기본 설정만 포함한다.

server {
  listen 80;
  location / {
    root /home/ec2-user/#######/#######/build;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
  }
}
  • location 뒤의 /는 directive라고 하는 부분인데, IP 주소나 도메인의 뒷부분인 URI에 대응된다. /만 쓰면 ‘/’로 시작하는 모든 URI에 해당한다는 것으로 현재 설정은 이 인스턴스의 IP 주소로 port 80을 통해 들어오는 모든 URL을 연결시켜주는 것이다.
  • root 행에는 아까 Git을 통해 가져온 프로젝트 내부의 build 디렉토리 경로를 입력한다.
  • 아래와 같은 내용이 출력되면 설정의 문법이 정상적이라는 것이다.
$ sudo ln -s /etc/nginx/sites-available/이전에 설정한 파일명.conf /etc/nginx/sites-enabled/이전에 설정한 파일명.conf
$ sudo nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Nginx 동작

이제 Nginx를 동작시키고, 웹 브라우저에서 AWS EC2 인스턴스 IP 주소를 입력하면 build한 React 앱으로 연결되는 것을 확인할 수 있다.
(AWS EC2 인스턴스 IP 주소로 바로 연결할 때 https로 들어가지는데, 현재는 http만 설정했기 때문에, http로 수정하면 들어가질 것이다.)

$ sudo systemctl start nginx

만약, 500 Internal Server Error가 발생한다면, build까지의 경로로 접근할 때 거치는 디렉토리들에 대해 외부에서의 실행 권한이 없어서 발생하는 문제일 가능성이 높으므로, 홈 디렉토리인 /home/ec2-user의 권한을 others의 실행 권한을 포함한 711로 설정한다.

$ chmod 711 /home/ec2-user

Express 서버 구동

나의 경우 프로젝트 서버 관련 파일이 server.js고 package.json에 서버 구동 관련 설정을 해놨다.
따라서 ec2에서 yarn start명령어를 통해 서버를 구동시켰다.

"scripts": {
    "start": "node server.js", // (*)
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject",
  	... 중략
  },

큰 흐름

  • 로컬에서 프로젝트 build
  • 프로젝트 업뎃시 ec2에서 git pull (main에 머지한 거 아니면 특정 브랜치 선택!)
  • 혹시 pull 하고 ec2에서 플젝 내에 node_modules 폴더 없다면 yarn install
  • 빌드 파일만 따로 fileZilla 통해서 전달 (원래는 ec2에서 yarn run build)
  • nginx 동작 시키기 sudo systemctl start nginx
  • express 서버 동작시키기 yarn start
  • 혹여나 ec2 용량이 부족하다면 아래 명령어 실행
1. sudo dd if=/dev/zero of=/mnt/swapfile bs=1M count=2048
2. sudo mkswap /mnt/swapfile
3. sudo swapon /mnt/swapfile
  • 마지막으로 aws ip주소로 접속~ -> http://aws ip 주소:8000/(port번호는 플젝에서 express 8000으로 설정했기 때문에 마지막이 8000)

이로써 Nginx로 React 앱 배포 성공 !!!


0개의 댓글