[Cloudfront+S3] Frontend 배포

taehee kim·2023년 3월 28일

0. 기술적용 배경

  • 기존에는 EC2를 통해 Frontend 배포를 지속해 왔는데 t2.medium 급의 성능이 아니면 Memory 부족으로 서버가 계속해서 다운되었음.
  • S3를 활용해 빌드한 정적파일을 배포하는 방식으로 하면 비용을 훨씬 더 절감할 수 있을 뿐만 아니라 성능적으로도 Cloudfront와 활용하여 유리하기 때문에 Cloudfront + S3로 react 프로젝트를 배포하기로 결정하였음.

1. 관련 기술 개념 정리

S3

  • aws S3은 버킷이라는 공간에 정적 콘텐츠를 저장하여 인터넷을 통해 접근할 수 있도록 하는 서비스이다. 정적 컨텐츠 배포 목적의 서버로도 활용할 수 있기 때문에 프론트엔드의 정적 콘텐츠를 배포시 활용할 수 있다.

Cloudfront

  • AWS에서 제공하는 CDN 서버.
  • HTTP → HTTPS : 손쉬운 설정으로 http 로의 접속을 https로 리디렉션 시켜줄 수 있음.
  • CDN 을 통한 더 빠른 페이지 응답속도 : S3으로만 배포하는 경우, 선택한 리전 내에서만 생성이 되기 때문에 해당 리전에서 멀어질수록 접속 속도가 느려짐. 하지만 CloudFront 를 이용하면 전 세계에 분포된 엣지 로케이션이라고 하는 데이터 센터의 엣지 서버를 사용해 콘텐츠를 캐싱하고, 사용자가 위치한 곳에서 가장 가까운 엣지 로케이션에서 콘텐츠를 제공할 수 있기 때문에 성능이 향상됨.
  • 그 외의 장점들은 다음 공식 문서 참고 : https://aws.amazon.com/ko/cloudfront/

2. 전반적인 과정 순서

  1. IAM 권한 설정
  2. S3 버킷 만들기
  3. 빌드된 프로젝트 S3 버킷에 업로드
  4. CloudFront 배포 생성
  5. 캐시 Invalidation(Purge) 하기

프론트엔드 프로젝트 빌드

  • npm run build
    • build 디렉토리 안에 정적파일로 빌드

1. IAM 권한 설정

  • aws cli 를 사용할 때 필요한 access key, secret key를 활용할 때 필요하다.
  • AmazonS3FullAccess, CloudFrontFullAccess를 권한으로 설정해준다.

