React 배포 전 과정 톺아보기

원민관·2025년 9월 13일

deployment

목록 보기
6/7
post-thumbnail

0. 프론트엔드 배포 과정 🎯

React 프로젝트를, Amazon 서비스를 통해 배포하는 과정을 다룹니다.

추가적으로 Github Actions를 활용해서 수정 사항의 통합과 배포의 자동화 즉, CI/CD를 구축하는 전 과정에 대해 기술하고자 합니다.


(이 자료는 제가 만들었고, 저작권법에 의한 보호를 받지 않습니다. 마음껏 활용해서 글로벌 기업의 CEO가 되십쇼.)

저는 전체적인 흐름이 이해가 되지 않으면 내용을 잘 흡수하지 못하는 타입입니다. 그래서 어떤 작업을 하거나 문서를 읽기 전에 전체적인 흐름을 파악하는 데에 노력의 절반을 투입합니다. 프론트엔드 프로젝트를 배포하고 CI/CD를 구축하는 작업은, 지나고 보면 그리 어렵지 않지만 처음 시도할 때에는 참 막막합니다.

그래서 만약 프론트엔드 배포를 AWS를 통해 처음 진행하시는 분께서 이 글을 접하셨다면, 각 목차의 -1에 해당하는 서비스의 사용 이유를 먼저 쭉 훑어보시고 전체적인 흐름을 우선적으로 파악하시는 것을 권장 드립니다.

1-1 => 2-1 => ... => 4-1만 읽어도 프론트엔드 배포의 전 과정이 이해되도록 글을 설계했습니다. 전체적인 흐름을 스스로 도식화할 수 있을 때, 다시 전체 글을 읽게 되면 차원이 다른 이해를 경험하실 수 있습니다.

1. Amazon S3 🎯

1-1. Amazon S3 사용 이유 ✍️

Amazon S3는 Simple Storage Service로, 사진이나 동영상과 같은 데이터를 저장하고 검색할 수 있는 파일 저장소입니다.

그런데 프론트엔드 프로젝트를 배포하는데 왜 S3라는 서비스를 사용하는 것일까요?


Amazon S3는 정적 웹 사이트 호스팅을 지원합니다.

현대의 웹 개발에서는 SPA(Single Page Application) 방식이 널리 사용됩니다. SPA는 하나의 HTML 페이지(index.html)에서 JavaScript를 통해 동적으로 콘텐츠를 변경하여 마치 여러 페이지를 이동하는 것처럼 보이게 하는 애플리케이션입니다.

React, Vue.js, Angular 같은 프레임워크로 개발된 SPA는 빌드 과정을 거쳐 HTML, CSS, JavaScript 파일로 변환됩니다. 이렇게 빌드 된 파일들은 본질적으로 정적 파일입니다. 텍스트 파일의 확장자가 .txt이고 한글 파일의 확장자가 .hwp인 것처럼, HTML, CSS, JavaScript의 확장자는 .html / .css / .js입니다. 일반 텍스트 파일과 마찬가지이지만, 프로그래밍 언어로 작성된 파일이라는 점에서만 차이가 있습니다.


SPA의 핵심은 초기에 모든 필요한 리소스를 다운로드한 후, 서버와의 추가적인 통신 없이 클라이언트 사이드에서 라우팅과 상태 관리를 처리한다는 것입니다. 이는 별도의 서버 로직이 필요하지 않다는 의미이므로, S3의 정적 웹 사이트 호스팅만으로도 충분히 SPA를 배포하고 운영할 수 있습니다.

결국 React나 Vue.js로 개발한, 복잡해 보이는 웹 애플리케이션도 빌드 후에는 단순한 HTML, CSS, JS 파일 묶음이 되므로, S3라는 파일 저장소에서도 완벽하게 동작할 수 있는 것이죠.

빌드의 결과물이 정적 파일 묶음이기에, S3라는 파일 저장소 서비스에서 정적 웹 사이트 호스팅 서비스를 제공하는 것은 대단히 특별하다고 보기는 어렵습니다.

1-2. 버킷 생성 + 정책 설정 ✍️

S3는 파일 저장소입니다. S3에서 버킷(Bucket)은 하나의 저장소를 의미하고, 버킷에 업로드된 개별 파일을 객체(Object)라고 부릅니다.

버킷을 생성할 때 다른 설정들은 기본값을 유지하되, 모든 퍼블릭 액세스 차단의 체크는 반드시 해제해야 합니다.

처음에는 S3 버킷 자체만으로 웹 사이트가 정상적으로 표시되는지 테스트해야 하기에, 전체 공개 설정을 해야 합니다. 모든 퍼블릭 액세스 차단의 체크를 해제하는 것이 곧 전체 공개를 의미합니다.

