본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

Origin Cache Control

원문 보기 위키 갱신

Origin Cache Control은 Cloudflare 기능이에요. Enterprise 고객의 웹사이트에서 활성화하면 Cloudflare가 오리진 서버에서 받은 Cache-Control 지시어를 엄격히 존중해야 함을 나타내요. Free, Pro, Business 고객은 이 기능이 기본으로 활성화되어 있어요.

출처: 문서

본문

오리진 서버의 HTTP 응답에 있는 Cache-Control 지시어는 Cloudflare 같은 중간 서비스에 구체적인 캐싱 지침 ↗︎을 제공해요.

Origin Cache Control 기능이 활성화되면 오리진 서버 응답에 있는 Cache-Control 지시어가 지정된 대로 따르게 돼요. 예를 들어 응답에 3,600초의 max-age 지시어가 있으면 Cloudflare는 그 기간 동안 리소스를 캐시한 후 새 업데이트가 있는지 오리진 서버를 다시 확인해요.

Cloudflare의 Cache Rules을 사용하면 오리진 서버의 Cache-Control 헤더나 Cloudflare가 설정한 기본 정책을 보강하거나 덮어쓸 수 있어요.

다음 섹션에서 다룰 내용:

  • 가장 일반적인 Cache-Control 지시어.
  • Origin Cache Control을 활성화하는 방법.
  • Origin Cache Control이 Cache-Control 지시어와 함께 동작하는 방식.
  • 다른 Cloudflare 제품이 Cache-Control 지시어와 상호작용하는 방식.

Cache-control 지시어

Cache-Control 헤더는 여러 지시어를 포함할 수 있고, 지시어는 누가 리소스를 캐시할 수 있는지, 그리고 리소스가 업데이트되기 전에 얼마나 오래 캐시될 수 있는지 결정해요.

참고 — 오리진 서버의 Cache-Control 지시어에 대한 자세한 내용은 Mozilla Cache-Control 문서 ↗︎를 참고해요.

여러 지시어가 함께 전달되면 각 지시어는 쉼표로 구분돼요. 지시어가 인자를 받으면 등호로 구분해 지시어 뒤에 나와요. 예: max-age=86400.

지시어는 네 그룹으로 나눌 수 있어요: cacheability, expiration, revalidation, other.

Cacheability (캐시 가능성)

Cacheability는 리소스가 캐시에 들어가야 하는지 여부를 말하며, 아래 지시어는 리소스의 캐시 가능성을 나타내요.

  • public — 응답이 일반적으로 캐시 불가능하거나 개인 캐시에서만 캐시 가능하더라도, 어떤 캐시든 응답을 저장할 수 있음을 나타내요.
  • private — 응답 메시지가 브라우저 캐시 같은 단일 사용자를 위한 것이며, Cloudflare나 기업 프록시 같은 공유 캐시에 저장되어서는 안 됨을 나타내요.
  • no-store — 클라이언트나 프록시 캐시 같은 어떤 캐시든 즉각적인 요청이나 응답의 어떤 부분도 저장해서는 안 됨을 나타내요.

Expiration (만료)

Expiration은 리소스가 캐시에 얼마나 오래 남아 있어야 하는지를 말하며, 아래 지시어는 리소스가 캐시에 머무는 시간에 영향을 줘요.

참고 — Cloudflare는 Cloudflare의 Browser Cache TTL과 max-age 헤더 중 더 높은 값을 존중해요. s-maxage와 max-age Cache-Control 헤더를 통해 각각 브라우저 캐시 TTL과 다른 Cloudflare Edge Cache TTL을 동시에 지정할 수도 있어요.

Origin Cache Control을 사용하고 max-age=0을 설정하면 Cloudflare는 캐시하고 재검증하는 것을 선호해요. Origin Cache Control이 꺼져 있고 max-age=0이면 Cloudflare는 캐시를 우회해요.