2. S3 버킷 만들기

  • 버킷 이름과, 리전을 선택한다.
  • ACL 활성화
  • 모든 퍼블릭 엑세스 차단을 해제한다.
  • S3를 생성한다.
  • 정적 웹사이트 호스팅
    • 속성 탭에서 정적 웹사이트 호스팅을 활성화 시킨다.
      • nginx서버와 같이 정적 서버처럼 활용할 수 있다.
    • 인덱스 문서, 오류 문서를 index.html로 해준다.
      • React 와 같은 SPA는 index.html 파일하나만으로 랜더링하기 때문에 이렇게 설정 해준다.
  • 버킷 정책 편집
    • 버킷의 정책이란 버킷을 사용하는 사용자에게 어떤 권한을 부여해줄지를 말한다.
    • 정적 서버를 호스팅하기 때문에 모든 유저에게 GetObject권한을 부여하면 된다.
    • 정책 생성기를 클릭하여 다음과 같이 설정한다.
      • EffectAllow (유저가 접속할 수 있도록 설정)
      • Select Type of Policy에서는 S3 Bucket Policy를 선택
      • Principal에는 * 을 입력하고 (모든 유저에 대해서 라는 뜻입니다)
      • Action에는 GetObject를 선택.(유저들이 이 버킷에 접근할 수 있는 권한을 준다는 뜻입니다)
      • ARN에는 아까 버킷 정책 편집 페이지에 적혀있는 ARN을 입력하면 되는데, 끝에 /* 를 추가로 붙여준다.(*은 모든 오브젝트에 대해서 라는 의미입니다.)
    • 생성한 버킷 정책을 버킷 정책 탭에 붙여넣기.
    • 보통 다음과 같은 형태로 생성됨.
      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Sid": "PublicReadGetObject",
                  "Effect": "Allow",
                  "Principal": "*",
                  "Action": [
                      "s3:GetObject"
                  ],
                  "Resource": [
                      "arn:aws:s3:::Bucket-Name/*"
                  ]
              }
          ]
      }

3. 생성한 S3 버킷에 코드 업로드

  • aws-cli 설치
  • aws configure --profile [유저명]
  • 커맨드 입력후 입력창에 다음값들 입력 IAM에서 Access key Secret key생성하여 복사
    • AWS Access Key ID : (Access Key ID를 입력합니다)
    • AWS Secret Access Key : (절대 노출되면 안됩니다)
    • Default region name : ap-northeast-2
    • Default output format : json
  • s3에 배포
    • aws s3 sync ./build s3://[S3 버킷 이름] --profile=[사용자 아이디]

4. CloudFront 배포 생성

  • 원본 도메인은 클릭하여 우리가 생성한 S3 버킷을 선택.
    • 어떤 도메인을 캐싱할 것인지
  • S3 버킷 액세스는 OAI 사용을 눌러줌.
    • OAI 사용을 선택하면 아래와 같은 항목들이 나오는데, 새 OAI 를 생성해줌. (이미 가지고 있다면 기존 ID를 선택하면 됨.)
    • 자동으로 입력된 값을 사용하면 됨.
  • 아래로 내려 뷰어 프로토콜 정책에서 Redirect HTTP to HTTPS 를 선택함.(HTTPS인증은 따로 설정해야함.)
  • 이렇게 하면 http 접속을 https 로 리다이렉트 시킬 수 있음.
  • 아래로 내려 대체 도메인 이름에서 Route53으로 생성한 주소를 입력.
  • Route53을 이용하여 대체 도메인을 입력했다면, https 를 이용할 것이기 때문에 SSL 인증서가 필요함.
  • 인증서는 aws 에서 제공하는 AWS Certificate Manager 를 통하여 발급 받을 수 있음.
    • 위 작업들을 하기 위해서는
      • Route53에서 레코드를 생성하여 CloudFront에 도메인 부여
      • Certificate Manager를 통해 SSL인증서 발급.
        • 이때, 무조건 리전은 버지니아 북부를 선택해야함.

5. 캐시 Invalidation하기

  • S3에 파일을 새로 올리더라도 사용자는 CloudFront로 부터 정적파일을 받기 때문에 파일을 새로 받아오게 하기 위해서는 CloudFront를 Invalidation 하여야함.
  • aws cloudfront create-invalidation --profile=[사용자 아이디] --distribution-id [CloudFront ID] --paths /*

6. 문제 사항 해결

  • 프론트엔드에서 Cloudfront + S3를 통해 배포를 시도했지만 3가지 문제가 발생했다.
  1. 백엔드 Get API 호출 시 Forbidden 403이 발생함.
  2. 나머지 Method API들을 호출하면 Method Not Allowed(405)가 발생하였다.
  3. OAuth 인증후 서버에서 발급한 JWT Token을 Authorization header를 통해 보내 주게 되는데 403 응답이 발생하였다.

문제 원인

  • 원인은 브라우저에서 요청시 프론트엔드 프록시 서버를 통해 백엔드 서버로 요청을 주는 방식 때문이었다.
    • 이렇게 요청할 경우 다음과 같이 Request UrI의 domain을 프론트엔드 domain(web.42partner.com)으로 하여 요청하게 된다.

    • Untitled

    • 문제는 CloudFront, S3로 배포 할 경우 CloudFront의 Domain을 프론트엔드 domain(web.42partner.com)로 하기 때문에 브라우저에서의 요청이 CloudFront로의 요청으로 가는것 처럼 처리된다.
      Untitled

    1. 즉, Get이 아닌 Method를 호출 할 경우 CloudFront의 설정에서 Get Method만을 허용하도록 설정되었기 때문에 405응답이 온것이다.
    2. Get 메서드 인 경우에도 CloudFront설정에서 Root 경로만 설정해놓은 것과 달리 Backend API상의 경로로 요청하기 때문에 403, 404 해당 경로의 파일을 찾을 수 없다는 응답이 나오게 된다.
    3. Authorization Header는 S3에서 인증 관련 헤더로 활용될 수 있는데 Backend Server JWT token이 S3의 인증요청 데이터로 받아들여져 403응답이 나오게 된다.

문제 해결 방법

  • 이를 해결 하기 위해서는 Request UrI의 domain을 백엔드 domain (api.42partner.com)으로 하여 요청하게 하면 된다는 판단을 하였고 시도해 보았다.
  • Request URL을 직접적으로 백엔드로 설정하고 CORS를 위해 Request의 Origin을 프론트엔드 origin(https://web.42partner.com)으로 설정하였다.
    Untitled

7. 출처

profile
Fail Fast

0개의 댓글