도입: R2 커스텀 도메인과 캐시를 함께 점검해야 하는 이유
R2 객체가 브라우저에서 열린다고 해서 운영 구성이 끝난 것은 아니다. r2.dev 주소는 개발 확인에는 편하지만 Cloudflare Cache, WAF, 봇 관리 기능을 사용하는 운영 주소로는 적합하지 않다. 공개 버킷에 커스텀 도메인을 연결하고 캐시 규칙과 객체 헤더를 함께 확인해야 일관된 이미지 전달 경로를 만들 수 있다.
Cloudflare R2 커스텀 도메인 연결과 캐시 설정 핵심 항목
1. 공개 경로를 커스텀 도메인으로 통일
- 확인 대상: 운영 페이지의 이미지 URL이 소유한 도메인으로 연결되는지 확인한다.
- 확인 방법: R2 버킷의 Settings에서 Custom Domains 연결 상태를 확인하고 실제 HTML의 이미지 주소를 검사한다.
- 실패 신호: 운영 글에
pub-....r2.dev주소가 남아 있거나 새 도메인이 인증 대기 상태다. - 조치: Cloudflare에서 관리 중인 도메인을 버킷에 연결하고 애플리케이션의
R2_PUBLIC_URL을 새 주소로 교체한다.
2. 개발용 r2.dev 공개 주소 정리
- 확인 대상: 커스텀 도메인 연결 뒤에도 r2.dev 공개 주소가 계속 노출되는지 확인한다.
- 확인 방법: 버킷의 Public access 설정과 배포 환경 변수를 함께 점검한다.
- 실패 신호: 같은 객체가 두 공개 주소로 제공되거나 운영 코드가 계속 r2.dev를 생성한다.
- 조치: 커스텀 도메인 전환을 확인한 뒤 필요하면 r2.dev 공개 접근을 끄고 하나의 정식 URL만 사용한다.
3. Cache-Control과 파일명 전략
- 확인 대상: 이미지 응답의
Cache-Control값과 객체 키가 변경 불가능한 형태인지 확인한다. - 확인 방법: 브라우저 개발자 도구나
curl -I로 응답 헤더를 확인하고 파일명에 콘텐츠 해시가 포함되는지 본다. - 실패 신호: 같은 URL의 파일을 덮어쓰면서 긴 캐시 시간을 적용해 이전 이미지가 계속 보인다.
- 조치:
파일 해시가 바뀌면 URL도 바뀌는immutable 키를 사용하고 긴 캐시는 그 경로에만 적용한다.
4. Cache Rule 적용 범위
- 확인 대상: 캐시 규칙이 이미지 경로에만 적용되는지, 필요한 파일 형식이 캐시 대상인지 확인한다.
- 확인 방법: Cache Rules의 호스트와 경로 조건을 읽고 응답의
CF-Cache-Status를 여러 번 요청해 비교한다. - 실패 신호: 이미지가 계속
DYNAMIC으로 나오거나 HTML·JSON까지 의도치 않게 장기 캐시된다. - 조치:
assets.example.com/blog/*처럼 호스트와 경로를 좁히고, 이미지 응답에 맞는 Edge TTL 정책을 설정한다.
5. 업로드 직후 404 캐시
- 확인 대상: 객체를 올리기 전에 같은 URL을 요청한 적이 있는지와 404가 캐시됐는지 확인한다.
- 확인 방법: S3 API로 객체 존재를 확인한 뒤 커스텀 도메인 응답과 Cache Status를 비교한다.
- 실패 신호: R2에는 객체가 있지만 브라우저에서는 계속 404가 반환된다.
- 조치: 해당 URL의 캐시를 제거하거나 콘텐츠 해시가 포함된 새 키를 사용한다. 업로드 완료 후 공개 URL을 검증한 다음 글을 게시한다.
6. 덮어쓰기와 삭제 후 캐시
- 확인 대상: 같은 키를 덮어쓰거나 삭제한 뒤 엣지 캐시에 이전 응답이 남는지 확인한다.
- 확인 방법: R2 직접 조회 결과와 커스텀 도메인 응답의 ETag·크기·내용을 비교한다.
- 실패 신호: 저장소의 최신 객체와 방문자에게 보이는 파일이 다르다.
- 조치: 운영 이미지에는 새 해시 키를 발급한다. 긴급 삭제나 수정은 관련 URL을 purge한다.
7. 접근 제어 경계
- 확인 대상: 공개 이미지와 생성 중인 임시 파일이 같은 공개 경로에 섞이지 않는지 확인한다.
- 확인 방법:
generated,review,publishedprefix 또는 별도 버킷의 공개 범위를 점검한다. - 실패 신호: 검수 전 이미지 URL을 외부에서 바로 열 수 있거나 비공개 파일이 검색 엔진에 노출된다.
- 조치: 생성 원본은 private 버킷에 두고 승인된 객체만 published 경로로 복사한다. 민감한 저장소는 Access나 WAF 같은 별도 접근 제어를 적용한다.
점검 순서
먼저 Custom Domain 연결과 DNS 활성 상태를 확인한다. 다음으로 애플리케이션이 새 도메인을 생성하는지 확인하고, 테스트 객체를 해시 기반 키로 업로드한다. curl -I로 상태 코드·콘텐츠 형식·Cache-Control·CF-Cache-Status를 확인한다. 마지막으로 같은 URL을 두 번 요청해 캐시 상태를 비교하고, 삭제·교체 정책과 purge 절차를 문서화한다.
자주 놓치는 포인트
브라우저에서 이미지가 열린다는 사실은 캐시가 동작한다는 뜻이 아니다. r2.dev는 운영 캐시 기능을 제공하는 커스텀 도메인과 역할이 다르다. 또한 긴 TTL을 적용하면서 동일 객체 키를 덮어쓰면 이전 이미지가 남는다. 업로드와 DB 저장 사이에 실패가 발생할 수 있으므로, 공개 URL 검증과 고아 객체 정리 기록도 필요하다.
재사용 체크리스트
- [ ] 운영 이미지 URL이 커스텀 도메인을 사용한다.
- [ ] r2.dev 주소가 본문과 환경 변수에 남아 있지 않다.
- [ ] 객체 키에 콘텐츠 해시가 포함된다.
- [ ] Cache Rule의 호스트와 경로 범위가 제한되어 있다.
- [ ] 응답이 올바른
Content-Type과Cache-Control을 가진다. - [ ] 두 번째 요청에서 캐시 상태를 확인했다.
- [ ] 404·덮어쓰기·삭제 시 purge 절차가 있다.
- [ ] 생성·검수 객체와 공개 객체의 접근 범위가 분리되어 있다.
참고 자료
- Cloudflare Docs, Public buckets
- Cloudflare Docs, Enable cache in an R2 bucket
- Cloudflare Docs, R2 consistency model