no-cache를 Origin Cache Control이 꺼진 상태로 설정하면 Cloudflare는 캐시하지 않아요. no-cache를 Origin Cache Control이 켜진 상태로 설정하면 Cloudflare는 캐시하고 항상 재검증해요.

  • max-age=seconds — 나이가 지정된 초 수보다 크면 응답이 stale이 됨을 나타내요. 나이는 자산이 오리진 서버에서 제공된 이후의 시간(초)으로 정의돼요. seconds 인자는 따옴표가 없는 정수예요.
  • s-maxage=seconds — 공유 캐시에서 이 지시어가 지정한 최대 나이가 max-age 지시어나 Expires 헤더 필드가 지정한 최대 나이를 덮어씀을 나타내요. s-maxage 지시어는 proxy-revalidate 응답 지시어의 의미도 내포해요. 브라우저는 s-maxage를 무시해요.

s-maxage는 stale-while-revalidate를 비활성화해요 — RFC 9111 ↗︎에 따라 s-maxage는 proxy-revalidate의 의미를 포함하므로, 공유 캐시는 오리진과 먼저 재검증하지 않고는 stale 콘텐츠를 제공해서는 안 돼요. stale-while-revalidate를 비활성화하는 지시어와 해결 방법의 전체 목록은 Controlling stale behavior를 참고해요.

  • no-cache — 오리진 서버에서 성공적인 검증 없이는 응답이 이후 요청을 충족하는 데 사용될 수 없음을 나타내요. 이는 오리진 서버가, stale 응답을 보내도록 구성된 캐시라도, 접촉하지 않고 캐시가 오리진을 사용해 요청을 충족하는 것을 막을 수 있게 해요.

RFC 2616 ↗︎에 명시된 대로 HTTP Expires 헤더가 GMT(그리니치 표준시)를 사용하도록 오리진 서버에 설정해야 해요.

Revalidation (재검증)

Revalidation은 리소스가 만료될 때 캐시가 어떻게 동작해야 하는지를 결정하며, 아래 지시어는 재검증 동작에 영향을 줘요.

  • must-revalidate — 리소스가 stale가 되면 캐시(클라이언트 또는 프록시)가 오리진 서버에서 성공적인 검증 없이 응답을 사용해 이후 요청을 충족해서는 안 됨을 나타내요.
  • proxy-revalidate — 개인 클라이언트 캐시에는 적용되지 않는다는 점을 제외하고 must-revalidate 응답 지시어와 같은 의미예요.
  • stale-while-revalidate=<seconds> — HTTP 응답에 있을 때, 리소스가 stale가 된 후 표시된 초 수(리소스 만료 이후 경과)까지 캐시가 그 응답을 제공할 수 있음을 나타내요. Always Online이 활성화되면 stale-while-revalidate와 stale-if-error 지시어는 무시돼요. 이 지시어는 Cache API 메서드 cache.match 또는 cache.put을 사용할 때는 지원되지 않아요. 자세한 내용은 Workers의 Cache API 문서를 참고해요.

참고 — stale-while-revalidate는 이제 완전히 비동기예요. 만료 후 첫 번째 요청이 백그라운드에서 재검증을 트리거하고, 차단하는 대신 UPDATING 상태의 stale 콘텐츠를 즉시 받아요. 재검증 중의 모든 요청은 오리진이 응답할 때까지 UPDATING 상태로 stale 제공되며, 이후에는 HIT를 받아요.

자세한 내용은 Revalidation을 참고해요.

  • stale-if-error=<seconds> — 오류가 발생했을 때, 다른 신선도 정보와 무관하게 캐시된 stale 응답이 요청을 충족하는 데 사용될 수 있음을 나타내요. 이 동작을 피하려면 오리진에서 반환된 객체에 stale-if-error=0 지시어를 포함해요. 이 지시어는 Cache API 메서드 cache.match 또는 cache.put을 사용할 때는 지원되지 않아요. 자세한 내용은 Workers의 Cache API 문서를 참고해요.

