2023. 8. 27. 22:22ㆍNetwork
스터디룸 예약 사이트 프로젝트를 EC2 인스턴스에 배포해보았다.
매번 vercel같은 배포 서비스를 사용하다가 처음으로 서버에 직접 배포를 해봤는데,
백엔드 팀원분의 도움을 받아 성공적으로 배포를 마쳤다.
서버는 개발서버와 운영서버 두 개를 구성하였고,
개발서버에서는 develop브랜치를, 운영서버에서는 main 브랜치를 배포했다.
EC2 인스턴스를 생성하고 nginx를 웹서버로 사용하여 React 프로젝트를 배포하는 과정을 정리해보고자 한다.
(여기서 웹서버 (Web Server)란, 클라이언트로부터 http 요청을 받아 정적인 파일을 제공해주는 역할을 하는 서버이다. 나의 경우 이 응답을 제공하는 웹서버를 Nginx로 사용했다. 즉 Nginx가 EC2 서버에 올려놓은 나의 웹 애플리케이션 빌드 파일을 http 응답으로 제공해주는 역할을 한다.)
1. EC2 인스턴스 생성하기
적절한 이름을 ec2에 부여하고, 원하는 OS를 선택한다.
나의 경우 좀 더 명령어가 익숙하고 구글링하기 편한 ubuntu를 선택해줬다.
다음으로 인스턴스 사양을 선택할 수 있는데, 우리 프로젝트는 한이음으로부터 지원금을 받고 있기 때문에 넉넉하게 t2.large를 선택해줬다. 무료로 사용하고 싶다면 프리 티어를 선택하면 된다.
인스턴스에 접속하려면 키 페어를 사용해 권한을 체크하도록 설정할 수 있다.
이미 만들어둔 키페어를 사용해도 되고, 새 키페어를 생성해도 된다.
(이때 키페어가 어디 있는지 잘 알고 있어야 함!)
다음은 VPC (가상 네트워크)를 필수로 설정해줘야 한다. 팀원 분이 미리 만들어 둔 VPC와 서브넷을 선택해줬다.
퍼블릭 IP 자동 할당을 활성화해줄지를 설정해준다!
나의 경우 이미 서버 팀원분이 구축해둔 Bastion 서버를 거쳐서 접속이 가능하도록 하기 위해 퍼블릭 IP는 비활성화해뒀다. (만약 내 컴퓨터에서 바로 접속이 가능하도록 하려면 퍼블릭 IP 할당하면 된다.)
보안 그룹도 선택해야 하는데, 기존에 만들어 둔 보안 그룹이 없다면 새로 생성한다.
보안 그룹은 해당 서버로 접속을 시도하는 것에 대해 허용 여부를 규정하는 인바운드 규칙과, 해당 EC2에서 외부로 접근하는 것을 규정하는 아웃바운드 규칙을 설정해놓은 것이다. 대부분 보안에 문제가 되는 경우는 내 서버로 비정상적인 접근을 하는 인바운드 규칙일 테니 인바운드 규칙을 설정해놓은 보안 그룹을 생성하면 된다.
프로토콜마다 어떤 IP 주소로부터의 접근만 허용할 것인지, 또는 위치와 무관하게 모두 혀용할 것인지를 규정할 수 있다.
나는 이미 만들어둔 보안 그룹이 있어 그걸 선택했다.
더 구체적으로 설정해주고 싶다면 EC2 > 보안그룹에서 해당 보안그룹을 선택하고 인바운드 규칙을 편집 / 추가해주면 된다.
나머지 스토리지 구성이나 고급 설정도 해줄 수 있는데, 나는 우선 디폴트 값으로 두고,
인스턴스 시작 !
성공적으로 인스턴스가 생성되었다면 인스턴스 콘솔에서 바로 확인할 수 있다.
처음에는 대기 시간이 조금 있는데, 조금만 기다리면 인스턴스가 자동으로 실행된다.
2. 인스턴스 서버에 React 프로젝트 clone 하기
이제 서버도 구축했으니, 만들어 둔 서버에 내 프로젝트를 저장해두어야 한다.
인스턴스를 생성할 때 지정해뒀던 키페어를 가지고 ssh로 EC2 서버에 접속할 수 있다.
나의 경우 desktop/aws 위치에 키페어를 저장해두었기 때문에,
cd desktop/aws
로 해당 경로로 이동한다. 만약 새로 생성한 키페어라면,
chmod 400 키페어파일
를 입력해주어 해당 키페어에 대한 접근 권한을 소유자로 한정한다. (보안을 위해!)
chmod는 change mode의 약자로, 세자리 숫자의 가장 왼쪽 자릿수부터 각각 소유자, 그룹, 기타 사용자에 대한 권한을 설정해주는 명령어다.
4는 읽기 권한,
2는 쓰기 권한,
1은 실행 권한
으로, 예를 들어 읽기 권한만 있다면 4를, 모든 권한이 있다면 4 + 2 + 1 = 7을, 아무 권한이 없다면 0을 입력해주면 된다.
위의 경우 400이므로 소유자만 읽기 권한이 있고 그룹, 기타 사용자는 아무 권한이 없다.
권한까지 설정이 되었다면,
키페어를 가지고 ssh 접속하기 위해
ssh -i "[키페어파일]" ubuntu@\[IP주소\]
를 입력해주면 된다. (ubuntu@IP주소 부분은 구성한 EC2에 따라 달라질 수 있음!)
[키페어파일]을 가지고 이 IP주소에 ssh 접속하겠다! 는 뜻.
더 확실하게 하려면 해당 EC2 콘솔에서 '연결'을 클릭해 정확한 명령어를 복사할 수 있다.
(앞에서 언급했듯이 나의 경우 Bastion 서버로부터의 ssh 접속만 허용해뒀기 때문에 Bastion 서버로 ssh 접속 후 해당 서버에서 다시 거기다 저장해둔 키페어를 가지고 개발서버로 ssh 접속이 가능하도록 했다. 즉 위 과정을 두 번 거치는 셈..!)
그러면 터미널에 아래와 같이 사용자 정보가 변경되면서 성공적으로 접속이 되었을 것이다.
이제 접속한 이 서버에 React 프로젝트를 clone 해주면 된다.
평소 로컬 컴퓨터에다 클론을 해오던 것처럼 git clone 프로젝트를 해주고,
패키지를 다운받고 빌드를 하려면 npm 관련 명령어를 사용해야 하니 node js를 설치한다.
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs
여기서 sudo apt-get install nodejs만 해주면
라고 뜨는데, sudo apt-get install nodejs만 해주면 npm 과 같은 관련 패키지가 아니라 nodejs binary만 설치하기 때문에 저 curl ~ 명령어가 필요하다 (출처 스택오버플로우...)
다 설치가 되었다면 node -v, npm -v 명령어로 정상적으로 설치가 완료되었는지 확인하자.
드디어 이제 내 프로젝트를 빌드할 수 있다.
내 프로젝트 경로로 이동한 후, 빌드하고자 하는 브랜치로 checkout한다.
나는 개발 서버를 구축했고 해당 서버에 올라갈 브랜치는 develop 브랜치로 관리하기 때문에 develop으로 이동했다.
관련된 패키지를 npm install로 설치해주고,
package.json의 script에 명시되어있는 빌드 명령어를 입력해준다.
(cra로 구축한 나의 프로젝트의 경우 npm run build)
이제 ls로 빌드된 폴더가 생성되었음을 확인할 수 있다.
빌드 폴더로 들어가보면 index.html이 정상적으로 생성됐다.
이 인덱스 파일을 웹서버가 띄우도록 해야한다.
나중에 웹서버에게 index.html이 어디있는지 알려주기 위해 해당 build 폴더의 경로 (pwd) 를 복사해두자.
3. Nginx 설정하기
웹서버는 http 요청에 대한 응답을 제공하는 서버다.
이 역할을 해줄 nginx를 설치해주자.
sudo apt-get install nginx
설치가 정상적으로 되었는지 확인해주려면 역시 nginx -v를 입력해보면 된다.
nginx가 우리가 2번에서 빌드해둔 index.html를 접근해서 클라이언트에게 제공하려면 빌드 경로를 알아야 한다.
이 경로를 알려주기 위해 nginx 폴더에 들어가보자.
cd /etc/nginx
ls 를 입력해보면
이렇게 여러 파일과 폴더들이 보이는데, 우리가 주목해야 할 건 nginx.conf, sites-enabled 폴더와 sites-available 폴더다.
가장 기본 설정 파일인 nginx.conf 파일에 http 요청에 대한 응답 값을 설정해줄 수도 있지만,nginx.conf에 바로 작성하기보단,
sites-available에 [원하는 이름].conf 파일을 직접 만드는 것이 좋다. (이유는 아래에)
sites-enabled는 sites-available에 있는 conf파일과 연결하는 Symbolic Link를 담을 폴더다.
(여기서 Symbolic Link (symlink)는 유닉스 운영체제에서 특정 파일에 대한 shortcut과 같은 기능을 한다고 한다.)
우선 nginx.conf에
이렇게 sites-enabled에 있는 conf 파일 (사실은 symbolic link를 통해 sites-available에 있는 conf 파일)을 읽도록 명령어를 추가해준다.
그리고 sites-availble에 실제 conf 파일을 만들어주면 된다.
sudo vi /etc/nginx/sites-available/[원하는 이름].conf
편집기를 열고,
아래 내용을 입력해준다.
http 요청 (80 포트) 에 대해 root 경로에 있는 index.html 파일을 내보내라는 설정값이다.
root 경로에는 아까 빌드하고 복사해뒀던 build 폴더 경로를 입력해주면 된다.
이제 sites-enabled 폴더에 sites-available에 방금 만들어둔 conf 파일에 대해 Symbolic Link를 걸어준다.
아래의 명령어를 입력하면 연결 끝!
+) sudo nginx -t로 설정을 테스트해볼 수 있다.
왜 nginx.conf에 바로 위 설정값을 입력하지 않고 굳이 sites-available에 config 파일을 따로 만들까? 🤔
추후 ec2 서버에 다른 웹 애플리케이션도 저장해둘 수 있기 때문이다.
즉 하나의 서버에 여러 프로젝트가 있을 수 있는데, 각 서비스는 다른 도메인을 가지고 하나의 IP 주소를 공유하는 것이다.
이런 경우 nginx가 각 도메인에 해당하는 프로젝트의 경로를 따로 관리하고 있어야 하기 때문에
하나의 nginx.conf에 설정을 하는 것이 아닌 sites-available에 프로젝트 각각의 config 파일을 두는 것이다.
클라이언트가 A 도메인으로 접속을 하면, nginx가 A 도메인에 대해 설정해둔 config를 찾아
해당 root 경로에 있는 index.html을 띄울 수 있다.
이제 nginx를 실행해준다.
$ sudo service nginx start
$ sudo service nginx status
status 명령어를 입력했을 때 콘솔에 Active라고 뜨면 구동 성공!
+) 참고로, 무언가 설정을 잘못했을 때 오류를 잡기 위해서
nginx의 error log를 조회할 수 있는 명령어는:
tail -f [error.log의 경로]
인데, 여기서 error.log의 경로가 어딘지 모른다면
/etc/nginx/nginx.conf 파일을 보면
이렇게 경로를 알려준다. (access log는 말그대로 내 서버에 접속한 정보들!)
이 경로를 가지고 위 명령어를 입력해주면 실시간으로 에러 로그와 액세스 로그를 띄워준다.
그걸로 어떤 문제가 있는지 확인할 수 있다.
보통 build/index.html 파일에 대한 접근 권한으로 인해 nginx에서 404처리를 하는 경우가 있는데, 그런 에러도 이 에러로그를 통해 잡을 수 있다. 나도 이런 경험을 했는데, 결국 접근 권한을 풀어주어 에러를 해결했다.
만약 ec2를 퍼블릭 IP 할당을 해주었다면 해당 퍼블릭 IP DNS 주소로 접속하면 웹 페이지를 볼 수 있을 것이다!
나의 경우는 퍼블릭 IP를 할당하지 않았기 때문에 로드밸런서를 통해 외부에서 http 접속이 가능하도록 설정해야 하는데, 이건 다음 포스팅에서...👋