프론트엔드 S3 배포 + 통합 테스트
학습 목표
- S3 정적 웹사이트 호스팅의 개념과 장점을 이해한다
- 프론트엔드용 S3 버킷을 생성하고 정적 웹사이트 호스팅을 설정한다
- React 앱을 빌드하고 S3에 배포한다
- S3 웹사이트 URL로 접속하여 전체 서비스를 통합 테스트한다
왜 S3 정적 웹 호스팅을 사용하나?
ShopEasy 프론트엔드는 React로 만들어진 정적 파일(HTML, CSS, JavaScript)입니다. 이런 정적 파일을 서비스하기 위해 EC2 서버를 운영하는 것은 불필요한 비용과 관리 부담을 발생시킵니다. S3 정적 웹사이트 호스팅을 사용하면, 서버 없이도 웹사이트를 배포할 수 있습니다.
S3 정적 웹 호스팅은 전단지를 인쇄해서 진열대에 놓는 것과 같습니다. 진열대(S3)에 전단지(HTML/CSS/JS)를 올려두면 고객(사용자)이 직접 가져갈 수 있습니다. 직원(서버)이 일일이 전달해 줄 필요가 없죠. 반면 EC2에 프론트엔드를 올리는 것은, 전단지를 나눠주기 위해 직원을 고용하는 것과 같습니다. 비용이 훨씬 많이 들죠.
왜 EC2에 프론트엔드를 올리지 않나?
현재 EC2 인스턴스는 Node.js API 서버(백엔드)를 운영하고 있습니다. 프론트엔드까지 EC2에 올리면 다음과 같은 문제가 발생합니다:
| 항목 | EC2 호스팅 | S3 정적 호스팅 |
|---|---|---|
| 비용 | t2.micro ~$8.5/월 (프리티어 후) | 거의 무료 (~$0.01/월) |
| 관리 | OS 업데이트, 웹 서버 관리 필요 | 관리할 서버 없음 |
| 확장 | 트래픽 증가 시 서버 증설 필요 | 자동 확장 (무제한) |
| 가용성 | 서버 장애 시 중단 | 99.99% 가용성 |
| 배포 | SSH 접속, 파일 복사, 서버 재시작 | aws s3 sync 한 줄 |
| 역할 분리 | API + 프론트 혼합 (비효율) | EC2는 API 처리에만 집중 |
정적 파일: HTML, CSS, JS, 이미지 등 서버에서 별도 처리 없이 그대로 전달하는 파일. React 빌드 결과물(dist/ 폴더)이 이에 해당합니다.
동적 처리: API 요청을 받아 데이터베이스 조회, 비즈니스 로직 실행 등 서버에서 처리가 필요한 것. Node.js API 서버가 이에 해당합니다.
정적 파일은 서버가 필요 없으므로 S3에서 직접 서비스하는 것이 훨씬 효율적입니다. EC2는 API 처리에만 집중하게 합시다!
S3 정적 웹사이트 호스팅이란?
S3 버킷을 웹 서버처럼 사용하는 기능입니다. 버킷에 HTML 파일을 넣고 정적 웹사이트 호스팅을 활성화하면, 웹 브라우저에서 URL을 통해 바로 접속할 수 있습니다.
# S3 정적 웹사이트 URL 형식 (ap-northeast-2 리전)
http://[버킷이름].s3-website.ap-northeast-2.amazonaws.com
# 예시
http://shopeasy-frontend-123456789012.s3-website.ap-northeast-2.amazonaws.com
S3 정적 웹사이트 호스팅은 HTTP만 제공합니다. HTTPS를 사용하려면 CloudFront를 앞에 배치해야 합니다. 이번 실습에서는 HTTP만 사용합니다.
React SPA와 S3 오류 문서 설정
React는 SPA(Single Page Application)입니다. 모든 URL 요청이 index.html로 전달되어야 합니다. S3에서 /products/3 같은 URL로 직접 접속하면 해당 파일이 없어 404 에러가 발생합니다. 오류 문서(Error document)를 index.html로 설정하면, 404 발생 시 index.html을 반환하고 React Router가 적절한 페이지를 렌더링합니다.
일반 웹사이트는 각 페이지가 별도 HTML 파일입니다(about.html, contact.html). 하지만 React SPA는 입구가 하나(index.html)인 건물과 같습니다. 어떤 방(페이지)으로 가든 먼저 입구(index.html)를 거쳐야 하고, 입구에서 안내원(React Router)이 적절한 방으로 보내줍니다. 그래서 오류 문서도 index.html로 설정하는 것입니다.
빌드와 배포 과정 이해
프론트엔드를 S3에 배포하려면 먼저 빌드(Build)라는 과정을 거쳐야 합니다. 빌드는 개발용 소스코드를 브라우저가 실행할 수 있는 최적화된 파일로 변환하는 작업입니다.
개발용 파일들
최적화 & 번들링
assets/*.js, *.css
aws s3 sync
VITE_API_URL 환경변수
프론트엔드는 API 서버에 요청을 보내야 합니다. 하지만 S3에 배포된 프론트엔드는 EC2의 API 서버 주소를 어떻게 알까요? 바로 빌드 시점에 환경변수로 주입하는 것입니다.
# 빌드할 때 VITE_API_URL 환경변수를 설정
VITE_API_URL=http://EC2_PUBLIC_IP:5000 npm run build
# 빌드된 JS 파일 안에 이 URL이 포함됨
# 예: fetch("http://3.35.xxx.xxx:5000/api/products")
Vite 환경변수(VITE_ 접두사)는 빌드할 때 JavaScript 코드에 포함됩니다. 빌드 후에는 변경할 수 없습니다! API 서버 주소가 바뀌면 반드시 다시 빌드해야 합니다. 런타임에 .env 파일을 수정해도 적용되지 않습니다.
빌드 시점(Build time): npm run build를 실행하는 순간. 이때 환경변수가 코드에 하드코딩됩니다.
런타임(Runtime): 사용자가 브라우저에서 웹사이트에 접속하는 순간. S3에서 이미 완성된 JS 파일을 받아옵니다.
서버 사이드(Node.js)에서는 process.env로 런타임에 환경변수를 읽을 수 있지만, 클라이언트 사이드(React)에서는 빌드 시점에만 환경변수가 주입됩니다.
전체 아키텍처 - 프론트엔드 배포 후
HTML / CSS / JS
실습: 프론트엔드 S3 배포
S3 정적 호스팅은 매우 저렴합니다. 프리티어에서 5GB 스토리지, 20,000 GET 요청이 무료이며, 초과해도 월 몇 센트 수준입니다.
-
프론트엔드용 S3 버킷 생성
프론트엔드 정적 파일을 저장할 S3 버킷을 생성합니다.
버킷 설정
- Bucket name:
shopeasy-frontend-{ACCOUNT_ID}
예:shopeasy-frontend-123456789012 - AWS Region:
ap-northeast-2(서울)
ACCOUNT_ID 확인 방법AWS 콘솔 오른쪽 상단의 계정 이름을 클릭하면 12자리 계정 ID를 확인할 수 있습니다. 또는 EC2에서
aws sts get-caller-identity --query Account --output text명령어로 확인할 수 있습니다.AWS 콘솔 → S3 → Create bucket에서 생성합니다. 버킷 이름은 전 세계적으로 고유해야 하므로 계정 ID를 포함합니다.
- Bucket name:
-
퍼블릭 액세스 차단 해제
S3 정적 웹사이트 호스팅을 위해서는 퍼블릭 읽기가 가능해야 합니다. 버킷 생성 시 또는 생성 후에 퍼블릭 액세스 차단을 해제합니다.
- Block all public access: 체크 해제
- 경고 메시지가 나타나면 "I acknowledge that the current settings might result in this bucket and the objects within becoming public" 체크
퍼블릭 버킷은 프론트엔드 전용!이 버킷은 공개해도 되는 HTML/CSS/JS 파일만 저장합니다. API 키, 비밀번호, 개인정보 등 민감한 파일을 절대로 이 버킷에 올리지 마세요!
S3 → 버킷 선택 → Permissions 탭 → Block public access (bucket settings) → Edit에서 모든 체크를 해제합니다.
-
정적 웹사이트 호스팅 활성화
S3 버킷을 웹 서버처럼 동작하도록 정적 웹사이트 호스팅 기능을 활성화합니다.
설정 값
- Static website hosting:
Enable - Hosting type:
Host a static website - Index document:
index.html - Error document:
index.html(React SPA 라우팅을 위해!)
Error document를 index.html로 설정하는 이유React SPA에서
/products/3같은 URL로 직접 접속하면, S3는products/3이라는 파일을 찾습니다. 해당 파일이 없으므로 404 에러가 발생하는데, Error document를index.html로 설정하면 404 시index.html을 반환합니다. 그러면 React Router가 URL을 파싱하여 적절한 페이지를 렌더링합니다.설정 저장 후, Properties → Static website hosting 섹션에서 Bucket website endpoint URL을 메모합니다.
texthttp://shopeasy-frontend-{ACCOUNT_ID}.s3-website.ap-northeast-2.amazonaws.comS3 → 버킷 선택 → Properties 탭 → 맨 아래 Static website hosting 섹션 → Edit에서 설정합니다.
- Static website hosting:
-
버킷 정책 설정 (퍼블릭 읽기 허용)
모든 사용자가 버킷의 파일을 읽을 수 있도록 버킷 정책을 추가합니다.
json{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::shopeasy-frontend-{ACCOUNT_ID}/*" } ] }버킷 이름을 정확히 입력하세요!Resource의
shopeasy-frontend-{ACCOUNT_ID}를 본인이 생성한 실제 버킷 이름으로 변경하세요. 버킷 이름이 다르면 정책이 적용되지 않습니다.S3 → 버킷 선택 → Permissions 탭 → Bucket policy → Edit에서 위 JSON을 붙여넣습니다.
{ACCOUNT_ID}부분을 본인의 계정 ID로 변경하는 것을 잊지 마세요. -
EC2에서 프론트엔드 빌드
EC2 인스턴스에 SSH로 접속하여 프론트엔드를 빌드합니다.
bash# 1. EC2에 SSH 접속 ssh -i "ShopEasy-Key.pem" ec2-user@EC2_PUBLIC_IP # 2. 프론트엔드 디렉토리로 이동 cd ~/ecommerce-app/frontend # 3. 의존성 설치 npm install # 4. VITE_API_URL을 EC2 퍼블릭 IP로 설정하여 빌드 VITE_API_URL=http://EC2_PUBLIC_IP:5000 npm run build # 5. 빌드 결과 확인 ls -la dist/EC2_PUBLIC_IP를 실제 IP로 변경하세요!EC2_PUBLIC_IP를 EC2 인스턴스의 실제 퍼블릭 IP 주소로 변경하세요. 예:VITE_API_URL=http://3.35.123.456:5000 npm run buildIP 주소 뒤에 슬래시(/)를 넣지 마세요. 포트 번호 5000도 정확히 입력하세요.
EC2 퍼블릭 IP는 AWS 콘솔 → EC2 → Instances에서 확인할 수 있습니다. 빌드가 완료되면
dist/폴더에index.html과assets/폴더가 생성됩니다. -
dist/ 폴더를 S3에 업로드
빌드된 파일을 S3 버킷에 업로드합니다.
bash# EC2에서 실행 (IAM 역할이 S3 권한을 가지고 있어야 함) aws s3 sync dist/ s3://shopeasy-frontend-{ACCOUNT_ID}/ # 업로드된 파일 확인 aws s3 ls s3://shopeasy-frontend-{ACCOUNT_ID}/ --recursiveaws s3 sync 명령어aws s3 sync는 로컬 폴더와 S3 버킷을 동기화합니다. 새로 추가된 파일은 업로드하고, 수정된 파일은 덮어쓰고, 로컬에서 삭제된 파일은--delete옵션을 추가하면 S3에서도 삭제됩니다.EC2에 연결된 IAM 역할에 S3 접근 권한이 있어야 합니다. Chapter 04에서 설정한 IAM 역할에
s3:PutObject,s3:ListBucket권한이 포함되어 있는지 확인하세요. 권한이 없으면AccessDenied에러가 발생합니다. -
S3 웹사이트 URL로 접속하여 테스트
웹 브라우저에서 S3 웹사이트 엔드포인트로 접속합니다.
texthttp://shopeasy-frontend-{ACCOUNT_ID}.s3-website.ap-northeast-2.amazonaws.comShopEasy 메인 페이지가 정상적으로 로드되면 성공입니다!
축하합니다!S3에서 서비스되는 프론트엔드가 EC2 API 서버(포트 5000)를 통해 RDS, DynamoDB, S3(리뷰 이미지)에 접근하는 전체 아키텍처가 동작합니다.
통합 테스트 체크리스트
S3에 배포한 프론트엔드에서 전체 서비스가 정상적으로 동작하는지 아래 항목을 순서대로 테스트합니다.
-
회원가입 / 로그인
S3 웹사이트 URL에서 회원가입 후 로그인이 정상 동작하는지 확인합니다.
- 회원가입 페이지에서 새 계정 생성
- 생성한 계정으로 로그인
- 로그인 후 사용자 이름이 표시되는지 확인
-
상품 목록 / 상세 보기
메인 페이지에서 상품 목록이 정상적으로 로드되는지 확인합니다.
- 메인 페이지에 상품 목록이 표시되는지 확인 (RDS에서 데이터 조회)
- 상품 클릭 시 상세 페이지로 이동되는지 확인
- 상품 이미지, 가격, 설명이 정상 표시되는지 확인
-
리뷰 작성 (사진 포함)
상품 상세 페이지에서 리뷰를 작성합니다.
- 별점 선택 및 리뷰 텍스트 작성
- 사진 첨부 후 리뷰 등록 (S3에 이미지 업로드)
- 등록된 리뷰와 사진이 정상 표시되는지 확인 (DynamoDB에서 리뷰 데이터 조회)
-
장바구니 추가 / 주문
장바구니 기능과 주문 기능을 테스트합니다.
- 상품을 장바구니에 추가
- 장바구니 페이지에서 수량 변경 / 삭제
- 주문 진행 및 완료 확인
브라우저 개발자 도구(F12)의 Console 탭과 Network 탭을 확인하세요. CORS 에러, 네트워크 에러, API 서버 응답 에러 등의 원인을 파악할 수 있습니다. 흔한 문제와 해결 방법은 강사용 답안을 참고하세요.
확인 사항
- S3 버킷
shopeasy-frontend-{ACCOUNT_ID}가 생성되었는가? - 퍼블릭 액세스 차단이 해제되었는가?
- 정적 웹사이트 호스팅이 활성화되었는가? (Index: index.html, Error: index.html)
- 버킷 정책에 퍼블릭 읽기(s3:GetObject)가 허용되었는가?
- VITE_API_URL을 EC2 퍼블릭 IP:5000으로 설정하여 빌드했는가?
- dist/ 폴더가 S3 버킷에 업로드되었는가?
- S3 웹사이트 URL로 접속하여 메인 페이지가 로드되는가?
- 회원가입 / 로그인이 정상 동작하는가?
- 상품 목록이 정상 표시되는가? (RDS 연동)
- 리뷰 작성 및 사진 업로드가 정상 동작하는가? (DynamoDB + S3 연동)
- 장바구니 및 주문이 정상 동작하는가?
- S3 버킷을 생성하고 정적 웹사이트 호스팅을 활성화
- 버킷 정책으로 퍼블릭 읽기를 설정
- EC2에서 프론트엔드를 빌드하고 S3에 배포
- S3 웹사이트 URL로 전체 서비스를 통합 테스트
- ShopEasy 이커머스 애플리케이션의 전체 배포를 완료!