오류 상태 코드 — stale-if-error 지시어는 오리진이 5xx 상태 코드(500, 502, 503, 504)를 반환할 때 트리거돼요. 404 같은 다른 응답은 이 목적에서 오류로 간주되지 않아요. 오리진 응답이 stale 캐시 콘텐츠를 교체해요. 현재 stale-if-error를 트리거하는 상태 코드를 커스터마이즈할 방법은 없어요.

stale-if-error 지시어는 Always Online이 활성화되거나 명시적인 프로토콜 내 지시어가 전달되면 무시돼요. 명시적 프로토콜 내 지시어의 예로는 no-store 또는 no-cache 캐시 지시어, must-revalidate 캐시-응답 지시어, 또는 적용 가능한 s-maxage나 proxy-revalidate 캐시-응답 지시어가 있어요.

Other (기타)

캐시 동작에 영향을 주는 추가 지시어는 아래와 같아요.

  • no-transform — 캐시를 구현하든 말든 중간자가 페이로드를 변형해서는 안 됨을 나타내요.
  • vary — 기본적으로 Cloudflare는 캐싱 결정에서 vary 값을 고려하지 않아요. vary 값은 Cache Rules Vary 설정을 구성하거나, Vary for images를 구성할 때, 그리고 vary 헤더가 vary: accept-encoding일 때 존중돼요.
  • immutable — 응답 본문이 시간이 지나도 변하지 않음을 클라이언트에 나타내요. 만료되지 않은 리소스는 서버에서 변경되지 않은 상태예요. 사용자는 페이지를 명시적으로 새로 고쳐도 업데이트를 확인하기 위해 If-None-Match나 If-Modified-Since 같은 조건부 재검증 요청을 보내서는 안 돼요. 이 지시어는 Cloudflare 같은 공개 캐시에는 효과가 없지만 브라우저 동작은 바꿔요.

no-store와 no-cache 지시어 이해하기

Cache-Control: no-store와 Cache-Control: no-cache 지시어 사이에는 특히 브라우저 캐싱과 Back-Forward Cache ↗︎(BFCache) 같은 기능에 미치는 영향에 관해 혼동이 자주 있어요.

no-store

  • 브라우저와 중간자(CDN 같은) 모두 어떤 상황에서도 응답의 복사본을 저장하지 말라고 지시해요.
  • 응답은 디스크나 메모리에 절대 기록되지 않으므로, 브라우저가 매번 다시 가져와야 해요.
  • 많은 브라우저에서 no-store는 BFCache를 비활성화해요. BFCache에서 페이지를 복원하려면 브라우저가 페이지의 메모리 상태 복사본을 유지해야 하는데, 이는 "저장하지 말라"는 지시어와 모순되기 때문이에요.
  • 이 지시어는 매우 민감하거나 동적인 데이터(예: 은행 앱, 개인 정보, 보안 대시보드)에 사용돼요.

no-cache

  • 응답 저장(브라우저와 중간 캐시 모두)은 허용하지만, 사용하기 전에 오리진 서버와의 재검증을 요구해요.
  • 이렇게 하면 콘텐츠가 항상 최신 상태로 유지되면서, BFCache나 다른 형태의 성능 최적화는 여전히 허용될 수 있어요.
  • 이 지시어는 자주 변하지만 민감하지 않고, 다시 다운로드하는 대신 검증하면 더 빨리 제공될 수 있는 데이터에 사용돼요.

Origin Cache Control이 활성화되거나 비활성화될 때 이 지시어들이 어떻게 동작하는지는 Directives 섹션을 참고해요.

Origin Cache Control 활성화

Origin Cache Control을 활성화하면 Cloudflare는 RFC 7234 ↗︎를 엄격히 준수하려고 할 거예요. Enterprise 고객은 대시보드의 캐시 규칙 또는 API를 통해 웹사이트에 대해 Origin Cache Control을 활성화하거나 비활성화할지 선택할 수 있어요. Free, Pro, Business 고객은 이 옵션이 기본으로 활성화되어 있으며 비활성화할 수 없어요.

Origin Cache Control 동작

