Intro

React로 만든 웹사이트를 로컬에서 완성했더라도,
사용자가 언제 어디서나 빠르고 안정적으로 접속하려면 배포가 필요합니다.
배포 플랫폼은 다양하지만, 이번 글에서는 AWS S3 + CloudFront 조합을 사용합니다.
왜 S3 + CloudFront일까요?
  • S3: HTML, CSS, JS 등 정적 파일을 안전하게 저장하고 웹으로 제공하는 안정적인 스토리지
  • CloudFront: AWS의 글로벌 CDN으로 전 세계 사용자에게 빠른 응답 속도와 HTTPS 보안을 제공
  • 조합의 장점: 안정성, 속도, 보안을 모두 확보 가능
물론 더 간편한 방법도 있습니다.
예를 들어 Vercel은 GitHub 연동만으로 자동 빌드·배포가 가능하지만, 무료 요금제에서는 빌드 시간·대역폭 제한이 있고 인프라를 직접 제어하기 어렵습니다.
반면 S3 + CloudFront는 인프라를 직접 구성·관리할 수 있어, 대규모 트래픽 대응부터 캐시 정책·라우팅·보안 설정까지 세밀하게 조정할 수 있습니다.
이번 글에서는 React 웹을 AWS S3 + CloudFront로 배포하는 과정을 단계별로 안내합니다.
순서대로 따라 하면 AWS 인프라 위에서 안정적인 서비스를 운영할 수 있습니다.
다음 편에서는 여기에 나만의 도메인 연결과 HTTPS 적용까지 이어갈 예정입니다.

AWS S3 + CloudFront 개요

React 웹을 배포할 때 S3와 CloudFront는 서로를 보완하며 작동합니다.
각 서비스를 이해하면, 이 조합이 배포에서 자주 쓰이는 이유를 바로 알 수 있습니다.

1. S3 (Amazon Simple Storage Service)

  • 정적 파일 저장소
    HTML, CSS, JavaScript, 이미지 등 정적 파일을 안전하게 저장
  • 정적 웹 호스팅 지원
    별도의 서버 없이도 웹 페이지 제공 가능
  • 저렴하고 확장성 높음
    트래픽 증가 시 자동 확장, 사용량 기반 과금

2. CloudFront

  • CDN(Content Delivery Network)
    전 세계 엣지 로케이션에 콘텐츠를 캐싱해, 사용자와 가까운 서버에서 전달
  • HTTPS 지원
    무료 SSL 인증서 제공으로 안전한 통신 가능
  • 세부 제어 가능
    캐시 기간, 접근 권한, 헤더 설정 등 세밀한 정책 적용 가능

3. S3와 CloudFront를 함께 쓰는 이유

  1. 속도 향상
    S3 단독 호스팅보다 전 세계 어디서나 더 빠른 로딩 속도 제공
  2. 보안 강화
    Origin Access Control(OAC)로 S3를 비공개로 유지하면서 CloudFront만 접근 허용
  3. 안정적인 확장성
    대규모 트래픽 상황에서도 안정적 서비스 가능
  4. 세밀한 설정
    캐시 무효화, SPA 라우팅, 보안 헤더 추가 등 정밀 제어 가능

S3 버킷 생성하기

일반 구성

일반 구성
  • AWS 리전: 현재 로그인한 콘솔의 기본 리전이 자동으로 선택됩니다. 저는 배포 위치를 한국 사용자에게 최적화하기 위해 아시아 태평양(서울) 리전을 선택했습니다.
  • 버킷 이름: 전 세계적으로 고유해야 하며, 소문자·숫자·하이픈만 사용할 수 있습니다.
  • 기존 버킷에서 설정 복사: 다른 버킷의 설정값만 가져오는 기능입니다. 객체(파일)는 복사되지 않고, 접근 권한, 버전 관리, 암호화 같은 설정만 복사됩니다.
이번 배포에서는 Baro 프로젝트의 클라이언트 사이트를 올릴 예정이기 때문에, 프로젝트 이름을 반영한 baro-client라는 버킷 이름을 사용했습니다. 이렇게 하면 추후 여러 프로젝트를 구분하기에도 좋습니다.

객체 소유권 및 퍼블릭 설정

