Nginx / AWS EC2를 활용하여 React와 Node 서버 배포해보기 1탄

1. EC2 서버 인스턴스를 생성

인스턴스 이미지: Amazon Linux 2 AMI (HVM), 64bit(x86) 을 선택

인스턴스 타입: t2.micro 타입을 선택 

스토리지 사이즈: 최대 30GB까지는 무료

HTTPSHTTP를 지원하도록 보안 설정

Key를 발급받기 (키는 다시 재발급이 안되므로 잘 관리해야 한다)

mkdir ~/keys
mv ~/Downloads/backfront.pem ~/keys
chmod 400 ~/Documents/keys/ci-cd-study.pem
  • `mv <옮길파일> <옮길위치>` : 파일을 특정 디렉토리에 옮기는 명령어
  • `chmod <옵션> <권한대상>`: 리눅스와 유닉스 계열 운영체제에서 파일 시스템 객체(파일, 디렉토리 등)의 접근 권한을 설정하는 명령어 
    • chmod (changemode) 옵션은 숫자 또는 기호를 사용하여 지정. 
      1. 숫자 방식
        • 3자리로 표현하며 각자리의 의미는 다음과 같습니다
          <사용자(Owner) 그룹(Group) 기타 사용자(Others)>
        • 숫자는 3가지 숫자가 들어올 수 있으며, 숫자를 조합하여 여러 개의 권한을 부여할 수 있습니다.
          • 읽기 (r) = 4
          • 쓰기 (w) = 2
          • 실행 (x) = 1
          • 읽기 + 쓰기 (rw) = 6
          • 읽기 + 실행 (rx) = 5
          • 쓰기 + 실행 (wx) = 3
          • 읽기 + 쓰기 + 실행 (rwx) = 7
      2. 기호 방식
        • 다음과 같은 형식을 띔
          `chmod [u/g/o/a][+/=/-][r/w/x] <대상>`
          • u: 소유자 (user)
          • g: 그룹 (group)
          • o: 기타 사용자 (others)
          • a: 모두 (all)
          • +: 권한 추가
          • -: 권한 제거
          • =: 권한 설정
          • r: 읽기 (read)
          • w: 쓰기 (write)
          • x: 실행 (execute)
    • chmod 400 명령어는 파일이나 디렉토리의 권한을 설정하여 소유자에게만 읽기 권한을 부여하고, 그룹과 기타 사용자에게는 어떠한 권한도 부여하지 않는 설정입니다. 

맥을 사용하게 된다면 `chmod`로 설정할 경우 `chmod: Unable to change file mode on /Users/devlee/Documents/keys/ci-cd-study.pem: Operation not permitted` 이런 에러가 뜰 수 있는데 이런 경우 설정의 전체 디스크 접근 권한에서 터미널의 접근권한을 풀어주면 해결된다.

iTerm의 접근 권한을 해제

 

2. EC2 인스턴스에 접속하기

ssh -i <키위치> ec2-user@<개방주소번호>
  • `-i`: SSH 키 파일을 지정하는 옵션
  • `ec2-user@<개방주소포트번호>`: 원격 서버의 사용자 이름과 IP주소입니다.
    • ec2-user: AWS EC2 인스턴스의 기본 사용자 이름

위 명령어를 통해 EC2 인스턴스에 입장할 수 있습니다. 

접속 완료~!

ssh는 무엇일까?
SSH는 Secure Shell의 줄임말로 네트워크 프로토콜 중 하나압니다.
보호되지 않는 네트워크를 통해 컴퓨터에 명령을 안전하게 전송하는 방법이며, 원격지 호스트 컴퓨터 (EC2 인스턴스)에 접속하여 명령을 실행하고 정보를 보고 받을 수 있도록 해주는 통신 프로토콜입니다.

 

3. Git과 htop 설치

htop: 메모리와 CPU 상태를 볼 수 있는 top 명령을 개선한 프로그램

sudo yum update -y // 리눅스 시스템에서 패키지 업데이트를 수행하는 명령어
  • `sudo`: superuser(최고 관리자) 권한으로 명령어를 실행
  • `yum`: `Yellowdog Updater, Modified`의 약자로, RPM 기반의 패키지 관리 도구
    주로 RedHat 계열의 리눅스 배포판에서 사용됨. (Ubuntu의 경우 Debian 계열이며, apt를 사용)
  • `-y`: 모든 질문에 자동으로 'yes'로 응답
sudo yum install git htop -y // git과 htop 설치

 

4. Node 설치하기

