next.js의 build 옵션으로 'export' 로 빌드한 정적 페이지를 cloudfront에 배포했을때 발생하는 Access Denied 오류 해결하기
export
로 빌드nextjs로 빌드한 간단한 사이드 프로젝트를 cloudfront에 배포했다. 서버 기능이 전혀 필요없는 완전한 정적 사이트기 때문에 빌드한 파일을 cloudfront를 통해 배포했는데 access denied
에러가 발생했다. 정확히는 메인 페이지인 /
로 접근한다음 페이지의 링크를 통해 다른 url로 이동하면 문제가 없지만 브라우저에서 직접 / 가 아닌 다른 링크로 접속하면 access denied 에러가 발생했다.
결론부터 말하자면 요청한 페이지를 cloudfront에서 찾을수 없어서 발생한 문제였다. 자료를 찾아보다 알게된 사실인데 next.js로 정적 빌드한 폴더의(out 폴더)
구조는 아래와 같다.
├── _next/
├── (퍼블릭 파일 폴더)/
├── (하위 경로가있는 path1)/
├── 404.html
├── favicon.ico
├── index.html
├── index.txt
├── (path2).html
├── (path2).txt
├── (path3).html
├── (path3.txt
...
루트 경로인 /
의 경우 보통은 cloudfront를 배포할때 / 경로로 들어오는 요청을 index.html로 응답하도록 설정해두니까 메인 페이지는 제데로 응답하는데 문제는 /path1
과 같은 다른 경로는 path1.html
과 같은 파일로 생성된다. 브라우저에서 /path1 으로 접근하면 cloudfront는 폴더내에서 path1 이라는 파일을 찾으려고하지만 path1 이라는 파일이 없기때문에(정확히는 path1.html 파일) access denied 에러가 뜨는것이다. 실제로 /path1 경로가 아닌 /path1.html로 요청하면 문제없이 응답을 한다.
/path1으로 들어온 요청을 실제 파일인 /path1.html로 리다이렉트 시켜주면된다 다만 모든 페이지마다 하나하나 리다이렉트를 작성할순 없으니 cloudfront functions
를 사용하여 요청이 들어왔을때 실제 html 파일로 리다이렉트 시키면 해결된다.
cloudfront의 메뉴에서 함수를 클릭한다.
함수 생성을 클릭하고 적당한 이름을 쓴다음 생성한다.
cloudfront에 요청이 들어왔을때 실행될 함수를 작성한다.
function handler(event) {
const request=event.request;
const uri=request.uri;
//루트 도메인 요청일 경우 index.html로 리다이렉트
if (uri === '' || uri=== '/') {
request.uri = '/index.html';
return request;
}
//정적파일이 아닐경우(.확장자 가 없는 /path 같은 경우)
else if (!uri.includes('.')) {
//맨뒤의 공백 또는 / 이스케이프 처리
const newUri = uri.replace(/[\/\s]+$/g, '');
request.uri=newUri+'.html';
}
return request;
}
이 코드는 정적파일을 요청하는 경로를 제외한 모든 경로의 뒤에다가 .html
을 붙인다. 이렇게 처리하면 /path 요청이 와도 cloudfront에서는 /path.html 파일을 찾아 응답한다.
변경 사항 저장
을 클릭하고 게시
탭으로 가서 작성한 함수를 게시해야 cloudfront의 동작에서 연결시킬수있다.
게시하기 전에 테스트
탭에서 작성한 함수를 실행시킬수있는데 스테이지
는 development와 live 가있다
development는 방금 빌드 탭에서 수정한 함수를 실행시키고 live는 게시가 완료된 함수를 실행시킨다.
테스트 실행결과 화면이다 /test
를 요청했는데 cloudfront에서는 /test.html
로 인식한다.
적용시킬 cloudfront의 배포의 동작으로 가서 기본값을 수정한다.
함수 연결에서 뷰어 요청에 cloudfront functions로 아까 생성한 함수를 연결한다.
추가적으로 없는 페이지에 대하여 404 페이지를 응답하고싶을땐 오류 페이지
탭에서 404나 403(cloudfront는 파일이 없을때 403을 응답함)에다가 /404.html
을 응답하도록 설정해두자.