객체 소유권 및 퍼블릭 설정

객체 소유권 설정

  • ACL 비활성화(권장)를 선택했습니다.
    이 옵션을 사용하면 버킷과 그 안의 모든 객체의 소유권이 현재 계정으로 통일됩니다. ACL(액세스 제어 목록)은 사용하지 않고, 대신 버킷 정책을 통해 접근 권한을 관리합니다. 이렇게 하면 권한 설정이 단순해지고 보안 관리가 쉬워집니다.

퍼블릭 액세스 차단 설정

  • 모든 퍼블릭 액세스 차단을 체크했습니다.
    기본적으로 S3는 외부에서 함부로 접근할 수 없도록 퍼블릭 액세스를 차단하는 것이 안전합니다.
    단, 나중에 CloudFront를 연결할 때는 퍼블릭 액세스를 풀지 않고도 접근할 수 있도록 Origin Access Control(OAC)을 사용할 예정입니다.
Tip: React 웹을 직접 S3 정적 웹 호스팅으로만 배포하는 경우엔 퍼블릭 접근 허용이 필요하지만, CloudFront를 거칠 땐 이렇게 차단해도 무방합니다.

이 외

객체 소유권 및 퍼블릭 설정 상세 화면

버전 관리

  • 비활성화를 선택했습니다.
    버전 관리는 같은 객체의 여러 버전을 저장하고 복원할 수 있는 기능입니다. 프로젝트에 따라 유용할 수 있지만, 정적 웹 배포에서는 필요하지 않고 저장 공간(비용)을 불필요하게 차지할 수 있습니다.
    추후 파일 이력 관리가 필요하다면 활성화할 수 있습니다.

태그

  • 태그는 버킷에 라벨을 붙여 비용 추적이나 프로젝트 구분을 쉽게 하는 기능입니다.
    이번 배포에서는 태그 없이 진행하지만, 회사나 팀 단위 프로젝트에서는 프로젝트명·환경(dev/prod) 같은 태그를 지정하면 관리가 편리합니다.

기본 암호화

  • Amazon S3 관리형 키(SSE-S3)를 선택했습니다.
    이 옵션은 S3가 자동으로 서버 측에서 객체를 암호화해 저장합니다. 따로 키를 관리할 필요가 없고, 기본 보안이 보장됩니다.
    AWS KMS를 사용하면 직접 키를 관리할 수 있지만, 비용이 추가되고 설정이 복잡해질 수 있습니다.

React 빌드 파일 업로드

  1. 로컬에서 npm run build 또는 yarn build 실행 → build 폴더 생성
  2. 폴더 안의 내용물만 선택해 AWS S3 콘솔의 버킷으로 드래그 앤 드롭
Tip: build 폴더 자체를 업로드하면 경로가 꼬여 CloudFront에서 파일을 찾지 못합니다.

정적 웹 사이트 호스팅

S3 버킷 속성 탭 → 페이지 맨 아래 정적 웹 사이트 호스팅 섹션 이동
정적 웹 사이트 호스팅 1
편집 버튼 클릭 후 아래와 같이 설정
정적 웹 사이트 호스팅 2
정리하면 다음과 같습니다.
  • S3 버킷으로 이동
    AWS S3 콘솔에서 방금 생성한 버킷을 클릭한 후, 속성 탭으로 들어갑니다.
  • 정적 웹 사이트 호스팅 활성화
    페이지를 맨 아래까지 스크롤하면 정적 웹 사이트 호스팅 섹션이 보입니다.
    편집 버튼을 눌러 설정 화면으로 들어갑니다.
  • 설정 값 입력
    • 호스팅 유형: 정적 웹 사이트 호스팅 활성화 선택
    • 인덱스 문서: index.html

CloudFront 배포 생성

Get started 단계

Get started 단계
  • Distribution name
    • CloudFront 배포 이름. 관리 편의를 위해 S3 버킷명과 동일하게 설정
    • 저는 S3 버킷 이름과 동일하게 baro-client로 입력했습니다.
  • Description (optional)
    • 배포에 대한 간단한 설명을 추가할 수 있습니다.
    • 필수는 아니므로 필요할 때만 입력합니다.
  • Distribution type
    • Single website or app: 하나의 웹사이트 또는 애플리케이션을 배포할 때 선택합니다.
    • Multi-tenant architecture: 여러 도메인에서 동일한 설정을 공유해야 하는 SaaS 환경에 적합합니다.
    • 저는 React 웹앱 단일 배포이므로 Single website or app을 선택했습니다.

