도입: Next.js next/image에서 R2 원격 이미지 오류를 푸는 한 줄 답
R2 이미지가 브라우저 주소창에서는 열리는데 Next.js Image 컴포넌트에서 실패한다면 먼저 remotePatterns와 실제 URL을 문자 단위로 비교해야 한다. Next.js는 protocol, hostname, port, pathname, search 조건을 엄격하게 검사한다. 그다음 공개 URL의 상태 코드와 Content-Type, 애플리케이션의 이미지 렌더링 방식을 순서대로 확인하면 원인을 빠르게 좁힐 수 있다.
Next.js next/image에서 Cloudflare R2 원격 이미지 오류 해결 핵심 항목
1. 실제 이미지 URL 분해하기
- 준비: 실패한
src전체 주소와 브라우저 Network 오류를 복사한다. - 단계: URL을 protocol, hostname, pathname, search로 나눠 적는다.
- 주의점: 커스텀 도메인과 r2.dev 주소는 서로 다른 hostname이다. 대소문자와 경로도 실제 값 기준으로 본다.
- 완료 기준:
src가 어떤 remote pattern과 일치해야 하는지 한 줄로 설명할 수 있다.
2. remotePatterns를 좁고 정확하게 설정하기
- 준비: R2 공개 도메인과 게시 이미지 prefix를 확인한다.
- 단계:
next.config에 정확한 protocol·hostname·pathname을 등록한다. - 주의점: 필요한 경로가
/blog/**인데/**전체를 허용하면 범위가 지나치게 넓다.search: ''는 쿼리 문자열이 없는 URL만 허용한다. - 완료 기준: 허용한 R2 경로는 표시되고 다른 호스트나 경로는 차단된다.
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'assets.example.com',
port: '',
pathname: '/blog/**',
search: '',
},
],
},
}
export default nextConfig
3. 설정 변경 후 서버 다시 시작하기
- 준비: 현재 실행 중인 개발 서버와 배포 빌드를 확인한다.
- 단계:
next.config변경 후 개발 서버를 재시작하고 운영 환경은 새 빌드로 배포한다. - 주의점: 브라우저 새로고침만으로 서버 설정이 반영됐다고 판단하지 않는다.
- 완료 기준: 새 빌드 로그에 오류가 없고 같은 URL이 Image 컴포넌트에서 로드된다.
4. R2 응답 자체 검증하기
- 준비: 공개 URL과 원본 객체 키를 준비한다.
- 단계: HEAD 또는 GET 요청으로 200 상태와
image/jpeg,image/png,image/webp같은 Content-Type을 확인한다. - 주의점: 200이어도 HTML 오류 페이지를 반환하면 이미지 최적화가 실패할 수 있다.
- 완료 기준: 공개 URL이 인증 없이 실제 이미지 바이트를 반환한다.
curl -I https://assets.example.com/blog/post-id/cover.jpg
5. 경로와 쿼리 문자열 불일치 확인하기
- 준비:
remotePatterns와 실패 URL을 나란히 둔다. - 단계:
http/https, 서브도메인, 포트,/blog/**경로,?v=같은 검색 문자열을 차례로 비교한다. - 주의점: URL 생성자에서 검색 조건을 비워두면 쿼리 문자열을 허용하지 않는 설정이 될 수 있다.
- 완료 기준: 필요한 쿼리 정책을 의도적으로 허용하거나 제거했다.
6. MDX 렌더러가 사용하는 컴포넌트 확인하기
- 준비: MDX의 Markdown 이미지와 JSX
Image가 어떤 컴포넌트로 매핑되는지 확인한다. - 단계:
mdx-components또는 커스텀 렌더러에서src,alt, 크기 값을 어떻게 전달하는지 본다. - 주의점: 원격 이미지의 크기를 알 수 없다면 width·height 또는
fill과 부모 레이아웃이 필요하다. - 완료 기준: MDX 이미지와 직접 작성한 Image가 같은 정책으로 렌더링되고 레이아웃 이동이 없다.
전체 실행 순서
실패 URL을 복사한 뒤 브라우저에서 이미지 자체가 열리는지 확인한다. 응답 상태와 Content-Type이 정상이면 remotePatterns의 다섯 조건을 비교한다. 설정을 수정한 후 서버를 재시작하고, 단순 페이지에서 Image 하나를 먼저 테스트한다. 마지막으로 MDX 렌더러와 운영 배포에서 같은 주소를 확인한다.
주의점과 실패하기 쉬운 지점
domains와 remotePatterns 예제를 섞어 사용하거나, 개발용 r2.dev와 운영 커스텀 도메인을 동시에 쓰면 원인 추적이 어렵다. 모든 외부 주소를 **로 허용하는 것은 빠른 우회처럼 보이지만 불필요한 호스트까지 이미지 최적화 대상으로 만들 수 있다. URL이 404였던 시점의 CDN 캐시가 남은 경우도 애플리케이션 설정 오류와 구분해야 한다.
완료 확인 체크리스트
- [ ] 실제 src의 protocol과 hostname이 remotePatterns와 같다.
- [ ] pathname 패턴이 게시 이미지 경로를 포함한다.
- [ ] search 조건이 실제 쿼리 문자열 정책과 일치한다.
- [ ] 공개 URL이 200과 image Content-Type을 반환한다.
- [ ] 설정 변경 후 개발 서버와 운영 빌드를 다시 시작했다.
- [ ] MDX 이미지 컴포넌트의 크기와 alt가 전달된다.
- [ ] 허용하지 않은 외부 호스트는 계속 차단된다.
참고 자료
- Next.js Image Component 문서
- Next.js
next/imageUn-configured Host 오류 문서 - Cloudflare R2 Public buckets 문서