mkdir ~/local
wget https://nodejs.org/dist/v16.14.0/node-v16.14.0-linux-x64.tar.xz // LTS 버전을 다운로드 받을 수 있도록 한다
tar xvf node-v16.14.0-linux-x64.tar.xz
cd node-v16.14.0-linux-x64/bin 
pwd // 현재 작업중인 디렉토리 확인
  • 리눅스 관례에 따라 local 디렉토리를 만들어 준다. (리눅스 관례에 대해 알아보기)
    `/usr/local` : 개인 컴퓨터에서 지역적으로 생성되는 시스템 파일
  • `wget`: 웹에서 파일을 다운로드 하는 명령어
  • `xz`: 무손실 데이터 압축 프로그램 및 LZMA2 압축 알고리즘 파일 형식
    xz는 파일 하나만을 압축하기 위해 설계되어 다수의 파일을 하나로 묶진 못함
    다수의 파일을 압축하기 위해서는 tar와 같은 툴을 사용하여 하나의 파일로 모아야합니다.
  • `tar`: 여러 개의 파일을 하나의 파일로 묶거나 풀 때 사용하는 명령어
    Tape ARchiver의 줄임말
    • 여러 개의 옵션이 존재 
      • `xvf`:  tar 해제 (아카이브를 풀기)
      • `cvf`: tar 생성
      • `czvf`: 압축 생성
      • `xzcf`: 압축 해제

5. 환경변수 적용하기

`.bash_profile` 파일을 열어서 환경변수 설정해주기

vi ~/.bash_profile

 

./bash_profile 파일이란?
사용자가 로그인 셸에 접속할 때 실행되는 초기화 스크립트
로그인 셸 환경을 설정하는데 사용하며, 사용자가 로그인할 때마다 실행

역할
1. 환경 변수 설정

환경 변수를 설정하여 셸과 자식 프로세스에서 사용할 수 있게 함

예시)`export PATH=$PATH:/new/directory`

2. 별칭 설정
자주 사용하는 명령어에 대해 별칭을 설정할 수 있음
예시) `alias ll='ls -l'`

3. 셸 옵션 설정
셸의 동작 방식을 변경하는 옵션을 설정할 수 있음
예시) `set -o vi` (vi모드로 셸 설정)

4. 사용자 정의 함수
셸에서 사용자 정의 함수를 정의할 수 있음
예시) 
my_function() {
  echo "Hello, World!"
}​


5. 프로그램 실행
로그인할 때 자동으로 실행할 프로그램을 지정할 수 있음
예시) `startx` (X 윈도우 시스템을 시작)

.bash_profile vs .bashrc
`.bahs_profile`: 로그인 셸에 대해 실행. 시스템에 로그인할 때 한 번만 실행
`.bashrc`: 비로그인 셸(예: 터미널을 열 때)에 의해 실행. 각 셸 세션마다 실행

셸이란?
사용자와 운영체제 커널 사이의 인터페이스 역할을 하는 프로그램. 셸
은 사용자로부터 명령어를 입력받아 이를 해석하고, 해당 명령을 실행하는 역할을 한다. 셸은 명령어 기반의 사용자 인터페이스(CLI, Command Line Interface)로, 다양한 명령어와 스크립트를 통해 시스템을 제어하고 작업을 자동화할 수 있다.

대표적인 셸
1. Bash
2. Sh
3. Csh
4. Ksh
5. Zsh

 

.bash_profile 파일을 열면 다음과 같이 보일 것이다

아래에 node가 위치한 곳을 환경변수로 설정해주자.

 

이렇게 추가해준 후에 환경변수를 적용하기 위해 다음 명령어를 실행해보면 node 버전이 잘나옴을 확인할 수 있다.

source ~/.bash_profile
node -v

 

6. nginx 설치

Amazon Linux 2를 사용하는 경우 다음과 같은 명령어를 사용하여 nginx를 설정하자

sudo amazon-linux-extras install nginx1

 

그리고 nginx 설정을 해주기 위해 conf 파일을 열어주자

sudo vi /etc/nginx/nginx.conf

 

설정파일을 내리다보면 server 옵션이 있는 부분을 볼 수 있게 될 것이다.

