이번엔 React 프로젝트에 Express를 이용한 서버 설정 및 EC2에 NGINX를 이용한 배포를 하며 삽질 및 오류 해결을 정리한 글이다.
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')
})
$ sudo yum install nginx // Amazon Linux 1 환경
$ sudo amazon-linux-extras install nginx1.12 // Amazon Linux 2 환경
yarn install
후 build
를 생성한다. (두 과정은 새로운 버전 배포할 때마다 이뤄져야 한다.)$ yarn install
$ yarn run build
사실 여기서부터 삽질의 연속이었다...
build
를 하면 Creating an optimized production build..
에서 멈추고 진행이 끝나지 않았다. 꽤나 큰 규모의 플젝이라면 빌드시 소스맵을 생성하게 되면 메모리 부족 현상일 일어날 수 있다고 해서 소스맵 관련 설정을 추가했다.
하지만 이 방법도 해결되진 않았다. 그래도 나중에 참고할 일이 있을 것 같아 기록한다.
소스맵이란?
스택오버플로우
관련 링크
// 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
위의 방법으로도 해결이 안되어서 생각해낸 방법이 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에 옮겼다.
npm run build시 어떤 지시사항이 나오는 경우가 있다.
그래서 위 사진처럼 serve -s build
명령어를 입력했다.
만약 안되는 경우 serve 패키지가 없는 거라 npm i -g serve
로 먼저 설치한다.
따라해보니 Serving이라는 메세지와 함께 5000번 포트에서 제대로 동작한다.
Nginx와 관련된 설정 파일들은 /etc 하위에 존재하므로, sudo 권한을 이용해서 파일 생성과 수정 등을 해야 한다.
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 디렉토리에 필요한 파일들을 작성한 후 이들과 연결되는 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;
}
}
/
는 directive라고 하는 부분인데, IP 주소나 도메인의 뒷부분인 URI에 대응된다. /
만 쓰면 ‘/’
로 시작하는 모든 URI에 해당한다는 것으로 현재 설정은 이 인스턴스의 IP 주소로 port 80을 통해 들어오는 모든 URL을 연결시켜주는 것이다.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를 동작시키고, 웹 브라우저에서 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
나의 경우 프로젝트 서버 관련 파일이 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
yarn install
sudo systemctl start nginx
yarn start
1. sudo dd if=/dev/zero of=/mnt/swapfile bs=1M count=2048
2. sudo mkswap /mnt/swapfile
3. sudo swapon /mnt/swapfile
http://aws ip 주소:8000/
(port번호는 플젝에서 express 8000으로 설정했기 때문에 마지막이 8000)이로써 Nginx로 React 앱 배포 성공 !!!