이후에는 모든 트래픽이 CloudFront를 통해서만 S3 버킷에 도달하도록 강제해야 하기 때문에 다시 모든 퍼블릭 액세스 차단에 체크를 적용할 것입니다. 이에 대해서는 CloudFront에서 추가적인 설명이 있을 예정입니다.


다음으로는 권한 설정입니다.

이전에 버킷 생성에서 모든 설정을 기본값으로 유지했고 모든 퍼블릭 액세스 차단의 체크를 해제했다면, 정상적으로 버킷이 생성되었을 것입니다. 해당 버킷의 권한 탭으로 들어가면 버킷 정책을 편집하는 섹션을 확인할 수 있습니다.

버킷 정책이란, 개별적인 S3 버킷 자체에 직접 연결하는 JSON 형식의 권한 문서입니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "statement1",
            "Principal": "*",
          	"Effect": "Allow",
            "Action": [
              "s3:GetObject"
              ],
            "Resource": [
              "arn:aws:s3:::<버킷-이름>/*"
              ],
        }
    ]
}

위 내용을 복사해서 붙여 넣습니다. 우리가 설정한 이름에 해당하는 S3 버킷 안의 모든 파일을, 인터넷상의 누구나 다운로드할 수 있도록 허용하는 정책입니다.

1-3. IAM에서 액세스 키 발급 ✍️

AWS IAM(Identity and Access Management)에서 액세스 키를 발급받아야 Github Actions에서 S3에 배포할 때 사용할 수 있습니다.

IAM 콘솔로 이동하여 새 사용자를 생성합니다. 사용자 이름은 github-actions-user와 같이 용도가 명확하게 드러나는 이름으로 설정하는 것을 권장합니다.


권한 설정에서는 직접 정책 연결 옵션을 선택하고, 다음과 같은 정책을 추가해야 합니다.

  • AmazonS3FullAccess: S3 버킷에 파일을 업로드하고 관리하기 위함
  • CloudFrontFullAccess: CloudFront 배포를 무효화(invalidation) 하기 위함

여기서 CloudFront 배포를 무효화한다는 것은, 전 세계 서버(엣지 로케이션)에 저장된 파일의 복사본(캐시)을 강제로 삭제하여 사용자들이 즉시 최신 버전의 파일을 받아보게 만드는 것을 의미합니다.


사용자 생성이 완료되면, 해당 사용자의 보안 자격 증명 탭에서 액세스 키를 생성합니다. 이때 생성되는 Access Key IDSecret Access Key는 Github Secrets에 저장할 예정이므로 안전한 곳에 별도로 보관해야 합니다.

1-4. S3 업로드 + 웹 호스팅 설정 ✍️

React 프로젝트를 빌드하고 결과물을 S3 버킷에 업로드해 보겠습니다.

먼저 React 프로젝트를 빌드 합니다.

yarn build

빌드 과정에서 여러 가지 에러가 발생할 수 있습니다. 열심히 디버깅하시면 되겠습니다. 에러가 모두 수정되면, 빌드가 완료됩니다.

빌드가 완료되면 dist 폴더가 생성됩니다. 이 폴더 안의 모든 파일을 S3 버킷에 업로드해야 합니다. 아래 명령어를 통해 빌드 된 폴더를 업로드합니다.

aws s3 sync ./dist/ s3://<버킷-이름> --delete

로컬 컴퓨터의 ./dist/ 폴더를 지정한 버킷에 동기화하며, 로컬에는 없는 불필요한 파일은 S3 버킷에서 삭제하는 명령어입니다.


S3 버킷에서 웹 호스팅을 활성화하려면, 버킷의 속성 탭에서 정적 웹 사이트 호스팅 섹션을 찾아 편집을 클릭합니다.

활성화를 선택하고, 다음과 같이 설정합니다.

  • 호스팅 유형: 정적 웹 사이트 호스팅
  • 인덱스 문서: index.html
  • 오류 문서: index.html

설정을 저장하면 버킷 웹사이트 엔드 포인트 URL이 생성됩니다. 이 URL로 접속하면 업로드한 React 애플리케이션이 정상적으로 표시되는지 확인할 수 있습니다.

2. Amazon CloudFront 🎯

2-1. Amazon CloudFront 사용 이유 ✍️

우리는 S3 버킷에 빌드 된 컨텐츠(정적 파일)를 업로드했습니다.

Amazon CloudFront는 컨텐츠(파일, 동영상 등)를 빠르게 전송하게 해주는, CDN(Content Delivery Network) 서비스입니다. S3 파일 저장소가 만약 한국에 있다면, 미국에 있는 제임스는 S3로부터 원하는 데이터를 전송받으려면 한국 사용자보다 더 오랜 시간을 기다려야 할 것입니다.