다음 섹션은 Origin Cache Control 활성화 또는 비활성화와 관련된 지시어와 동작 조건을 다뤄요.

정수 값 필요 — max-age, s-maxage, stale-while-revalidate 지시어는 RFC 9111에 따라 정수 값을 요구해요. 부동 소수점 값(예: max-age=2.5)은 유효하지 않으며 무시되어 캐시 우회를 초래할 수 있어요. 오리진이 정수 TTL 값을 반환하는지 확인하세요.

지시어

아래 표는 Origin Cache Control이 비활성화되거나 활성화될 때의 지시어와 동작을 나열해요.

지시어 Origin Cache Control 비활성화 동작 Origin Cache Control 활성화 동작
s-maxage=0 캐시하지 않음. 캐시하고 항상 재검증.
max-age=0 캐시하지 않음. 캐시하고 항상 재검증.
no-cache 캐시하지 않음. 캐시하고 항상 재검증. stale 제공 안 함.
no-cache=<headers> 캐시하지 않음. no-cache=<headers>에 언급된 헤더가 존재하지 않으면 캐시함. no-cache=<headers>에 언급된 헤더가 있으면 항상 재검증.
Private=<headers> 캐시하지 않음. Private=<headers> 지시어에 언급된 <headers> 값은 캐시하지 않음.
must-revalidate 캐시 지시어 무시되고 stale 제공됨. stale 제공 안 함. CDN과 브라우저 모두 재검증해야 함.
proxy-revalidate 캐시 지시어 무시되고 stale 제공됨. stale 제공 안 함. CDN은 재검증해야 하지만 브라우저는 아님.
no-transform (un)Gzip, Polish, 이메일 필터 등을 할 수 있음. 본문을 변형하지 않음.
s-maxage=delta, delta>1 max-age와 같음. Max-age와 proxy-revalidate.
immutable 하위로 프록시되지 않음. 하위로 프록시됨. 브라우저 대상, 캐시 프록시에는 영향 없음.
no-store 캐시하지 않음. 캐시하지 않음.

조건

특정 시나리오도 활성화되거나 비활성화될 때 Origin Cache Control 동작에 영향을 줘요.

조건 Origin Cache Control 비활성화 동작 Origin Cache Control 활성화 동작
Authorization 헤더 존재. 콘텐츠가 캐시될 수 있음. must-revalidate, public, 또는 s-maxage도 함께 있을 때만 콘텐츠가 캐시됨.
no-cache 헤더 사용. 로그에서 cacheStatus=miss. 로그에서 cacheStatus=bypass.
오리진 응답에 Set-Cookie 헤더가 있고 기본 캐시 레벨 사용. set-cookie 헤더가 제거된 채 콘텐츠가 캐시될 수 있음. 콘텐츠가 캐시되지 않음.
Browser Cache TTL이 설정됨. 사용자에게 반환되는 Cache-Control에 private이 포함되지 않음. 오리진이 Cache-Control에서 private을 반환하면 보존함.

참고 — Cloudflare-Cdn-Cache-Control 헤더가 설정되면 OCC는 (활성화 여부와 무관하게) 켜져요. 결과적으로 우리는 RFC 7234, Section 3.2 ↗︎에 따라 Authorization 헤더 로직을 적용해 s-maxage, must-revalidate, public 지시어만 허용해요. 다른 지시어가 있으면 자산을 캐시하지 않고 대신 BYPASS를 반환해요.

예시

특정 캐싱 동작을 제어하기 위해 Cache-Control 헤더에 어떤 지시어를 사용해야 하는지 아래 예시를 검토해요.

정적 자산 캐시하기.

Cache-Control: public, max-age=86400

비밀 자산이 절대 캐시되지 않도록 보장하기.

Cache-Control: no-store

프록시 캐시가 아닌 브라우저에서 자산 캐시하기.

Cache-Control: private, max-age=3600

클라이언트와 프록시 캐시에서 자산을 캐시하되, 제공 시 재검증을 선호하기.

