TIL - 20260805

juni·2026년 8월 5일

TIL

목록 보기
423/468

0805 인프라/DevOps 운영 심화 (4/N): S3 + CloudFront 정적 배포와 캐시 전략


✅ 1. S3 + CloudFront 정적 배포란 무엇인가?

  • S3 + CloudFront 정적 배포는 React/Vite 같은 프론트엔드 빌드 결과물을 S3에 올리고, CloudFront를 통해 사용자에게 빠르게 제공하는 배포 방식입니다.
  • 프론트엔드 빌드 결과물은 대부분 HTML, CSS, JavaScript, 이미지 같은 정적 파일입니다.
  • 이런 정적 파일은 별도 Node 서버 없이도 S3와 CDN으로 안정적으로 제공할 수 있습니다.
사용자 브라우저
  ↓
CloudFront
  ↓
S3 Bucket
  ↓
index.html, JS, CSS, 이미지

➕ 1-1. 왜 S3 + CloudFront를 쓸까?

  • 서버 관리 부담이 적습니다.
  • 정적 파일 제공 속도가 빠릅니다.
  • 트래픽이 늘어도 확장성이 좋습니다.
  • HTTPS 적용이 쉽습니다.
  • 백엔드 API 서버와 프론트 배포를 분리할 수 있습니다.
  • 프론트 배포는 파일 업로드와 캐시 무효화 중심으로 단순화됩니다.
Nginx 서버 직접 제공:
서버 관리 필요
서버 장애 시 프론트도 영향

S3 + CloudFront:
정적 파일은 CDN에서 제공
백엔드와 프론트 장애 범위 분리
  • 고객 화면처럼 이미지, 배너, 상품 상세 페이지가 많은 서비스에서는 CDN 배포가 특히 유리합니다.

✅ 2. S3와 CloudFront의 역할

구성요소역할
S3정적 파일 원본 저장소
CloudFrontCDN, 전 세계 엣지에서 파일 캐싱
Route 53도메인 DNS 연결
ACMHTTPS 인증서
GitHub Actions빌드/업로드 자동화
IAM배포 권한 제어

➕ 2-1. S3

S3:
빌드 결과물 저장

예:
dist/index.html
dist/assets/index-abc123.js
dist/assets/index-def456.css
dist/images/banner.webp

➕ 2-2. CloudFront

CloudFront:
사용자와 가까운 엣지 서버에서 정적 파일 제공

장점:
속도 개선
S3 직접 접근 차단 가능
HTTPS 적용
캐시 정책 제어

➕ 2-3. ACM

ACM:
CloudFront에 연결할 HTTPS 인증서 관리

주의:
CloudFront용 ACM 인증서는 us-east-1 리전에 만들어야 함
  • S3는 파일 저장소이고, CloudFront는 사용자에게 빠르게 전달하는 CDN입니다.
  • 운영에서는 S3를 직접 공개하기보다 CloudFront만 공개하는 구조가 좋습니다.

✅ 3. 정적 프론트엔드 빌드 결과물

  • Vite/React 프로젝트에서 npm run build를 실행하면 보통 dist 폴더가 생성됩니다.
npm run build
dist/
  index.html
  assets/
    index-B2k3f9.js
    index-A8c2d1.css
  images/
    logo.webp
    banner.webp

➕ 3-1. 파일별 특징

파일특징
index.html앱의 진입점
JS/CSS assetshash가 붙는 경우 많음
이미지상품/배너/로고
favicon/manifest브라우저/앱 메타 정보

➕ 3-2. 중요한 차이

index.html:
항상 최신이어야 함

hashed JS/CSS:
파일명이 바뀌면 새 버전이므로 오래 캐시 가능
  • 이 차이를 이해해야 캐시 전략을 제대로 잡을 수 있습니다.
  • index.html과 assets를 같은 캐시 정책으로 두면 배포 후 문제가 생길 수 있습니다.

✅ 4. 기본 배포 흐름

1. 코드 수정
2. npm run lint
3. npm run test:run
4. npm run build
5. dist 파일 생성
6. S3로 업로드
7. CloudFront invalidation
8. 운영 URL Smoke Test

➕ 4-1. S3 업로드 예시

aws s3 sync dist/ s3://YOUR_BUCKET_NAME --delete

➕ 4-2. CloudFront 캐시 무효화