Amazon CloudFront는 전 세계 곳곳에 컨텐츠의 복사본을 저장해놓을 수 있는 임시 저장소를 구축해놓은 네트워크를 제공합니다. 제임스는 한국 사용자만큼이나 빠른 속도로 본인이 요청한 컨텐츠를 받을 수 있게 되는 것이죠.

다만, 컨텐츠 전송 성능 향상만을 위해서 CloudFront를 사용하는 것은 아닙니다.

S3는 HTTPS를 적용하는 기능을 제공하고 있지 않습니다. 즉 HTTPS를 적용하기 위해서는 S3의 앞단에 CloudFront를 배치해야 합니다. CloudFront에는 HTTPS를 적용할 수 있기 때문이죠. 컨텐츠 전송 성능의 향상과 더불어 HTTPS 적용을 통한 보안 강화를 위해 Amazon CloudFront라는 CDN 서비스를 이용하는 것입니다.

2-2. Amazon CloudFront 설정 ✍️

CloudFront 콘솔에서 새 배포를 생성합니다. 원본(Origin) 설정에서는 앞서 생성한 S3 버킷을 선택합니다.


원본 설정:

  • Origin Domain: S3 버킷의 정적 웹사이트 엔드 포인트 URL 사용 (REST API 엔드 포인트가 아님)
  • Origin Access: Origin Access Control settings (recommended) 선택

기본 캐시 동작 설정:

  • Viewer Protocol Policy: Redirect HTTP to HTTPS 선택
  • Allowed HTTP Methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE 선택
  • Cache key and origin requests: Cache policy and origin request policy (recommended) 선택

배포 설정:

  • Price Class: 원하는 지역에 따라 선택
  • Default Root Object: index.html

사용자 정의 오류 페이지 설정:
SPA의 클라이언트 사이드 라우팅을 지원하기 위해 404 오류를 index.html로 리디렉션해야 합니다.

  • HTTP Error Code: 404
  • Response Page Path: /index.html
  • HTTP Response Code: 200

배포 생성 후 상태가 Deployed가 될 때까지 기다립니다.


이제 앞서 설정한 S3 버킷 정책을 업데이트해야 합니다. 아래의 내용을 입력합니다.

{
    "Version": "2012-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<버킷-이름>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::<AWS-계정-ID>:distribution/<CloudFront-배포-ID>"
                }
            }
        }
    ]
}

마지막으로 S3 버킷의 모든 퍼블릭 액세스 차단 설정을 다시 활성화하여 CloudFront를 통해서만 접근할 수 있도록 합니다.

3. Amazon Route 53 🎯

3-1. Amazon Route 53 사용 이유 ✍️

현재까지의 작업으로 CloudFront를 통해 React 애플리케이션에 접근할 수 있지만, CloudFront에서 제공하는 기본 도메인은 d1ddsddads.cloudfront.net과 같은 형태로 사용자가 기억하기 어렵습니다.

Route 53은 AWS의 DNS(Domain Name System) 웹 서비스로, 도메인 이름을 관리하고 DNS 레코드를 설정할 수 있게 해줍니다. 우리가 구매한 도메인(예: myapp.com)을 CloudFront 배포와 연결하여 사용자가 기억하기 쉬운 주소로 접근할 수 있게 만드는 것이 Route 53의 역할입니다.

또한 Route 53은 SSL/TLS 인증서 발급을 위한 도메인 검증 과정에서도 필요합니다. AWS Certificate Manager(ACM)에서 HTTPS를 위한 인증서를 발급받을 때, 도메인 소유권을 확인하는 과정에서 Route 53의 DNS 레코드 설정이 활용됩니다.

3-2. Amazon Route 53 설정 ✍️

먼저 Route 53에서 호스팅 영역(Hosted Zone)을 생성해야 합니다. 이는 구매한 도메인에 대한 DNS 설정을 관리하는 공간입니다.

Route 53 콘솔에서 호스팅 영역 생성을 클릭하고 도메인 이름을 입력합니다. 호스팅 영역이 생성되면 4개의 NS(Name Server) 레코드가 자동으로 생성됩니다.

도메인을 구매한 등록 업체(예: 가비아, 후이즈 등)에서 네임서버를 Route 53에서 제공하는 4개의 네임서버로 변경해야 합니다. 이 과정은 도메인 등록 업체마다 다르지만, 일반적으로 도메인 관리 페이지에서 네임서버 설정을 찾아 변경할 수 있습니다.


SSL/TLS 인증서 발급:
AWS Certificate Manager(ACM) 콘솔에서 새 인증서를 요청합니다.

  • 도메인 이름 추가: myapp.com*.myapp.com (와일드카드 도메인)
  • 검증 방법: DNS 검증 선택

