문제 상황: S3 + CloudFront로 배포 시 403 / 404 에러 발생
React 프로젝트를 S3 + CloudFront 조합으로 배포했는데, 루트 경로 /는 잘 열리지만, 사용자가 브라우저 주소창에 다음과 같은 경로를 직접 입력하거나 새로고침을 하면 에러가 발생한다.
예시)
https://cocomu.co.kr/login
https://cocomu.co.kr/about
https://cocomu.co.kr/user/123
발생하는 에러
- ❌ 403 Forbidden
- ❌ 404 Not Found
원인: SPA와 정적 서버의 라우팅 방식 차이
React는 대표적인 SPA(Single Page Application) 라이브러리이다.
SPA는 단 하나의 HTML 파일(index.html)을 기반으로 동작하고, 모든 페이지 간 이동은 브라우저의 JavaScript가 클라이언트에서 처리한다.
즉, /login, /about, /user/123 같은 경로는 실제로 서버에 별도 HTML 파일이 있는 게 아니라, index.html 하나에서 자바스크립트 라우터가 경로를 해석해서 화면을 보여주는 것이다!
하지만 정적 서버는 그렇게 동작하지 않음
CloudFront나 S3 같은 정적 파일 서버는 브라우저 주소에 /login이 있으면 그걸 정적 파일 경로로 인식해서 S3 버킷에서 /login이라는 파일이나 디렉토리를 찾는다. 만약 실제로 그런 파일이 없으면? → 403 또는 404 에러가 발생한다.
💡 추가 설명: 왜 403이 뜨는 경우도 있을까?
S3에서는 다음 두 상황 중 하나가 발생한다.
CloudFront는 SPA의 클라이언트 라우팅을 리디렉션이나 오류로 처리하는 특성이 있다.
상황 결과 요청한 경로가 아예 없음 404 Not Found 경로가 없고, 리스트 보기 권한도 없음 403 Forbidden
React에서 react-router-dom을 사용할 경우, 페이지 간 이동은 실제 페이지 전환 없이 브라우저 내부에서 처리되는데, CloudFront는 이런 경로를 실제 파일 경로로 인식한다.
결과적으로 해당 경로에 대응되는 정적 파일이 없으면, 403이나 404 같은 에러를 반환하게 된다.
결론
SPA는 클라이언트 라우터가 경로를 해석해서 보여줘야 하는데, CloudFront + S3 조합에서는 서버에 해당 경로의 실제 파일이 없기 때문에 에러가 발생한다.
이 문제를 해결하려면, CloudFront에서 발생하는 403 / 404 에러를 index.html로 리디렉션 시켜줘야 SPA가 정상적으로 라우팅을 이어갈 수 있다.
해결하기: SPA fallback을 위한 CloudFront 설정
SPA fallback이란?
존재하지 않는 경로 요청이 들어오면 무조건 index.html을 응답하도록 서버나 CDN에 설정하는 것을 의미한다.
그 이후 경로 해석은 React 라우터가 담당하게 되므로, 클라이언트 라우팅이 정상적으로 작동하게 된다.
먼저, 정적 파일이 올라간 S3와 연결된 CloudFront 배포 항목을 선택한 후, 상단 탭에서 [오류 페이지] 메뉴로 이동한다.
사용자 정의 오류 응답 생성 버튼을 누른 후 아래와 같이 설정해주면 된다.
- HTTP error code: 403
- Customize error response: Yes 선택
- Response page path: /index.html
- HTTP Response code: 200
정리하자면, "403 오류가 발생하면 /index.html을 대신 보여주고, 상태 코드는 200(정상 응답)으로 처리해달라"는 설정이다.
SPA는 실제 파일이 없는 경로로 접근할 수 있기 때문에, 이런 식으로 진입점을 항상 index.html로 fallback 시켜줘야 라우팅이 끊기지 않는다.
마찬가지로 404 오류에 대해서도 위와 동일하게 설정해주면 된다.
모든 설정을 마치고 나면 위의 사진과 같이 403, 404 오류에 대해 /index.html로 리디렉션되도록 등록되어 있어야 한다.
이제 S3 + CloudFront 환경에서도 SPA 라우팅이 정상적으로 동작할 것이다!
'Develop' 카테고리의 다른 글
gpt-error-analyzer 라이브러리 개발기: 실시간 에러 분석 자동화 (0) | 2025.04.08 |
---|---|
디스코드 알림봇 만들기: 반복 메시지, 슬래시 커맨드, 자동 등록까지 (0) | 2025.04.08 |
[ React ] useInsertionEffect 참조 에러 ( @emotion/react ) (0) | 2025.03.06 |
[ React Native ] Error while updating property 'borderTopLeftRadius' of a view managed by: RCTImageView (0) | 2025.01.08 |
[ CI/CD ] GitHub Actions로 AWS EC2 배포 시 환경변수 적용 문제 해결기 (0) | 2025.01.07 |