댓글 (0)
댓글 (0)
Object Storage인 Cloudflare R2에 이미지를 올리고, Docker(Nginx + Next.js)로 배포한 앱에서 next/image로 이미지를 불러오려 하니 아래와 같은 에러가 발생했다.
// next.config.ts
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{ protocol: "https", hostname: "images.kotys.dev" },
],
},
...,
};
next.config.ts 설정 자체는 문제없었다.
next.config.ts 변경사항은 빌드 타임에 번들링되기 때문에 컨테이너 재시작만으로는 반영이 안 된다.
docker compose build --no-cache
docker compose up -d
--no-cache 옵션으로 재빌드했지만 여전히 같은 에러가 발생했다.
컨테이너 안에서 실제 빌드된 config를 확인해봤다.
docker exec -it <nextjs-container> sh
cat .next/required-server-files.json | grep -A 20 "remotePatterns"
"remotePatterns": [
{ "protocol": "https", "hostname": "images.kotys.dev" },
...,
]
빌드에는 제대로 반영돼 있었다.
Next.js는 이미지 최적화 시 서버 사이드에서 직접 이미지를 fetch한다. 컨테이너 안에서 네트워크 접근이 되는지 확인했다.
wget -O- https://images.kotys.dev/test.png
네트워크에도 문제가 없었다.
혹시 Cloudflare가 이전의 잘못된 응답을 캐싱하고 있을 수도 있어서 Cache Purge를 수행했지만, 동일한 에러가 계속 발생했다.
Dockerfile의 멀티스테이지 빌드에서 runner 스테이지에 next.config.ts를 복사하지 않은 것이 원인이었다.
# Runner stage
...,
COPY /usr/src/app/.next ./.next
COPY /usr/src/app/public ./public
COPY /usr/src/app/next.config.ts ./next.config.ts # 추가
...,
next.config.ts가 없으면 Next.js 서버가 기본값으로 동작해서 remotePatterns가 빈 상태로 실행된다. Next.js 공식문서에 아래와 같은 설명이 있다.
next.config.js is a regular Node.js module, not a JSON file. It gets used by the Next.js server and build phases, and it's not included in the browser build.
.next/required-server-files.json에는 config가 반영되어 있었다 하더라도, 서버 환경에서 next.config.ts가 없으면 소용이 없다.
수정 후 재빌드하니 문제가 해결되었다.
Docker의 멀티스테이지 빌드를 쓸 때 runner 스테이지에 필요한 파일을 빠뜨리기 쉽다. 공식 문서를 잘 참고하여 런타임에 필요한 설정 파일들을 누락하지 않도록 조심해야겠다.
비슷한 증상으로 헤매는 사람에게 도움이 되었으면 좋겠다.