인증서 요청 후 도메인 검증을 위한 CNAME 레코드가 제공됩니다. 이 레코드를 Route 53 호스팅 영역에 추가해야 합니다. ACM 콘솔에서 Route 53에서 레코드 생성 버튼을 클릭하면 자동으로 추가됩니다.


CloudFront와 도메인 연결:
CloudFront 배포 설정을 업데이트합니다.

  • Alternate Domain Names (CNAMEs): myapp.com 추가
  • Custom SSL Certificate: 앞서 발급받은 ACM 인증서 선택

Route 53 레코드 생성:
Route 53 호스팅 영역에서 A 레코드를 생성합니다.

  • 레코드 이름: 비워두거나 www
  • 레코드 유형: A
  • 별칭: 예
  • 트래픽 라우팅 대상: CloudFront 배포 선택

이제 구매한 도메인으로 React 애플리케이션에 HTTPS를 통해 안전하게 접근할 수 있습니다.

4. Github Actions 🎯

4-1. Github Actions 사용 이유 ✍️

지금까지의 과정을 통해 React 애플리케이션을 성공적으로 배포했습니다. 하지만 코드를 수정할 때마다 수동으로 빌드하고, S3에 업로드하고, CloudFront를 무효화하는 작업을 반복해야 합니다. 이는 매우 번거롭고 실수가 발생할 가능성이 높습니다.

Github Actions는 소프트웨어 개발 워크플로우를 자동화하는 CI/CD(Continuous Integration/Continuous Deployment) 플랫폼입니다. 코드가 Github 레포지토리에 push 되거나 풀 리퀘스트가 생성될 때 자동으로 정의된 작업들을 수행할 수 있습니다.

우리의 경우, main 브랜치에 코드가 push될 때마다 다음 작업들이 자동으로 실행되도록 설정할 것입니다.

  1. 레포지토리 체크아웃
  2. AWS Credentials 설정
  3. .env.production 파일 생성
  4. 프로젝트 빌드 (client 폴더 기준)
  5. S3에 업로드 (dist 폴더 기준)
  6. CloudFront 캐시 무효화

이를 통해 개발자는 코드 작성에만 집중할 수 있고, 배포는 완전히 자동화되어 실수 없이 일관된 방식으로 진행됩니다.

4-2. Github Actions 설정 ✍️

Github 레포지토리에서 Settings > Secrets and variables > Actions로 이동하여 다음 시크릿들을 추가합니다.

  • AWS_ACCESS_KEY_ID: IAM에서 발급받은 액세스 키 ID
  • AWS_SECRET_ACCESS_KEY: IAM에서 발급받은 시크릿 액세스 키
  • DOTENV_PROD: 프로덕션에서 사용할 .env.production 파일 내용

프로젝트 루트에 .github/workflows/deploy.yml 파일을 생성하고 다음과 같이 작성합니다.

name: Deploy To S3

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      # (1) 레포지토리 체크아웃
      - name: Checkout Repository
        uses: actions/checkout@v4

      # (2) AWS Credentials 설정
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-2
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      # (3) .env.production 파일 생성
      - name: Create .env.production file
        run: |
          echo "${{ secrets.DOTENV_PROD }}" > .env.production
        working-directory: ./client

      # (4) 프로젝트 빌드 (client 폴더 기준)
      - name: Build Project
        run: |
          yarn install
          yarn build
        working-directory: ./client

      # (5) S3에 업로드 (dist 폴더 기준)
      - name: Upload to S3
        run: |
          aws s3 sync ./dist/ s3://<버킷-이름> --delete
        working-directory: ./client

      # (6) CloudFront 캐시 무효화
      - name: Invalidate CloudFront Cache
        run: |
          aws cloudfront create-invalidation --distribution-id <클라우드프론트-디스트리뷰션-아이디> --paths "/*"

5. 마무리 🎯

AWS 서비스와 Github Actions를 활용하여 React 프로젝트의 완전한 CI/CD 파이프라인을 구축했습니다.

구축한 시스템의 특징:

  • S3: 정적 파일 호스팅으로 비용 효율적
  • CloudFront: 전 세계 빠른 콘텐츠 전송 및 HTTPS 보안
  • Route 53: 사용자 친화적인 도메인과 SSL 인증서 관리
  • Github Actions: 완전 자동화된 배포 파이프라인

앞으로 고려해볼 점:

  • 환경별 배포 (개발/스테이징/프로덕션) 설정
  • 빌드 최적화 및 캐시 전략 개선
  • 모니터링 및 로그 분석 시스템 구축
  • 보안 설정 강화 (WAF, 보안 헤더 등)
profile
Write a little every day, without hope, without despair ✍️

0개의 댓글