여기서 include와 error_page 사이에 아래의 코드를 추가해주자. 
Nginx에서 특정 경로(/)로 들어오는 요청을 어떻게 처리할지 정의한 것이며 Nginx를 역방향 프록시 서버로 설정하여 요청을 내부의 다른 서버(http://127.0.0.1:4000)으로 전달

location / {
  sendfile off;
  proxy_pass         http://127.0.0.1:4000;
  proxy_redirect     default;
  proxy_http_version 1.1;
  proxy_set_header   Host              $host;
  proxy_set_header   X-Real-IP         $remote_addr;
  proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
  proxy_set_header   X-Forwarded-Proto $scheme;
  proxy_cache_bypass $http_upgrade;
  proxy_max_temp_file_size 0;
}
  • `location /` : `/`로 시작하는 모든 요청을 처리 (기본 경로에 대한 요청 처리)
  • `sendfile off`: sendfile(파일을 직접 전송하는 기능) 기능을 비활성화. 
  • `proxy_pass http:127.0.0.1:4000`: 모든 요청을 http:127.0.0.1:4000으로 전달 (포트 4000에서 실행 중인 서버로 요청을 프록시 함)
  • `proxy_redirect default`: 기본 설정을 사용하여 프록시 응답의 `Location` 헤더를 수정. 이 지시문은 기본적인 리다이렉션 처리를 수행
  • `proxy_http_version 1.1`: 프록시 요청에 HTTP 1.1을 사용
  • `proxy_set_header Host $host`: 원래 요청의 호스트 헤더를 백엔드 서버로 전달. `$host` 변수는 원래 요청의 호스트 이름을 포함
  • `proxy_set_header X-Real-IP $remote_addr`: 클라이언트의 실제 IP 주소를 백엔드 서버로 전달. `$remote_addr` 변수는 클라이언트의 IP 주소를 포함
  • `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for`: 요청이 여러 프록시를 거쳤을 때 클라이언트의 IP 주소들을 백엔드 서버로 전달. `$proxy_add_x_forwarded_for` 변수는 이전 `X-Forwarded-For` 헤더에 현재 클라이언트의 IP 주소를 추가
  • `proxy_set_header X-Forwarded-Proto $scheme`: 요청이 어떤 프로토콜(HTTP/HTTPS)을 사용했는지 백엔드 서버로 전달. `$scheme` 변수는 요청의 프로토콜을 포함
  • `proxy_cache_bypass $http_upgrade`: 업그레이드 요청(예: WebSocket)에 대해서는 프록시 캐시를 우회. `$http_upgrade` 변수는 업그레이드 요청 여부를 포함
  • `proxy_max_temp_file_size 0`: 임시 파일을 만들지 않도록 설정. 이 지시문은 프록시 서버가 응답을 임시 파일에 저장하지 않도록 함.

 

설정을 다 했으면 설정 파일에 이상이 없는지 명령어를 통해 체크해보자

sudo nginx -t
  • `sudo`: superuser(최고 관리자) 권한으로 명령어를 실행. Nginx의 설정 파일은 시스템 파일이므로, 이를 테스트하거나 변경하려면 루트 권한이 필요하다.
  • `nginx`: Nginx 웹 서버 프로그램을 실행
  • `-t`: Nginx의 설정 파일을 테스트하는 옵션. 이 옵션은 Nginx가 설정 파일을 로드하고 구문 및 논리적 오류를 체크하도록 함

만약 문제가 없다면 다음과 같이 뜰 것이다.

 

이제 Nginx 서버를 시작해보도록 합시다.

sudo systemctl start nginx // Nginx 웹 서버를 시작하는 데 사용
  • `systemctl`: 시스템과 서비스 관리 도구인 systemd의 명령어. 이 도구를 사용하여 시스템 서비스를 제어할 수 있다.
  • `start nginx`: 지정된 서비스를 시작하는 명령. 여기서는 nginx를 실행

이번에는 서버를 재시작해도 nginx도 재시작하도록 명령해봅시다.

sudo systemctl enable nginx // Nginx 서비스가 시스템 부팅 시 자동으로 시작되도록 설정

 

만약 서버가 정상적으로 실행되었는지 확인해보고자 한다면 아래의 명령어를 입력해보자

curl localhost // curl localhost:80과 동일한 의미

 

만약 정상적으로 실행되었다면 다음과 같은 화면을 볼 수 있습니다.

 

NGINX란?

고성능 HTTP 및 역방향 프록시 서버입니다. 


기능
1. HTTP 서버
: 정적 콘텐츠(HTML, CSS, JavaScript, 이미지 파일 등)를 제공하는 웹 서버로 사용됩니다.

2. 역방향 프록시: 클라이언트 요청을 다른 서버로 전달하고, 그 결과를 클라이언트에게 반환하는 역방향 프록시 서버로 사용됩니다. 이는 부하 분산(로드 밸런싱)과 캐싱을 통해 웹 사이트의 성능을 향상시킬 수 있습니다.
3. 로드 밸런서: 여러 서버에 부하를 분산시켜 트래픽을 효율적으로 처리하고, 서버 장애 시에도 서비스의 가용성을 유지할 수 있습니다.
4. 메일 프록시 서버: IMAP/POP3 메일 서버의 프록시로도 사용됩니다.
5. TLS/SSL 지원: HTTPS를 통해 안전한 웹 트래픽을 제공합니다.
6. 리버스 프록시: 여러 백엔드 서버에 대한 요청을 프록시하는 역할을 수행하며, 로드 밸런싱, 캐싱, 압축, 및 SSL 종료 등을 제공합니다.


주요 장점
1. 높은 성능: Nginx는 이벤트 기반 아키텍처를 사용하여 높은 동시성 처리가 가능합니다. 이는 많은 수의 요청을 효율적으로 처리할 수 있음을 의미합니다.
2. 낮은 메모리 사용량: 효율적인 메모리 사용으로 많은 클라이언트를 처리할 수 있습니다.
3. 유연한 구성: 다양한 기능을 제공하며, 모듈식 설계를 통해 필요에 따라 기능을 추가하거나 제거할 수 있습니다.
4. 안정성: 높은 안정성을 제공하며, 많은 대형 웹 사이트에서 신뢰할 수 있는 웹 서버로 사용되고 있습니다.

사용 예시
1. 정적 파일 서비스: 정적 파일을 빠르고 효율적으로 제공하는 웹 서버로서의 역할을 합니다.
2. 역방향 프록시 서버: 애플리케이션 서버 앞단에 위치하여 클라이언트의 요청을 백엔드 서버로 전달하고, 그 결과를 반환하는 역할을 합니다. 이는 부하 분산 및 캐싱을 통해 성능을 향상시킵니다.
3. 로드 밸런싱: 여러 백엔드 서버에 트래픽을 분산시켜 웹 애플리케이션의 성능과 가용성을 향상시킵니다.
4. API 게이트웨이: API 요청을 처리하고, 인증, 인가, 라우팅 등의 기능을 제공합니다.

 

역방향 프록시 서버란?
클라이언트의 요청을 받아서 내부 네트워크에 있는 여러 서버로 전달하고, 서버로부터 받은 응답을 다시 클라이언트로 전달하는 서버
클라이언트와 서버 사이에 위치하며 클라이언트는 역방향 프록시 서버를 통해서만 백엔드 서버에 접근할 수 있음

작동 원리
1. 클라이언트 요청: 웹 브라우저를 통해 역방향 프로시 서버에 요청을 보냄
클라이언트가 http://example.com에 접속할 때 DNS는 이 도메인을 역방향 프록시 서버의 IP주소로 해석
2. 역방향 프록시 서버 처리: 역방향 프록시 서버는 클라이언트의 요청을 받아 적절한 백엔드 서버로 전달
로드 밸런싱 알고리즘을 사용하여 여러 백엔드 서버 중 하나를 선택
3. 백엔드 서버 응답: 백엔드 서버는 요청을 처리하고 응답을 역방향 프록시 서버로 보냄
4. 클라이언트로 응답 반환: 역방향 프록시 서버는 백엔드 서버의 응답을 받아 클라이언트에게 반환
클라이언트는 역방향 프록시 서버가 마치 실제 서버인 것처럼 인식

7. node.js 연결

서버에서 API 서버만 프로세스를 띄우고, React는 빌드한 결과물을 백엔드의 public 경로로 복사해서 실행한다.

`node.js` 서버를 띄우기 위해서는 `pm2`를 설치해야 합니다. 

npm i -g pm2

 

Github 레포지토리에 연결하기

mkdir ~/git && cd ~/git // 디렉토리 만들고 이동하기

git clone <주소> // 레포지토리를 옮기기

cd <프로젝트 폴더명> // 프로젝트 폴더로 이동

cd <프론트엔드 폴더명> // 프론트엔드 폴더로 이동

npm i // 의존성 설치

npm run build // 프로젝트 빌드하기

이렇게 빌드된 결과물을 백엔드 폴더의 public 디렉토리로 옮겨야 한다.

cp -rf dist/* ../be/public // dist/*(빌드된 파일들)을 (../be/public)백엔드 프로젝트의 public 디렉토리로 복사하기
  • `cp`: 파일 / 디렉토리를 복사
  • `-r`: 디렉토리를 재귀적으로 복사 (디렉토리 내부의 모든 파일과 하위 디렉토리를 복사)
  • `-f`: 기존 파일을 강제로 덮어쓰는 옵션 (동일한 이름이 있는 경우 덮어씀)
  • `dist/*`: 현재 작업중인 디렉토리의 dist 디렉토리(빌드파일) 내의 모든 파일과 디렉토리를 선택

이번에는 백엔드 프로젝트 폴더로 이동해서 다음과 같은 명령어를 순차적으로 실행해보자

npm i
pm2 start bin/www -name web
pm2 list

 

명령어를 실행하면 다음과 같이 실행되어 있음을 볼 수 있다.