Specify origin 단계

CloudFront 오리진 설정 화면

S3 origin

  • baro-client.s3.ap-northeast-2.amazonaws.com
    • CloudFront가 가져올 콘텐츠의 원본(오리진) 주소입니다.
    • 여기서는 방금 만든 S3 버킷이 오리진이 됩니다.

Origin path (optional)

  • 오리진 내부의 특정 하위 폴더만 지정해서 CloudFront가 가져오도록 하는 옵션입니다.
  • 예를 들어 S3 버킷 안에 /build 폴더만 배포하고 싶다면 /build를 입력하면 됩니다.
  • 비워두면 S3 버킷 전체를 대상으로 합니다.
  • 저는 build 폴더 안에 파일들을 올렸기때문에 비워두었습니다.
CloudFront 오리진 경로 설정 화면

Allow private S3 bucket access to CloudFront

  • 체크하면 CloudFront가 OAC(Origin Access Control)를 통해 S3 버킷에 접근할 수 있도록 권한을 자동 부여합니다.
  • Public Access를 열지 않고도 CloudFront에서만 S3를 읽을 수 있게 하므로 보안상 권장됩니다.

Origin settings

  • Use recommended origin settings: AWS가 권장하는 기본값을 사용 (대부분의 경우 이걸 선택)
  • Customize origin settings: 캐시 동작, 요청 정책 등을 직접 설정

Cache settings

  • CloudFront가 콘텐츠를 얼마나 오래 캐싱할지, 어떤 조건에서 원본에서 다시 가져올지를 결정
  • 기본적으로 S3에 최적화된 캐시 정책이 적용됩니다.
저는 Settings 부분은 기본 값으로 뒀습니다.

Enable security 단계

CloudFront 보안 설정 화면

AWS WAF란

AWS WAF는 웹 애플리케이션 방화벽으로, 웹 애플리케이션을 공격이나 취약점으로부터 보호하는 서비스입니다.
예를 들어 다음과 같은 공격을 방어합니다.
  • SQL Injection
  • Cross-Site Scripting (XSS)
  • 악성 봇 트래픽
  • 특정 국가/지역 또는 IP 주소 차단
저는 비활성화를 선택했습니다.

이후 설정들

배포한 CloudFront에 들어가서 배포 도메인으로 사이트에 접속을 해보면
CloudFront 배포 도메인 접속 화면
해당 화면과 비슷한 화면이 나올것입니다. 일단 여기까지 왔으면 거의 다 된겁니다.
일반에서 설정 편집을 들어가면 밑과 같은 화면이 나올텐데.
CloudFront 일반 설정 화면
Default root objectindex.html로 설정합니다.
CloudFront는 / 경로 요청 시 지정한 기본 파일을 반환합니다.
기본 파일을 지정하지 않으면 403 또는 404 오류가 발생할 수 있습니다.
React, Vue, Angular 같은 SPA는 모든 라우팅을 클라이언트에서 처리하므로,
서버는 모든 경로에 대해 index.html을 반환해야 합니다.
이후 자바스크립트 라우터가 알맞은 페이지를 렌더링합니다.
마지막으로, 오류 페이지 설정에서 403/404 상태 코드에 대해 index.html을 반환하도록 지정하면 배포가 완료됩니다.
객체 소유권 및 퍼블릭 설정 상세 화면
객체 소유권 및 퍼블릭 설정 상세 화면

Outro

이제 CloudFront 배포 도메인에 접속하면, 방금 업로드한 React 웹사이트가 정상적으로 표시됩니다.
배포 화면
여기까지 완료했다면 AWS S3 + CloudFront를 활용한 기본 배포 과정이 끝났습니다.
다음 단계에서는 맞춤 도메인 연결과 HTTPS 적용을 통해, 더 전문적이고 신뢰성 있는 서비스 환경을 구축하는 방법을 알아보겠습니다.