aws cloudfront create-invalidation \
  --distribution-id YOUR_DISTRIBUTION_ID \
  --paths "/*"

➕ 4-3. 배포 후 확인

운영 URL 접속
새 버전 반영 확인
상품 상세 접속
상담 신청 모달 확인
관리자 로그인 확인
상담 목록 조회 확인
브라우저 Network 탭에서 API 주소 확인
  • 배포는 업로드가 끝이 아닙니다.
  • CloudFront 캐시가 반영됐는지, 운영 URL에서 핵심 흐름이 정상인지 확인해야 합니다.

✅ 5. S3 버킷 공개 방식

  • 예전에는 S3 정적 웹 호스팅을 켜고 버킷을 public으로 열어 제공하는 경우가 많았습니다.
  • 운영에서는 가능하면 S3를 직접 공개하지 않고 CloudFront를 통해서만 접근하게 하는 것이 좋습니다.

➕ 5-1. 공개 버킷 방식

사용자
  ↓
S3 Website Endpoint 직접 접근

장점:

설정이 단순함
빠르게 테스트 가능

단점:

S3가 직접 공개됨
CloudFront 우회 접근 가능
보안/캐시/도메인 관리가 애매해질 수 있음

➕ 5-2. CloudFront OAC 방식

사용자
  ↓
CloudFront
  ↓
S3 private bucket

장점:

S3 직접 접근 차단
CloudFront를 통해서만 파일 제공
HTTPS/캐시/도메인 관리 일원화
  • 실무 운영에서는 S3 private bucket + CloudFront OAC 구조가 더 안전합니다.
  • 작은 테스트라면 public hosting으로 시작할 수 있지만, 운영 서비스는 CloudFront 중심 구조를 권장합니다.

✅ 6. OAI와 OAC

  • CloudFront에서 S3 private bucket에 접근하게 하는 방식으로 OAI와 OAC가 있습니다.
  • 최근에는 OAC를 사용하는 흐름이 더 권장됩니다.
구분의미
OAIOrigin Access Identity
OACOrigin Access Control

➕ 6-1. 개념

OAI/OAC:
CloudFront는 S3에 접근 가능
일반 사용자는 S3 직접 접근 불가

➕ 6-2. 운영 기준

S3 public access block 유지
CloudFront OAC 생성
S3 bucket policy에서 CloudFront distribution만 허용
사용자는 CloudFront 도메인 또는 커스텀 도메인으로 접속
  • 이렇게 하면 사용자가 S3 URL을 직접 알아도 파일을 가져가기 어렵습니다.
  • 도메인, HTTPS, 캐시 흐름도 CloudFront로 통일됩니다.

✅ 7. SPA 라우팅 문제

  • React Router 기반 SPA는 /products/1, /admin/consults 같은 경로가 실제 파일이 아닙니다.
  • 사용자가 해당 경로로 직접 접속하거나 새로고침하면 S3/CloudFront가 실제 파일을 찾으려다 404를 낼 수 있습니다.

➕ 7-1. 문제 흐름

사용자:
https://www.example.com/products/1 직접 접속

CloudFront/S3:
products/1 파일 찾음

결과:
파일 없음 → 404

➕ 7-2. 해결 방향

없는 경로 요청
  ↓
index.html 반환
  ↓
React Router가 클라이언트에서 경로 처리

➕ 7-3. CloudFront Custom Error Response

403 또는 404 응답 발생
  ↓
/index.html 반환
  ↓
HTTP status 200으로 응답
  • S3 private bucket + CloudFront 조합에서는 404 대신 403이 나오는 경우도 있습니다.
  • CloudFront에서 403/404를 /index.html로 돌려주는 설정을 확인해야 합니다.

✅ 8. /api 요청과 SPA fallback 충돌 주의

  • 같은 도메인에서 /api 경로를 API로 쓰는 경우, SPA fallback이 API 요청까지 index.html로 돌려버리면 안 됩니다.
정상:
https://example.com/api/products → API 서버

문제:
https://example.com/api/products → index.html

➕ 8-1. 분리 방식

서브도메인 분리:
www.example.com
api.example.com

