들어가며
우리가 만든 SSR 서버를 AWS EC2에 직접 배포해봤다. 인스턴스 생성부터 외부 접속을 열기까지, 실제로 진행한 순서 그대로 정리했다.
물론 이건 가장 기본적인 배포 방식이다. 실제 운영 환경이라면 더 복잡한 설정들이 필요하겠지만, 일단은 "내가 만든 서버를 인터넷에 띄운다"는 경험 자체가 중요하다고 생각한다. 그래야 나중에 더 복잡한 인프라를 구축할 때도 기본기가 탄탄하니까.
혹시 나처럼 처음 EC2로 서버 배포를 해보는 사람들에게 도움이 되었으면 좋겠다.
AWS에 배포하기
1. EC2 인스턴스 생성하기
- 먼저 AWS 콘솔에 로그인한 다음, EC2 서비스로 들어간다.
EC2 대시보드에서 Instances 메뉴로 접속한 다음 Launch Instances 버튼을 클릭하면 인스턴스 생성 화면이 나온다.
- 먼저 Name을 입력해준다. 나중에 인스턴스가 여러 개 생기면 구분하기 어려우니까 의미 있는 이름을 짓는 게 좋다. 나는 보통 프로젝트명이나 용도를 적어두는 편이다.
- 그 다음엔 애플리케이션과 OS 이미지를 선택해야 한다.
나는 Ubuntu를 선택했는데, Ubuntu가 Lunux 배포판 중에서 가장 많이 쓰이고 가장 문서와 튜토리얼이 풍부하다. 그렇기에 StackOverflow나 블로그에서 검색하면 대부분 Ubuntu 기준으로 작성되어 있어 문제 해결하기가 수월하다.
- 인스턴스 유형을 선택한다.
프리티어를 사용 중이라면 t2.micro나 t3.micro를 선택해야 추가 과금이 없다. 나는 테스트 용도라서 t2.micro로 충분했는데, 실제 운영 환경이라면 트래픽에 맞춰서 더 좋은 인스턴스 타입을 선택해야 할 것이다.
- Key pair를 선택한다.
Key Pair는 나중에 SSH로 서버에 접속할 때 필요한 일종의 열쇠라고 보면 된다.
만약 Key Pair가 없다면 Create new key pair를 눌러 이를 생성하면 된다.
유형은 RSA와 ED25519가 있다. RSA는 전통적으로 많이 쓰이는 방식이고, ED25519는 좀 더 최신 암호화 알고리즘이다. 보안성이나 속도 면에서는 ED25519가 더 낫다고 알려져 있긴 한데, 호환성을 생각하면 RSA도 나쁘지 않다. 나는 보안성이 더 뛰어난 ED25519를 선택했다.
형식은 .pem과 .ppk 중에 선택할 수 있는데, Mac이나 Linux를 쓴다면 .pem을 선택하면 되고, Windows에서 PuTTY를 쓴다면 .ppk를 선택하면 된다. 나는 Mac 유저라서 .pem으로 받았다.
여기서 중요한 건, 다운로드받은 Key Pair 파일은 절대 잃어버리면 안 된다는 것이다. 이 파일이 없으면 나중에 인스턴스에 접속할 수가 없다.
- 네트워킹 설정에서 보안 그룹을 설정한다.
보안 그룹은 일종의 방화벽이라 생각하면 된다. 어떤 포트로 접속을 허용할지 설정하는 건데, 일단은 SSH(22번 포트) 접속만 허용되도록 기본 설정으로 두고, 나중에 필요한 포트는 추가로 열어주면 된다. 이 부분은 뒤에서 다시 다룰 것이다.
여기까지 설정하고 Launch Instance 버튼을 누르면 인스턴스가 생성된다. 몇 분 정도 기다리면 인스턴스가 Running 상태로 바뀌는데, 이제 나만의 서버가 생긴 것이다.
2. EC2에서 배포하기
EC2 인스턴스를 생성했으면 이제 해당 인스턴스에 접속해보자.
- EC2 대시보드에서 방금 만든 인스턴스를 선택하고 우측 상단의 Connect 버튼을 클릭하면 접속 방법이 나온다.
- 여기서 인스턴스에 접속할 수 있는 방법에는 두 가지가 있는데, 하나는 AWS 콘솔에서 바로 접속하는 방법이다.
이 방법은 브라우저에서 바로 터미널이 열려서 편하긴 한데, 개인적으로는 로컬 터미널에서 SSH로 접속하는 게 더 익숙해서 이를 더 선호한다.
- SSH로 접속하려면 아까 다운로드받은
.pem파일이 필요하다. Connect 화면의 SSH client 탭에 보면 접속 명령어가 나와있는데, 이걸 그대로 복사해서 터미널에서 실행하면 된다.
- 나는 .pem 파일을 Downloads 폴더에 두고 있어서, 먼저 해당 폴더로 이동했다.
💡 만약 아래와 같은 에러가 뜬다면
![]()
이는 .pem 파일의 권한 문제다. 보안상의 이유로 이 파일은 소유자만 읽을 수 있어야 하는데, 다운로드받은 파일은 권한이 너무 열려있기 때문에 생긴 문제이다. 그래서 권한을 변경해줘야 한다.
chmod 400 guesung-2.pem위 명령어는 파일 소유자에게만 읽기 권한을 주는 것이다. 이렇게 권한을 설정하고 다시 SSH 명령어를 실행하면 연결이 잘 된다.
처음 접속하면 "정말 이 호스트에 접속할 건가?"라는 메시지가 뜨는데, yes를 입력하면 된다. 그러면 이제 Ubuntu 서버의 터미널이 눈앞에 펼쳐진다.
3. 서버 환경 세팅하기
EC2 인스턴스는 정말 깨끗한 상태다. Ubuntu가 설치돼있긴 하지만, Node.js도 없고 Git도 없고 아무것도 없다. 우리가 노트북을 처음 샀을 때 아무 것도 설치되어있지 않는 것과 같다고 보면 된다. 노트북을 처음 사면 뭐부터한다? Git과 Node.js부터 설치한다. 우리도 이제 그 과정을 할 것이다.
- 시스템 업데이트
sudo apt update && sudo apt upgrade -y
이 명령어는 두 가지 일을 하는데, apt update는 설치 가능한 패키지 목록을 업데이트하고, apt upgrade는 현재 설치된 패키지들을 최신 버전으로 업그레이드한다. -y 옵션을 붙이면 중간에 "정말 업그레이드할까?"라고 물어보지 않고 자동으로 진행된다.
- 기본 도구 설치
다음으로 개발에 필요한 기본 도구들을 설치해보자.
sudo apt install -y git curl vim
여기서 git은 코드를 클론하기 위해 필수로 필요하고, curl은 파일을 다운로드하거나 HTTP 요청을 테스트할 때 유용하다. vim이나 build-essential 같은 건 필요에 따라 설치하면 되는데, 나는 일단 꼭 필요한 것들만 먼저 깔았다. 나는 curl와 vim은 따로 설치하지 않았는데, Ubuntu 이미지에 기본적으로 포함이 되어 있는 듯하다.
- Node.js 설치하기
이제 본격적으로 Node.js를 설치해야 한다. 여기서 나는 nvm을 사용했다. nvm은 Node Version Manager의 약자인데, 여러 버전의 Node.js를 쉽게 관리할 수 있게 해준다.
curl -o-
https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh
| bash
설치를 마치고 환경변수를 적용해야 한다.
source ~/.bashrc
- 이제 원하는 Node.js 버전을 설치할 수 있다. 나는 프로젝트에서 22.17.0 버전을 사용하고 있어서 같은 버전으로 맞췄다.
nvm install 22.17.0
nvm use 22.17.0
nvm alias default 22.17.0
마지막 명령어(nvm alias default xx)는 이 버전을 기본값으로 설정하는 것이다. 그래야 나중에 터미널을 새로 열어도 같은 버전이 자동으로 활성화된다.
- 패키지 매니저와 프로세스 관리자 설치
현재 우리 프로젝트는 pnpm을 사용하고 있어서 pnpm도 설치해야 한다.
npm install -g pnpm
프로젝트에서 사용 중인 패키지 관리자인 pnpm을 설치한다.
그리고 PM2도 설치했다.
npm install -g pm2
PM2는 Node.js 애플리케이션을 백그라운드에서 실행하고 관리해주는 도구이다. 일반적으로 node server.js로 서버를 실행하면 터미널을 닫는 순간 서버도 꺼진다. PM2를 쓰면 터미널을 닫아도 서버가 계속 돌아가고, 만약 서버가 예상치 못하게 죽어도 자동으로 재시작해준다.
4. 프로젝트 배포하기
이제 환경 세팅이 끝났으니 실제로 프로젝트를 배포해볼 차례다.
- 코드 가져오기
먼저 GitHub에서 프로젝트를 클론해오자.
git clone https://github.com/woowacourse-teams/2025-bom-bom.git
cd 2025-bom-bom
우리는 특정 브랜치에서 작업하고 있어서 브랜치를 전환했다.
git checkout BOM-602-ssr
그리고 프론트엔드 프로젝트가 있는 폴더로 이동했다.
cd ./frontend/web
- 의존성 설치와 환경변수 설정
이제 필요한 패키지들을 설치해야 한다.
pnpm install
다음으로 환경변수 파일을 설정해야 하는데, 이 부분이 좀 까다로울 수 있다. 환경변수에는 API 키나 데이터베이스 접속 정보 같은 민감한 정보가 들어있다.
방법은 두 가지가 있다. 하나는 EC2에서 직접 파일을 만드는 것이다.
vim .env
vim 에디터가 열리면 필요한 환경변수들을 직접 입력하면 된다. 근데 vim이 익숙하지 않으면 이게 좀 불편할 수 있다.
또 다른 방법은 로컬에 있는 환경변수 파일을 scp 명령어로 EC2에 복사하는 것이다.
scp -i '/Users/home/Downloads/guesung.pem' .env
ubuntu@ec2-15-164-213-36.ap-northeast-2.compute.amazonaws.com
:~/2025-bom-bom/frontend/web/
이 명령어는 좀 길어 보이는데, 천천히 뜯어보면 그렇게 어렵지 않다. -i 옵션 뒤에는 인증에 필요한 .pem 파일의 경로를 적고, 그 다음에는 복사할 파일, 마지막에는 목적지를 적어주면 된다. 목적지는 사용자명@호스트:경로 형식이다.
이렇게 하면 환경변수 파일이 EC2 인스턴스로 안전하게 복사된다.
- 빌드하기
이제 프로젝트를 빌드할 차례다.
pnpm run build
빌드가 완료되면 dist 폴더에 프로덕션용 파일들이 생성된다. SSR 서버의 경우 서버 코드도 함께 번들링되는데, 우리 프로젝트는 dist/server/server.js에 서버 코드가 생성되었다.
5. 서버 실행하기
드디어 서버를 실행할 시간이다.
- 일반 실행 방식
pnpm run start
가장 간단한 방법은 이렇게 실행하는 것이다.
서버가 3000번 포트에서 잘 실행되는 걸 확인할 수 있다. 근데 이 상태로는 서버가 제대로 응답하는지 확인하기가 어렵다. 외부에서는 아직 접속할 수 없고, curl로 테스트하려고 해도 현재 터미널이 서버 실행으로 점유되어 있으니까.
물론 새로운 SSH 세션을 하나 더 열어서 테스트할 수도 있지만, 더 좋은 방법이 있다.
- PM2로 실행하기
아까 설치했던 PM2를 사용하면 서버를 백그라운드에서 실행할 수 있다. 현재 실행 중인 서버를 Ctrl+C로 종료한 다음, PM2로 다시 서버를 실행해보자.
pm2 start ./dist/server/server.js
이렇게 하면 서버가 백그라운드에서 실행되면서 터미널을 다시 사용할 수 있게 된다. 그럼 이제 curl로 서버가 제대로 응답하는지 확인해볼 수 있다.
curl http://localhost:3000
HTML 응답이 잘 오는 걸 확인할 수 있다. SSR이 제대로 작동하는지 확인하려면 응답 내용을 자세히 보면 되는데, 프리패칭한 데이터도 함께 들어있는 걸 확인할 수 있었다.
6. 외부 접속 허용하기
서버가 EC2 내부에서는 잘 작동하지만, 아직 외부(내 PC 등)에서는 접속할 수 없다. 왜냐하면 보안 그룹 설정에서 3000번 포트를 열어주지 않았기 때문이다.
- EC2 대시보드에서 해당 인스턴스를 선택하고 Security 탭으로 들어가면 현재 적용된 보안 그룹을 볼 수 있다.
- 보안 그룹 링크를 클릭해서 들어간 다음, Inbound rules 탭에서 Edit inbound rules 버튼을 누른다.
- 여기서 Add inbound rules 버튼을 눌러서 새로운 규칙을 추가하면 된다.
- Type은 Custom TCP로 선택하고, Port range에는 3000을 입력하고, Source는 Anywhere-IPv4(0.0.0.0/0)로 설정했다. 이렇게 하면 모든 IP에서 3000번 포트로 접속할 수 있게 된다.
여기서, 실제 운영 환경이라면 보안을 위해 Source를 좀 더 제한적으로 설정하는 게 좋다. 예를 들어 특정 IP 대역만 허용한다거나, CloudFront나 로드밸런서를 앞단에 두고 그쪽에서만 접속을 허용하는 식으로 말이다.
결과
페이지가 제대로 렌더링되는 걸 확인할 수 있다. 개발자 도구를 열어서 Network 탭을 확인해보니 SSR이 제대로 작동하고 있고, 초기 HTML에 데이터가 포함되어 있는 것도 확인할 수 있었다.
맺으며
인스턴스 생성부터 서버 실행까지 전 과정을 손으로 해봤다. 프론트엔드 개발자로서 이런 인프라를 직접 다룰 기회가 많지 않았다. 항상 Netlify나 Vercel 같은 자동 배포 플랫폼을 사용하면 간편하게 배포할 수 있었기 때문이다. 그러한 자동 배포 플랫폼이 내부적으로는 이러한 과정들을 자동으로 처리해주는구나 깨달았다. 그리고 이제는 이러한 과정을 스스로 해낼 수 있다는 점이 신기했다. EC2로 띄운 서버를 외부에서 접속했을 때는 감격스러울 정도였다.
수동으로 모든 과정을 진행했기에 첫 배포까지 시간이 다소 걸렸다. 하지만 프로그램을 설치하는 과정부터 서버를 실행하는 과정까지는 Docker를 이용하면 이러한 과정들을 모두 자동화할 수 있다. 그러면 이제 우리가 해야 할 일은 EC2 인스턴스를 생성하고, Dockerfile을 관리하기만 하면 된다.
다음에는 Dockerfile을 작성해 효율적으로 배포를 관리하는 과정을 다뤄볼 것이다.