Cache-Control: public, no-cache

프록시 캐시에서 자산을 캐시하되, 제공 시 프록시가 재검증하도록 요구하기.

Cache-Control: public, no-cache, proxy-revalidate 또는 Cache-Control: public, s-maxage=0

프록시 캐시에서 자산을 캐시하되, 제공 시 어떤 캐시든 재검증하도록 요구하기.

Cache-Control: public, no-cache, must-revalidate

자산을 캐시하되 프록시가 수정하지 않도록 보장하기.

Cache-Control: public, no-transform

이 구성은 원래 페이로드가 압축되지 않은 상태로 제공된 경우 에지에서 방문자에게 가는 gzip이나 brotli 압축 같은 변형도 비활성화해요.

재검증과 함께 자산을 캐시하되, 오리진 서버에 도달할 수 없으면 stale 응답 허용하기.

Cache-Control: public, max-age=3600, stale-if-error=60

이 구성으로 Cloudflare는 콘텐츠가 3600초(1시간) 동안 캐시된 후 오리진 서버와 재검증을 시도해요. 서버가 적절한 재검증 응답 대신 오류를 반환하면 Cloudflare는 리소스 만료 후 총 1분 동안 stale 리소스를 계속 제공해요.

Cloudflare와 방문자 브라우저에서 자산을 다른 기간 동안 캐시하기.

Cache-Control: public, max-age=7200, s-maxage=3600

자산을 캐시하고 재검증되는 동안 제공하기.

Cache-Control: max-age=600, stale-while-revalidate=30

이 구성은 자산이 600초 동안 신선함을 나타내요. Cloudflare가 백그라운드에서 오리진과 자산을 재검증하는 동안 자산은 최대 추가 30초까지 stale로 제공될 수 있어요. 자세한 내용은 Revalidation을 참고해요.

참고 — s-maxage를 stale-while-revalidate와 함께 사용하지 마세요. s-maxage 지시어는 proxy-revalidate를 의미하며, 이는 공유 캐시가 stale 콘텐츠를 제공하지 못하게 해요. 해결 방법은 Controlling stale behavior를 참고해요.

다른 Cloudflare 기능과의 상호작용

이 섹션은 다른 Cloudflare 기능이 Cache-Control 지시어와 어떻게 상호작용하는지 다뤄요.

Edge Cache TTL

Edge Cache TTL Cache Rules는 s-maxage를 덮어쓰고, 재검증 지시어가 있으면 비활성화해요. Cloudflare에서 Origin Cache Control이 활성화되면, Edge Cache TTL 덮어쓰기가 있어도 원래 Cache-Control 헤더가 우리 에지에서 하위로 전달돼요. 반대로 Cloudflare에서 Origin Cache Control이 비활성화되면 Cloudflare가 Origin Cache Control을 덮어써요.

Browser Cache TTL

Browser Cache TTL Cache Rules는 일반적으로 방문자 브라우저로 가는 에지에서 하위로 전달되는 max-age 설정을 덮어써요.

Polish

no-transform 지시어가 있으면 Polish가 비활성화돼요.

Gzip 및 기타 압축

no-transform 지시어가 있으면 압축이 비활성화돼요. 오리진에서 가져온 원래 자산이 압축되어 있으면 압축된 채로 방문자에게 제공돼요. 원래 자산이 압축되지 않았다면 압축이 적용되지 않아요.

JavaScript Detections

no-transform 지시어가 있으면 JavaScript Detections 주입이 비활성화돼요. 영향받는 요청에 대해 cf.bot_management.js_detection.passed 필드가 missing으로 표시돼요.

더 알아보기 (Learn more)

Origin Cache Control은 오리진의 Cache-Control 지시어를 엄격히 존중하게 해 주는 기능이에요. public·private·no-store·no-cache·max-age·s-maxage·stale-while-revalidate·stale-if-error 등 다양한 지시어의 동작을 정리한 문서예요. Free, Pro, Business는 기본 활성화, Enterprise는 선택 가능해요.