경로 분리:
example.com/api
example.com/*

➕ 8-2. 권장

프론트 S3 + CloudFront:
www.example.com

백엔드 API:
api.example.com

장점:
CloudFront SPA fallback과 API 라우팅 충돌 감소
CORS/쿠키 정책만 명확히 관리하면 됨
  • 프론트와 API를 서브도메인으로 분리하면 구조가 깔끔합니다.
  • 쿠키 인증을 쓴다면 CORS, SameSite, Secure, domain 설정을 같이 봐야 합니다.

✅ 9. 캐시 전략 기본

  • S3 + CloudFront 배포에서 가장 중요한 부분 중 하나가 캐시입니다.
  • 캐시를 잘못 잡으면 새 배포가 반영되지 않거나, 오래된 JS와 최신 HTML이 섞여 화면이 깨질 수 있습니다.

➕ 9-1. 파일별 캐시 전략

파일캐시 전략
index.html짧게 또는 no-cache
hashed JS/CSS길게
이미지파일명 변경 기준으로 길게
favicon/manifest상황에 따라 중간
설정 JSON짧게

➕ 9-2. 핵심 원칙

index.html:
항상 최신이어야 함

assets/index-abc123.js:
파일명이 바뀌면 새 파일이므로 오래 캐시 가능

➕ 9-3. 문제 예시

사용자 브라우저:
이전 index.html 캐시 보유

S3:
이전 JS 파일은 삭제됨

사용자:
이전 index.html이 이전 JS 파일 요청

결과:
Chunk Load Error 또는 흰 화면
  • index.html을 오래 캐시하는 것은 위험합니다.
  • JS/CSS에 hash가 붙어 있다면 오래 캐시해도 비교적 안전합니다.

✅ 10. S3 업로드 시 Cache-Control 설정

  • aws s3 sync로 업로드할 때 파일별 Cache-Control을 다르게 지정할 수 있습니다.
  • 단순 sync 한 번으로는 파일별 캐시를 나누기 어렵기 때문에 명령을 분리하는 방식이 좋습니다.

➕ 10-1. index.html 짧은 캐시

aws s3 cp dist/index.html s3://YOUR_BUCKET_NAME/index.html \
  --cache-control "no-cache, no-store, must-revalidate" \
  --content-type "text/html"

➕ 10-2. assets 장기 캐시

aws s3 sync dist/assets/ s3://YOUR_BUCKET_NAME/assets/ \
  --cache-control "public, max-age=31536000, immutable"

➕ 10-3. 나머지 파일 업로드

aws s3 sync dist/ s3://YOUR_BUCKET_NAME \
  --exclude "index.html" \
  --exclude "assets/*"
  • 작은 프로젝트에서는 처음에 단순 전체 invalidation으로 시작해도 됩니다.
  • 하지만 배포 품질을 높이려면 index.html과 hashed assets의 캐시 정책을 분리하는 것이 좋습니다.

✅ 11. --delete 사용 주의

  • aws s3 sync dist/ s3://bucket --delete는 dist에 없는 S3 파일을 삭제합니다.
  • 깔끔한 배포에는 좋지만 Chunk Load Error 위험을 키울 수 있습니다.

➕ 11-1. 문제 상황

사용자가 이전 버전 페이지를 열어둠
  ↓
새 배포 시 --delete로 이전 JS 삭제
  ↓
사용자가 페이지 이동
  ↓
이전 JS chunk 요청
  ↓
파일 없음
  ↓
Chunk Load Error

➕ 11-2. 대응 방법

이전 assets를 일정 기간 보존
index.html은 최신화
오래된 assets 정리는 주기적으로 수행
ChunkLoadError 발생 시 새로고침 안내

➕ 11-3. 현실적인 기준

작은 서비스:
--delete 사용 가능, 문제 발생 시 새로고침 안내

관리자 작업 중단이 민감한 서비스:
assets 즉시 삭제 지양

배포 안정성 높이고 싶을 때:
버전별 prefix 배포 검토
  • --delete는 편하지만 운영 사용자가 페이지를 열어둔 상태를 고려해야 합니다.
  • 특히 관리자 화면에서 긴 작업을 하는 경우 주의가 필요합니다.

✅ 12. CloudFront Invalidation 전략

  • CloudFront는 엣지에 파일을 캐시합니다.
  • 새 배포 후 즉시 반영하려면 invalidation이 필요합니다.

➕ 12-1. 전체 invalidation

aws cloudfront create-invalidation \
  --distribution-id YOUR_DISTRIBUTION_ID \
  --paths "/*"

장점:

간단함
모든 파일 최신화 가능
작은 서비스에서 관리 쉬움

단점:

불필요한 무효화가 많음
규모가 커지면 비용/효율 고려 필요

➕ 12-2. index.html 중심 invalidation

aws cloudfront create-invalidation \
  --distribution-id YOUR_DISTRIBUTION_ID \
  --paths "/index.html" "/"

장점:

hashed assets는 파일명이 바뀌므로 그대로 장기 캐시 가능
무효화 범위가 작음

➕ 12-3. 추천 기준

초기/작은 서비스:
전체 invalidation으로 단순 운영

캐시 전략 정리 후:
index.html, root 경로 중심 invalidation

이미지 파일명 변경 없이 덮어쓰기:
해당 이미지 경로도 invalidation 필요
  • 파일명이 바뀌지 않는 이미지를 교체하면 CloudFront가 이전 이미지를 계속 보여줄 수 있습니다.
  • 이미지도 파일명에 버전/hash를 붙이는 습관이 좋습니다.

✅ 13. 버전별 prefix 배포

  • 더 안정적인 배포를 위해 빌드 결과물을 버전별 경로에 올리고, CloudFront가 참조하는 진입점만 바꾸는 방식도 있습니다.
s3://bucket/releases/2026-08-05-001/
  index.html
  assets/

s3://bucket/releases/2026-08-05-002/
  index.html
  assets/

➕ 13-1. 장점

이전 버전 보존
롤백 쉬움
assets 삭제로 인한 chunk error 감소
배포 이력 명확

➕ 13-2. 단점

설정 복잡
S3 용량 증가
CloudFront origin/path 관리 필요
배포 스크립트 복잡
  • 처음부터 도입할 필요는 없습니다.
  • 운영 안정성이 더 중요해지면 고려할 수 있습니다.

✅ 14. 롤백 전략

  • 프론트 배포 후 문제가 생기면 빠르게 이전 버전으로 되돌릴 수 있어야 합니다.

➕ 14-1. 단순 롤백

이전 안정 커밋 checkout
  ↓
운영 env로 build
  ↓
S3 재업로드
  ↓
CloudFront invalidation
  ↓
Smoke Test

➕ 14-2. artifact 보관 방식

배포마다 dist artifact 저장
  ↓
문제 발생 시 이전 artifact를 S3에 재업로드
  ↓
CloudFront invalidation

➕ 14-3. 롤백 전 확인

백엔드 API 변경과 호환되는가?
환경변수 변경이 있었는가?
프론트만 롤백해도 되는가?
CloudFront 캐시 무효화가 필요한가?
사용자에게 강제 새로고침 안내가 필요한가?
  • 프론트만 롤백하면 더 깨지는 경우도 있습니다.
  • 특히 API 응답 구조가 같이 바뀐 배포라면 백엔드와 호환성을 반드시 봐야 합니다.

✅ 15. GitHub Actions로 S3 + CloudFront 배포

  • 반복 배포는 GitHub Actions로 자동화할 수 있습니다.
  • 단, 운영 배포는 branch 기준과 권한을 명확히 해야 합니다.

➕ 15-1. 기본 흐름

main branch push
  ↓
checkout
  ↓
node setup
  ↓
install
  ↓
lint/test/build
  ↓
AWS credentials 설정
  ↓
S3 upload
  ↓
CloudFront invalidation

➕ 15-2. workflow 예시

name: Frontend Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 24

      - name: Install
        run: npm ci

      - name: Verify
        run: |
          npm run lint
          npm run test:run
          npm run build

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

      - name: Upload assets
        run: |
          aws s3 sync dist/ s3://${{ secrets.S3_BUCKET_NAME }} --delete

      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"

➕ 15-3. 주의

GitHub Secrets에 AWS key 저장
운영 배포 branch 제한
PR에서는 build/test만 실행
main merge 후 배포
배포 실패 시 알림 필요
AWS 권한 최소화
  • 처음에는 수동 배포 스크립트로 안정화하고, 그 다음 GitHub Actions로 옮겨도 됩니다.
  • AWS key 권한은 S3 업로드와 CloudFront invalidation에 필요한 최소 권한만 주는 것이 좋습니다.

✅ 16. IAM 권한 최소화

  • 배포용 IAM 사용자는 필요한 권한만 가져야 합니다.
  • 모든 AWS 권한을 주면 키 유출 시 피해가 커집니다.

➕ 16-1. 필요한 권한

S3:
대상 버킷 PutObject, DeleteObject, ListBucket

CloudFront:
CreateInvalidation

그 외:
가능하면 불필요한 권한 제거

➕ 16-2. 주의할 점

AdministratorAccess 금지
개인 AWS key와 회사 배포 key 분리
GitHub Secrets 외부 노출 주의
퇴사/교체 시 key rotation
CloudTrail로 사용 기록 확인 가능하게
  • 배포 자동화는 편하지만 키 관리가 허술하면 위험합니다.
  • 특히 회사 운영 AWS 계정에서는 최소 권한 원칙을 지켜야 합니다.

✅ 17. 환경변수와 빌드 시점

  • Vite/React 프론트 환경변수는 대부분 빌드 시점에 코드에 포함됩니다.
  • 빌드 후 S3에 올린 뒤 환경변수만 바꿔도 이미 배포된 JS에는 반영되지 않습니다.
.env.production
  ↓
npm run build
  ↓
JS bundle에 값 포함
  ↓
S3 업로드

➕ 17-1. 주의할 점

VITE_API_BASE_URL 변경 시 재빌드 필요
운영 빌드에 localhost 들어가면 치명적
프론트 env에 Secret 넣으면 노출
스테이징/운영 env 분리 필요

➕ 17-2. 배포 전 확인

grep -R "localhost" dist/ || true
  • 운영 빌드 결과물에 localhost가 들어가 있으면 거의 확실히 문제입니다.
  • 배포 전 VITE_API_BASE_URL이 운영 API를 가리키는지 확인해야 합니다.

✅ 18. API 도메인과 CORS

  • 프론트를 www.example.com, API를 api.example.com으로 분리하면 브라우저 기준 origin이 달라집니다.
  • 이 경우 백엔드 CORS 설정이 필요합니다.
Frontend:
https://www.example.com

API:
https://api.example.com

브라우저:
서로 다른 origin으로 판단

➕ 18-1. NestJS CORS 예시

app.enableCors({
  origin: ['https://www.example.com', 'https://admin.example.com'],
  credentials: true,
});

➕ 18-2. 쿠키 인증 시 주의

credentials: true
Access-Control-Allow-Origin은 * 불가
쿠키 secure true
sameSite 설정 확인
API 요청 withCredentials 설정

➕ 18-3. 프론트 axios

export const apiClient = axios.create({
  baseURL: env.apiBaseUrl,
  withCredentials: true,
});
  • S3 + CloudFront 배포 문제처럼 보여도 실제로는 CORS/Cookie 문제인 경우가 많습니다.
  • 로그인 유지가 안 되면 HTTPS, CORS, cookie, API client를 같이 확인해야 합니다.

✅ 19. CloudFront Custom Domain

  • CloudFront 기본 도메인은 xxxxx.cloudfront.net 형태입니다.
  • 운영에서는 보통 www.example.com, admin.example.com 같은 커스텀 도메인을 연결합니다.

➕ 19-1. 연결 흐름

Route 53 또는 DNS
  ↓
www.example.com CNAME/Alias
  ↓
CloudFront Distribution
  ↓
S3 Origin

➕ 19-2. 필요한 것

ACM 인증서
CloudFront Alternate domain name 설정
DNS record 설정
HTTPS 접속 확인

➕ 19-3. 주의

CloudFront용 ACM은 us-east-1
DNS 전파 시간 고려
www와 apex 도메인 처리 구분
인증서 SAN에 필요한 도메인 포함
  • 인증서 도메인과 CloudFront alternate domain name이 맞아야 합니다.
  • www.example.com만 인증서에 있고 admin.example.com이 없으면 관리자 도메인 HTTPS가 실패할 수 있습니다.

✅ 20. 고객 화면과 관리자 화면 배포 분리

  • 고객 화면과 관리자 화면을 같은 빌드로 운영할 수도 있고, 별도 배포할 수도 있습니다.

➕ 20-1. 같은 앱/같은 배포

www.example.com
  ├─ /
  ├─ /products
  └─ /admin

장점:

구조 단순
배포 한 번
공통 코드 공유 쉬움

단점:

관리자 코드가 고객 번들에 섞일 수 있음
권한/라우팅 관리 주의
고객/관리자 장애 범위가 같음

➕ 20-2. 고객/관리자 별도 앱

www.example.com:
고객 화면

admin.example.com:
관리자 화면

장점:

역할 분리 명확
번들 분리
권한/라우팅 관리 쉬움
관리자 장애와 고객 화면 분리 가능

단점:

배포 설정 2개
CloudFront/S3 버킷 관리 증가
공통 UI 공유 구조 필요

➕ 20-3. 추천

초기:
같은 앱으로 시작 가능

규모 커짐:
고객/관리자 별도 도메인과 별도 배포 검토

관리자 보안 중요:
admin.example.com 분리 권장
  • 온라인 판매몰에서는 고객 화면과 관리자 화면을 분리하면 운영상 명확해집니다.
  • 다만 현재 규모와 개발 속도도 고려해야 합니다.

✅ 21. 이미지와 CloudFront

  • 상품 이미지, 배너 이미지도 CloudFront를 통해 제공하면 속도와 캐시 측면에서 유리합니다.
  • 다만 이미지 교체와 캐시 전략을 잘 잡아야 합니다.

➕ 21-1. 이미지 캐시 문제

banner.png 교체
  ↓
파일명 동일
  ↓
CloudFront/브라우저는 이전 파일 캐시
  ↓
사용자에게 이전 배너 표시

➕ 21-2. 해결 방법

파일명에 버전 포함:
banner-20260805.webp

파일명에 hash 포함:
banner-a8f3.webp

교체 시 invalidation:
해당 이미지 경로 무효화

➕ 21-3. 추천

배너:
파일명 버전 관리

상품 이미지:
업로드 시 고유 key 생성

수정 잦은 이미지:
짧은 캐시 또는 파일명 변경

로고:
변경 드물면 긴 캐시 가능
  • 같은 파일명으로 계속 덮어쓰면 캐시 때문에 변경 반영이 늦어질 수 있습니다.
  • 이미지 파일명에 버전이나 hash를 붙이는 습관이 좋습니다.

✅ 22. 배포 스크립트 예시

  • 수동 배포를 하더라도 스크립트로 표준화하면 실수가 줄어듭니다.
#!/bin/bash
set -e

BUCKET_NAME="YOUR_BUCKET_NAME"
DISTRIBUTION_ID="YOUR_DISTRIBUTION_ID"

echo "Checking branch..."
CURRENT_BRANCH=$(git branch --show-current)

if [ "$CURRENT_BRANCH" != "main" ]; then
  echo "현재 브랜치가 main이 아닙니다: $CURRENT_BRANCH"
  exit 1
fi

echo "Installing and verifying..."
npm run lint
npm run test:run
npm run build

echo "Checking build output..."
grep -R "localhost" dist/ && {
  echo "dist 안에 localhost가 포함되어 있습니다. 환경변수를 확인하세요."
  exit 1
} || true

echo "Uploading assets..."
aws s3 sync dist/assets/ s3://$BUCKET_NAME/assets/ \
  --cache-control "public, max-age=31536000, immutable"

echo "Uploading index.html..."
aws s3 cp dist/index.html s3://$BUCKET_NAME/index.html \
  --cache-control "no-cache, no-store, must-revalidate" \
  --content-type "text/html"

echo "Uploading rest..."
aws s3 sync dist/ s3://$BUCKET_NAME \
  --exclude "index.html" \
  --exclude "assets/*"

echo "Invalidating CloudFront..."
aws cloudfront create-invalidation \
  --distribution-id $DISTRIBUTION_ID \
  --paths "/index.html" "/"

echo "Deploy completed."

➕ 22-1. 스크립트에서 확인할 것

브랜치 확인
빌드 전 검증
운영 env 확인
dist 안 localhost 검색
S3 bucket 이름 확인
CloudFront distribution 확인
캐시 정책 분리
배포 후 Smoke Test
  • 운영 배포 스크립트는 조금 귀찮아도 방어 로직을 넣는 것이 좋습니다.
  • 특히 bucket 이름과 distribution ID 실수는 조심해야 합니다.

✅ 23. 배포 후 Smoke Test

  • S3 업로드와 invalidation이 끝났다고 배포가 끝난 것은 아닙니다.
  • 운영 도메인에서 핵심 흐름을 확인해야 합니다.

➕ 23-1. 고객 화면 Smoke Test

메인 페이지 접속
상품 목록 접속
상품 상세 접속
대표 이미지/배너 확인
상담 신청 모달 열기
필수값 검증 확인
API 요청 도메인 확인
모바일 화면 확인

➕ 23-2. 관리자 화면 Smoke Test

관리자 로그인
상담 목록 조회
검색/필터 실행
상담 상세 열기
상태 변경 모달 열기
권한별 버튼 확인
엑셀 다운로드 버튼 확인

➕ 23-3. 캐시 확인

새로고침 후 최신 화면인가?
시크릿 모드에서도 정상인가?
Network 탭에서 index.html cache-control 확인
JS/CSS가 404 나지 않는가?
Chunk Load Error가 없는가?
  • 캐시 문제는 일반 새로고침만으로 놓칠 수 있습니다.
  • 시크릿 모드, 강력 새로고침, 모바일에서도 확인하면 좋습니다.

✅ 24. 자주 생기는 문제와 원인

➕ 24-1. 새 배포가 반영되지 않음

가능한 원인:
CloudFront 캐시
브라우저 캐시
index.html 캐시가 너무 김
invalidation 누락
다른 S3 bucket에 업로드
다른 distribution을 무효화

확인:

CloudFront invalidation 상태
S3 index.html 수정 시간
브라우저 Network cache-control
배포 bucket/distribution ID

➕ 24-2. 새로고침 시 404/403

가능한 원인:
SPA fallback 미설정
CloudFront custom error response 미설정
S3 private bucket에서 403 반환

해결:

403/404를 index.html로 응답하도록 CloudFront 설정
React Router 경로 확인
API 경로와 fallback 충돌 확인

➕ 24-3. 화면이 흰 화면

가능한 원인:
JS chunk 404
환경변수 오류
API Base URL undefined
브라우저 런타임 에러
이전 index.html과 새 assets 불일치

확인:

브라우저 Console
Network JS/CSS 404 여부
dist 안 환경변수
CloudFront invalidation
ErrorBoundary 로그

➕ 24-4. 로그인 유지 안 됨

가능한 원인:
CORS 설정 오류
withCredentials 누락
secure cookie 설정
sameSite 설정
API 도메인 HTTPS 문제
X-Forwarded-Proto 누락

확인:

브라우저 Application Cookie
API 응답 Set-Cookie
CORS response header
axios withCredentials
백엔드 cookie option

✅ 25. 실무 체크리스트

➕ 25-1. S3/CloudFront 설정 체크리스트

  1. S3 bucket이 운영용과 스테이징용으로 구분되어 있는가?
  2. S3 public access 정책이 의도대로 설정되어 있는가?
  3. CloudFront OAC/OAI로 S3 직접 접근을 제한했는가?
  4. CloudFront origin이 올바른 S3 bucket을 바라보는가?
  5. Custom domain이 CloudFront에 연결되어 있는가?
  6. ACM 인증서 도메인이 맞는가?
  7. Route 53 또는 DNS record가 올바른가?
  8. SPA fallback 설정이 되어 있는가?

➕ 25-2. 캐시 체크리스트

  1. index.html 캐시가 짧거나 no-cache인가?
  2. hashed JS/CSS assets는 장기 캐시 가능한가?
  3. 이미지 파일명 변경 전략이 있는가?
  4. CloudFront invalidation 경로가 적절한가?
  5. --delete 사용 시 이전 chunk 삭제 위험을 고려했는가?
  6. 배포 후 최신 화면이 보이는지 확인했는가?
  7. 시크릿 모드에서 접속 확인했는가?
  8. Chunk Load Error 대응 기준이 있는가?

➕ 25-3. 배포 체크리스트

  1. 현재 branch가 맞는가?
  2. 운영 env로 build했는가?
  3. npm run lint가 통과했는가?
  4. npm run test:run이 통과했는가?
  5. npm run build가 통과했는가?
  6. dist 안에 localhost가 남아 있지 않은가?
  7. 올바른 S3 bucket에 업로드했는가?
  8. 올바른 CloudFront distribution을 invalidation했는가?
  9. 배포 후 Smoke Test를 완료했는가?
  10. 롤백 기준이 있는가?

➕ 25-4. 보안 체크리스트

  1. 프론트 환경변수에 Secret이 들어가지 않았는가?
  2. GitHub Actions AWS 권한이 최소화되어 있는가?
  3. GitHub Secrets가 외부에 노출되지 않았는가?
  4. S3 bucket이 불필요하게 public이 아닌가?
  5. 관리자 앱 도메인이 의도대로 분리되어 있는가?
  6. API CORS origin이 운영 도메인으로 제한되어 있는가?
  7. 쿠키 인증 사용 시 HTTPS/SameSite/Secure 설정이 맞는가?
  8. 배포 로그에 민감정보가 찍히지 않는가?

✅ 26. AI에게 S3/CloudFront 문제를 물어볼 때 좋은 질문법

  • S3 + CloudFront 문제는 캐시, DNS, 인증서, S3 권한, SPA fallback, 환경변수 중 어디서 막혔는지 좁히는 것이 중요합니다.
  • 질문할 때는 현재 구조와 증상, 확인 결과를 같이 줘야 합니다.

➕ 26-1. 좋은 질문 예시

React + Vite 프론트엔드를 S3 + CloudFront로 배포하고 있어.

상황:
1. 빌드 결과물은 dist 폴더에 생성됨
2. S3 bucket은 private이고 CloudFront OAC로 접근함
3. 도메인은 www.example.com
4. API는 https://api.example.com 사용
5. React Router를 사용함
6. /products/1에서 새로고침하면 403 또는 404가 발생함
7. CloudFront custom error response 설정은 아래와 같음
8. S3 bucket policy는 아래와 같음
9. Network 탭과 CloudFront 응답 상태는 아래와 같음

요청:
- 가장 가능성 높은 원인
- CloudFront/S3에서 확인할 설정
- SPA fallback 설정 방법
- API 경로와 충돌 가능성
- 배포 후 확인할 Smoke Test
- 재발 방지 체크리스트
를 순서대로 정리해줘.

➕ 26-2. AI 답변 검증 기준

  1. S3와 CloudFront 역할을 구분하는가?
  2. SPA 라우팅 403/404 문제를 설명하는가?
  3. private bucket에서는 404 대신 403이 날 수 있음을 고려하는가?
  4. index.html과 assets 캐시 전략을 구분하는가?
  5. CloudFront invalidation을 언급하는가?
  6. API 도메인/CORS/Cookie 문제와 구분하는가?
  7. 프론트 env가 빌드 시점에 들어간다는 점을 설명하는가?
  8. 운영 Secret을 프론트 env에 넣으라고 하지 않는가?

📌 요약

  • S3 + CloudFront 정적 배포는 React/Vite 빌드 결과물을 S3에 저장하고 CloudFront CDN을 통해 사용자에게 빠르게 제공하는 방식입니다.
  • S3는 원본 파일 저장소이고, CloudFront는 사용자에게 가까운 엣지에서 파일을 캐시해 제공하는 CDN입니다.
  • 운영에서는 S3를 직접 public으로 열기보다 private bucket + CloudFront OAC 구조로 CloudFront를 통해서만 접근하게 하는 것이 좋습니다.
  • React Router 같은 SPA는 /products/1, /admin/consults 새로고침 시 실제 파일이 없으므로 CloudFront에서 403/404를 /index.html로 돌려주는 fallback 설정이 필요합니다.
  • 캐시 전략은 index.html과 hashed JS/CSS assets를 반드시 구분해야 합니다. index.html은 짧은 캐시, hashed assets는 긴 캐시가 기본입니다.
  • aws s3 sync --delete는 깔끔하지만 이전 JS chunk를 삭제해 Chunk Load Error를 만들 수 있으므로 운영 사용자 상황에 따라 조심해야 합니다.
  • CloudFront invalidation은 작은 서비스에서는 /* 전체 무효화로 단순하게 시작해도 되고, 캐시 전략이 정리되면 /index.html, / 중심으로 줄일 수 있습니다.
  • 프론트 환경변수는 빌드 시점에 JS에 포함되므로 VITE_API_BASE_URL 변경 후에는 반드시 재빌드가 필요하고, Secret은 절대 넣으면 안 됩니다.
  • 고객 화면과 관리자 화면은 처음에는 같은 앱으로 운영할 수 있지만, 규모가 커지거나 보안/운영 분리가 중요해지면 www.example.com, admin.example.com처럼 별도 배포를 검토할 수 있습니다.
  • S3/CloudFront 문제를 AI에게 물어볼 때는 S3 공개 여부, OAC/OAI, CloudFront custom error response, 캐시 정책, invalidation, DNS/ACM, 브라우저 Console/Network 결과를 함께 제공해야 정확한 분석이 가능합니다.

0개의 댓글