Cloudflare 캐시 적중률이 30%뿐인가요? 이 3가지 규칙으로 90%까지 높이기

제 블로그의 Cloudflare 캐시 적중률은 오랫동안 30% 안팎에 머물렀습니다. 이미지와 CSS 같은 정적 리소스는 캐시됐지만 HTML 페이지는 요청할 때마다 원본 서버로 전달되어 서버가 여전히 많은 요청을 처리해야 했습니다. Cloudflare는 기본적으로 HTML을 캐시하지 않으며, Page Rules 구성 방식도 이미 폐기되었습니다.
Cache Rules와 Edge TTL 구성을 살펴보고 적용한 뒤 캐시 적중률은 30%에서 90%로 뛰었고, TTFB는 500밀리초에서 100여 밀리초로 줄었으며, 서버 부하는 90% 감소했습니다. 이 글에서는 Cloudflare 캐시 구성 방법, HTML이 캐시되지 않는 이유, Cache Rules 설정 절차, 효과를 검증하는 방법을 설명합니다.
Cloudflare는 왜 기본적으로 HTML을 캐시하지 않을까요?
Cloudflare의 기본 캐시 동작
먼저 Cloudflare의 기본 캐시 전략부터 살펴보겠습니다. 기본적으로 Cloudflare는 이미지(JPG, PNG, GIF), 스타일 파일(CSS), 스크립트 파일(JS) 같은 정적 리소스만 캐시합니다. HTML 페이지는 기본적으로 캐시하지 않습니다.
왜 그럴까요? Cloudflare는 주로 다음 세 가지 조건으로 리소스를 캐시할 수 있는지 판단합니다.
- Cache-Control 헤더:
private,no-store,no-cache,max-age=0이 설정되어 있으면 캐시하지 않습니다. - 응답 코드: 200, 301, 404처럼 특정 HTTP 상태 코드만 캐시합니다.
- 요청 메서드: GET 요청만 캐시하며 POST, PUT 요청은 캐시하지 않습니다.
HTML 페이지는 일반적으로 사용자별 정보를 포함할 수 있는 ‘동적 콘텐츠’로 간주되므로 기본적으로 캐시되지 않습니다. 이 설계는 합리적입니다. 사이트에 로그인 기능이 있다면 HTML에 사용자 이름이나 개인 정보가 포함될 수 있는데, CDN이 이를 캐시해 다른 방문자에게 보여서는 안 되기 때문입니다.
HTML을 캐시하지 않는 실제 이유
간단히 말하면 Cloudflare는 보안을 위해 이렇게 동작합니다. 커뮤니티 포럼에서 사이트 전체 캐시를 바로 켰다가 wp-login.php 로그인 페이지는 물론 로그인 계정 정보까지 모두 캐시된 사례를 본 적이 있습니다. 그 결과 어떤 방문자든 캐시된 페이지를 통해 WordPress 관리자 화면에 바로 들어갈 수 있었습니다. 생각만 해도 아찔합니다.
반대로 사이트가 다음과 같이 정적 콘텐츠 중심이라면 HTML 캐시로 성능을 크게 높일 수 있습니다.
- Next.js, Gatsby 같은 도구로 만든 정적 블로그
- 업데이트 빈도가 매우 낮은 기업 홈페이지나 문서 사이트
- 정보 표시만을 목적으로 하는 제품 소개 페이지
핵심은 관리자 화면과 로그인 페이지처럼 제외해야 할 페이지를 정확히 제외하는 것입니다.
HTML 캐시로 어느 정도 개선할 수 있을까요?
Medium에서 HTML 캐시를 구성한 뒤 TTFB가 500밀리초에서 100~160밀리초로 줄고 서버 부하가 90% 감소했다는 데이터를 본 적이 있습니다. 효과가 매우 큽니다.
왜 이렇게 큰 차이가 날까요? 이전에는 방문자가 사이트를 열 때마다 HTML을 원본 서버에서 가져와야 했고, 서버는 요청을 처리하고 데이터베이스를 조회하며 페이지를 렌더링해야 했습니다. 이제는 CDN이 캐시된 HTML을 방문자에게 바로 전달하므로 원본 서버가 처리할 일이 없습니다. 트래픽이 많을수록 차이는 더 커집니다.
Page Rules가 폐기된 지금, Cache Rules로 어떻게 대체할까요?
Page Rules의 퇴장
Cloudflare를 사용해 봤다면 Page Rules를 알고 있을 것입니다. 이 기능에서는 ‘Cache Everything’ 옵션으로 HTML을 캐시할 수 있었습니다. 하지만 현재 Page Rules에는 deprecated 표시가 붙어 있습니다.
일정은 다음과 같습니다.
- 2024년 7월: 새로 가입한 무료 계정은 Page Rules를 사용할 수 없게 됐습니다.
- 2025년: Cloudflare가 기존 Page Rules를 새 시스템으로 자동 마이그레이션합니다.
- 이후의 새 구성은 모두 Cache Rules를 사용해야 합니다.
폐기 이유는 어렵지 않게 이해할 수 있습니다. Page Rules는 기능이 오래되었고 구성 유연성이 부족하며, 무료 플랜에서는 규칙을 3개만 만들 수 있습니다. 복잡한 캐시 전략에는 충분하지 않습니다.
Cache Rules의 새로운 방식
Cache Rules는 Cloudflare의 새로운 캐시 구성 시스템으로, 기능이 훨씬 강력합니다. 가장 큰 차이는 다음과 같습니다.
Page Rules 방식: 모든 콘텐츠를 캐시하려면 ‘Cache Everything’을 직접 선택해야 합니다.
Cache Rules 방식: ‘Eligible for cache’를 선택하면 Cache Everything 기능이 자동으로 활성화됩니다.
이 변화는 꽤 중요합니다. 처음에는 이를 모르고 ‘Cache Everything’ 옵션을 계속 찾다가 이름이 바뀌었다는 사실을 뒤늦게 알았습니다.
또한 Cache Rules의 일치 조건은 더 유연합니다.
- URI 경로, 파일 확장자, 호스트 이름 등 여러 조건으로 일치시킬 수 있습니다.
- 정규 표현식을 지원합니다. 저는 자주 사용하지는 않습니다.
- 여러 조건을 조합할 수 있습니다.
마이그레이션 주의 사항
아직 Page Rules를 사용 중이라면 다음 사항에 유의해야 합니다.
- Cloudflare가 마이그레이션을 지원합니다: Cloudflare는 2025년에 Page Rules를 Cache Rules로 자동 변환하므로 직접 작업할 필요가 없습니다. 물론 미리 직접 마이그레이션해도 됩니다.
- 일부 설정은 마이그레이션되지 않습니다: 특히 이미 폐기된 ‘Disable Security’와 ‘Disable Performance’는 마이그레이션되지 않습니다.
- 동작에 약간의 차이가 있습니다: Cache Rules의 ‘Eligible for cache’는 Page Rules의 ‘Cache Everything’에 해당하지만 구현 논리는 조금 다릅니다.
어차피 전환해야 하므로 지금부터 Cache Rules를 사용하는 것이 좋습니다. 빨리 바꾸면 마음도 편하고, 실제로 구성도 더 명확하고 편리합니다.
Cache Rules 실전 구성: 규칙 3개로 사이트 전체 캐시하기
이제 실전으로 넘어가겠습니다. 관리자 화면 제외부터 사이트 전체 캐시까지 완성하는 Cache Rules 3개를 구성해 보겠습니다.
준비: 구성 페이지 열기
Cloudflare 대시보드에 로그인하고 구성할 도메인을 선택한 뒤 다음 단계를 진행합니다.
- 왼쪽 메뉴에서 ‘Caching’을 클릭합니다.
- ‘Cache Rules’ 탭을 찾습니다.
- ‘Create rule’ 버튼을 클릭합니다.
이제 규칙을 하나씩 구성하겠습니다.
규칙 1: 관리자 및 관리 페이지 우회(가장 높은 우선순위)
왜 첫 번째여야 할까요? 보안이 가장 중요하기 때문입니다. 이 규칙은 관리자 화면과 로그인 페이지가 절대 캐시되지 않도록 합니다.
구성 단계:
- Rule name:
Bypass Admin Pages를 입력합니다. - When incoming requests match:
- ‘Custom filter expression’을 선택합니다.
- Field에서 ‘URI Path’를 선택합니다.
- Operator에서 ‘contains’를 선택합니다.
- Value에
/wp-admin을 입력합니다. 관리자 경로가 여러 개라면 다음 단계에서 추가합니다.
- 제외 경로 추가: ‘Or’ 버튼을 클릭하고 다음 경로를 추가합니다.
/wp-login.php(WordPress 로그인 페이지)/admin/(일반적인 관리자 경로)/api/auth/(API 인증 엔드포인트가 있는 경우)
- Then:
- Cache eligibility 드롭다운에서 ‘Bypass cache’를 선택합니다.
- 우선순위: 1로 설정합니다.
구성을 마치면 ‘Deploy’를 클릭합니다. 이 규칙은 해당 경로가 포함된 모든 요청이 캐시를 거치지 않고 원본 서버로 바로 전달되도록 합니다.
WordPress 사이트의 전체 제외 목록:
/wp-admin
/wp-login.php
/wp-json
/cart
/checkout
/my-account
자신의 사이트에 맞게 목록을 조정하세요.
규칙 2: 정적 리소스 캐시(중간 우선순위)
Cloudflare는 기본적으로 정적 리소스를 캐시하므로 이 규칙은 선택 사항입니다. 하지만 명시적으로 구성하면 TTL을 더 정확하게 제어할 수 있습니다.
구성 단계:
- Rule name:
Cache Static Assets - When incoming requests match:
- Field에서 ‘File extension’을 선택합니다.
- Operator에서 ‘is in’을 선택합니다.
- Value에
jpg png gif css js woff woff2 ttf svg ico를 공백으로 구분해 입력합니다.
- Then:
- Cache eligibility에서 ‘Eligible for cache’를 선택합니다.
- Edge cache TTL에서 ‘Use cache-control header if present, use default Cloudflare caching behavior if not’을 선택합니다.
- 우선순위: 2로 설정합니다.
이 규칙은 정적 리소스에 원본 서버의 Cache-Control 헤더를 우선 적용하고, 원본 서버에 설정이 없으면 Cloudflare의 기본 TTL을 사용합니다. 기본 TTL은 파일 유형에 따라 일반적으로 4시간에서 1개월 사이입니다.
규칙 3: 나머지 모든 콘텐츠 캐시(가장 낮은 우선순위)
이제 핵심 규칙입니다. HTML을 포함한 나머지 모든 콘텐츠를 캐시합니다.
구성 단계:
- Rule name:
Cache Everything Else - When incoming requests match:
- ‘All incoming requests’를 선택합니다.
- 더 정밀하게 구성하려면 ‘Custom filter expression’을 선택하고 특정 경로를 제외할 수 있습니다.
- Then:
- Cache eligibility에서 ‘Eligible for cache’를 선택합니다.
- Edge cache TTL에서 ‘Ignore cache-control header and use this TTL’을 선택합니다.
- 기간은 7 days(1주)를 선택합니다.
- 우선순위: 3으로 설정합니다.
왜 1주일까요? 균형 잡힌 기간이기 때문입니다. 1일처럼 너무 짧으면 캐시 효과가 크지 않고, 1개월처럼 너무 길면 콘텐츠가 제때 갱신되지 않습니다. 업데이트 빈도가 낮은 블로그나 문서 사이트에는 1주가 적절합니다.
무료 플랜 주의 사항: 무료 계정의 최소 TTL은 2시간이고 Pro 계정은 1시간입니다. 콘텐츠가 자주 업데이트된다면 더 짧게 설정할 수 있습니다.
규칙 실행 순서가 중요합니다
Cloudflare는 우선순위 숫자가 작은 규칙부터 실행합니다.
- 먼저 규칙 1(우선순위 1)을 실행해 관리자 페이지인지 확인하고, 맞으면 Bypass합니다.
- 다음으로 규칙 2(우선순위 2)를 실행해 정적 리소스인지 확인하고, 맞으면 적절한 TTL로 캐시합니다.
- 마지막으로 규칙 3(우선순위 3)을 실행해 나머지 모든 요청을 1주간 캐시합니다.
이 순서로 관리자 페이지는 확실하게 캐시하지 않고, 정적 리소스에는 적절한 TTL을 적용하며, HTML 페이지는 1주간 강제로 캐시할 수 있습니다.
전체 구성 체크리스트
규칙 3개를 구성한 뒤 다음 항목을 확인하세요.
- 규칙 1의 우선순위가 가장 높습니다(숫자가 가장 작음).
- 모든 관리자 경로가 제외 목록에 들어 있습니다.
- 업데이트 빈도에 맞게 규칙 3의 TTL을 조정했습니다.
- 모든 규칙을 Deploy했습니다.
구성이 끝났습니다. 이제 Edge TTL에서 주의할 점을 살펴보겠습니다.
Edge TTL 구성 상세: 흔한 함정 피하기
Edge TTL(엣지 캐시 만료 시간)은 전체 캐시 전략의 핵심인 동시에 가장 실수하기 쉬운 부분입니다. 저도 처음 구성할 때 여러 번 시행착오를 겪었습니다.
Edge TTL의 세 가지 모드
Cloudflare의 Edge TTL에는 세 가지 모드가 있으며 올바른 선택이 중요합니다.
모드 1: Use cache-control header if present, bypass cache if not
- 의미: Cache-Control이 있으면 따르고, 없으면 캐시하지 않습니다.
- 적합한 상황: 원본 서버에 완전한 Cache-Control 헤더가 구성되어 있습니다.
- 제 평가: 많은 소규모 사이트에는 원본 서버의 Cache-Control 설정이 없어 사실상 캐시되지 않으므로 지나치게 엄격합니다.
모드 2: Use cache-control header if present, use default Cloudflare caching behavior if not(권장)
- 의미: Cache-Control이 있으면 따르고, 없으면 Cloudflare 기본 규칙을 사용합니다.
- 적합한 상황: 원본 서버 일부에만 Cache-Control이 구성되어 있고 나머지는 Cloudflare가 처리하기를 원합니다.
- 제 평가: 대부분의 사이트에 적합한 가장 균형 잡힌 선택입니다.
모드 3: Ignore cache-control header and use this TTL
- 의미: 원본 서버 설정과 관계없이 지정한 시간만큼 강제로 캐시합니다.
- 적합한 상황: 정적 사이트이거나 캐시 전략을 정확히 알고 있습니다.
- 제 평가: 강제적이지만 효과적이며 사이트 전체 HTML 캐시에 적합합니다.
HTML 캐시에는 모드 3을 권장합니다. 많은 사이트의 HTML 페이지에는 Cache-Control이 전혀 없거나 보안을 위해 no-cache가 설정되어 있어 모드 1과 2로는 캐시되지 않기 때문입니다. 모드 3은 간단하고 확실하게 강제 캐시할 수 있습니다.
TTL 기간은 어떻게 선택할까요?
사이트마다 다르므로 다음 표를 참고하세요.
| 콘텐츠 유형 | 권장 TTL | 이유 |
|---|---|---|
| 정적 리소스(이미지, CSS, JS) | 1개월 | 거의 바뀌지 않으므로 장기 캐시로 대역폭 절약 |
| 블로그 글 HTML | 1주 | 업데이트 빈도가 낮아 1주가 균형 잡힌 기간 |
| 제품 페이지 HTML | 1~3일 | 가격과 재고가 바뀔 수 있어 너무 오래 캐시하면 안 됨 |
| 홈페이지 HTML | 1일 | 업데이트가 잦으므로 TTL을 짧게 설정 |
| API 엔드포인트 | 캐시하지 않거나 5분 | 데이터 실시간성이 중요함 |
무료 플랜의 최소값은 2시간입니다. 더 짧게 설정할 수 없다면 플랜 제한 때문입니다.
제 블로그에서는 TTL을 1주로 설정했습니다. 실제로 사용해 보니 만족스럽습니다. 새 글을 발행한 뒤 캐시를 직접 Purge하고 나면 나머지 기간에는 캐시 적중률이 매우 높게 유지됩니다.
흔한 구성 실수(제가 모두 겪었습니다)
실수 1: 관리자 페이지를 제외하지 않음
처음에는 편하게 하려고 ‘Cache Everything’ 규칙 하나만 만들었고, 결국 WordPress 관리자 화면까지 캐시됐습니다. 로그인할 때마다 이전 페이지가 표시됐고, 작업 후에도 캐시를 직접 새로고침해야 결과를 볼 수 있어 매우 불편했습니다.
해결 방법: 반드시 Bypass 규칙을 먼저 만들고 우선순위를 가장 높게 설정하세요.
실수 2: TTL을 너무 길게 설정해 콘텐츠가 제때 갱신되지 않음
TTL을 1개월로 설정한 적이 있는데, 글 제목을 바꿨는데도 방문자에게는 이전 제목이 계속 보였습니다. 며칠 뒤에야 캐시가 원인이라는 것을 떠올렸습니다.
해결 방법: 업데이트 빈도에 맞춰 TTL을 설정하세요. 자주 업데이트하면 짧게, 드물게 업데이트하면 길게 설정합니다. 확신이 없다면 우선 1주로 테스트해 보세요.
실수 3: Edge TTL과 Browser TTL을 혼동함
Edge TTL은 CDN 노드의 캐시 기간이고 Browser TTL은 방문자 브라우저의 캐시 기간입니다. 둘은 서로 독립적입니다.
- Edge TTL: Cloudflare CDN 노드가 새 콘텐츠를 가져오기 위해 원본 서버에 다시 요청하는 주기를 제어합니다.
- Browser TTL: 방문자 브라우저가 CDN에 새 콘텐츠를 다시 요청하는 주기를 제어합니다.
Edge TTL만 설정하고 Browser TTL을 설정하지 않으면 방문자 브라우저는 계속 CDN에 자주 요청합니다. CDN이 원본 서버에 요청하지는 않지만 방문자 입장에서의 속도 개선은 제한적입니다.
해결 방법: Browser TTL은 ‘Respect origin’으로 설정하거나 1일 같은 적절한 값으로 설정할 수 있습니다.
캐시 수동 삭제: Purge Cache
콘텐츠가 업데이트되면 어떻게 해야 할까요? TTL이 만료될 때까지 기다리지 않고 캐시를 직접 삭제할 수 있습니다.
Cloudflare 대시보드에서 다음 단계를 진행합니다.
- ‘Caching’ 메뉴로 이동합니다.
- ‘Purge Cache’ 영역을 찾습니다.
- 다음 중 하나를 선택합니다.
- Purge Everything: 사이트 전체 캐시 삭제. 간단하지만 영향이 큽니다.
- Custom Purge: 특정 URL의 캐시만 정확히 삭제합니다.
저는 보통 Custom Purge로 업데이트된 몇 개의 페이지만 삭제합니다. 사이트 전체 캐시를 삭제하면 잠시 모든 요청이 원본 서버로 몰려 서버 부하가 급격히 증가합니다.
팁: WordPress를 사용한다면 Cloudflare 플러그인을 설치해 글을 발행할 때 관련 페이지의 캐시를 자동으로 Purge할 수 있어 매우 편리합니다.
검증과 최적화: 캐시가 실제로 적용됐는지 확인하기
구성을 마쳤다면 실제로 적용됐는지 추측하지 말고 데이터로 확인해야 합니다.
방법 1: 브라우저 개발자 도구에서 확인
가장 간단하고 직접적인 방법입니다.
- Chrome 또는 다른 브라우저를 엽니다.
- F12로 개발자 도구를 엽니다.
- ‘Network’ 탭으로 이동합니다.
- 사이트 홈페이지에 접속합니다.
- Network 목록에서 보통 첫 번째 요청인 HTML 문서를 찾습니다.
- 문서를 클릭하고 ‘Headers’를 확인합니다.
다음 헤더를 중점적으로 확인하세요.
cf-cache-status: 가장 중요한 값이며 다음 중 하나로 표시됩니다.
- HIT: 캐시 적중. 콘텐츠가 원본 서버가 아닌 CDN에서 제공됩니다.
- MISS: 캐시 미적중. 이번에는 원본 서버에 요청했지만 콘텐츠가 캐시에 저장됩니다.
- DYNAMIC: 캐시하지 않는 동적 콘텐츠입니다. Bypass 규칙이 적용되었을 수 있습니다.
- BYPASS: 명시적으로 캐시를 우회합니다. 관리자 페이지에 해당해야 합니다.
- EXPIRED: 캐시가 만료되어 CDN이 원본 서버에서 갱신합니다.
첫 번째 요청은 보통 MISS이고 두 번째 요청부터 HIT가 되어야 합니다. 계속 DYNAMIC 또는 BYPASS라면 구성에 문제가 있습니다.
age: 콘텐츠가 CDN에 캐시된 시간(초)을 보여 주는 헤더입니다. 예를 들어 age: 3600은 콘텐츠가 CDN에 캐시된 지 1시간이 되었다는 뜻입니다.
cache-control: 원본 서버가 설정한 캐시 전략입니다. Cloudflare에서 ‘Ignore cache-control’ 모드를 사용해도 이 헤더는 표시되지만 Cloudflare는 이를 따르지 않습니다.
방법 2: curl 명령으로 검증
명령줄을 주로 사용한다면 curl이 더 빠르고 편리합니다.
curl -I https://your-website.com
출력에는 모든 response headers가 표시됩니다. cf-cache-status가 HIT인지 MISS인지 확인하세요.
더 자세히 보고 싶다면 다음 명령을 사용합니다.
curl -svo /dev/null https://your-website.com 2>&1 | grep -i "cf-cache"
이 명령은 Cloudflare 관련 헤더만 표시합니다.
방법 3: Cloudflare Analytics에서 캐시 지표 확인
전체 효과를 확인하려면 Cloudflare 대시보드에서 다음 단계를 진행합니다.
- 도메인을 선택합니다.
- 왼쪽 ‘Analytics’ 메뉴를 클릭합니다.
- ‘Caching’ 탭을 찾습니다.
- ‘Cache Hit Ratio’를 확인합니다.
구성 전에는 적중률이 30%였지만 구성 다음 날 85%까지 올랐고, 현재는 약 90%로 안정적으로 유지됩니다. 적중률이 이 정도로 상승했다면 구성이 성공한 것입니다.
정상 지표 참고:
- 캐시 적중률: 목표 80% 이상
- 대역폭 절약: 많은 콘텐츠가 원본 서버로 전달되지 않으므로 사용량이 눈에 띄게 감소해야 합니다.
- 요청 수: CDN이 처리하는 요청은 크게 늘고 원본 서버 요청은 크게 줄어야 합니다.
캐시 적중률을 높이는 고급 팁
적중률이 충분히 높지 않다면 다음 방법을 시도해 보세요.
팁 1: 캐시 예열
새로 발행한 콘텐츠의 첫 번째 요청은 항상 MISS입니다. 첫 사용자부터 HIT가 되게 하려면 미리 ‘예열’할 수 있습니다.
새 글을 발행한 뒤 모든 페이지를 직접 한 번씩 방문해 CDN이 콘텐츠를 캐시하도록 합니다. 사이트를 자동으로 crawl하는 스크립트를 작성해도 됩니다.
팁 2: URL 형식 통일
같은 페이지라도 URL이 다르면 서로 다른 캐시 객체로 취급됩니다.
https://example.com/page와https://example.com/page?는 서로 다릅니다.https://example.com/page와https://example.com/page/도 서로 다릅니다.
불필요한 캐시 MISS를 피하려면 사이트 링크 형식을 통일하세요.
팁 3: 불필요한 Query String 제거
URL에 ?utm_source=twitter 같은 추적 매개변수가 있으면 각 매개변수 조합이 서로 다른 페이지로 간주되어 캐시 적중률이 크게 떨어집니다.
Cloudflare에는 ‘Query String Sort’ 기능이 있습니다. Caching 설정에서 활성화하면 query 매개변수를 정렬한 뒤 캐시하므로 적중률을 어느 정도 높일 수 있습니다.
더 좋은 방법은 Cloudflare Transform Rules로 콘텐츠에 영향을 주지 않는 query 매개변수를 제거하는 것입니다.
자주 발생하는 문제 해결
문제 1: cf-cache-status가 계속 DYNAMIC으로 표시됨
가능한 원인:
- 원본 서버의 Cache-Control에
no-cache또는private이 설정되어 있습니다. - Cache Rule이 잘못 구성되어 요청이 ‘Eligible for cache’ 규칙과 일치하지 않습니다.
해결 방법: Cache Rules의 일치 조건을 확인하고 HTML 요청이 포함되어 있는지 확인합니다. 모드 3(Ignore cache-control)을 사용하면 강제로 캐시할 수 있어야 합니다.
문제 2: 캐시 적중률이 50~60%에 불과함
가능한 원인:
- 일부 페이지 URL에 동적 매개변수가 있습니다.
- 원본 서버의 일부 헤더가 캐시를 막고 있습니다.
- 구성을 막 마쳐 CDN 노드가 콘텐츠를 차례로 캐시하는 중입니다.
해결 방법: 새 구성이 CDN 노드 전체에 캐시될 때까지 하루나 이틀 기다립니다. Analytics에서 어떤 요청 유형의 적중률이 낮은지 확인하고 해당 유형을 집중적으로 최적화하세요.
문제 3: 콘텐츠를 업데이트했는데 방문자에게 이전 버전이 표시됨
가능한 원인: TTL이 너무 길거나 Browser Cache에도 콘텐츠가 캐시되어 있습니다.
해결 방법: 콘텐츠를 발행한 뒤 Purge Cache를 직접 실행하거나 WordPress용 자동화 플러그인을 설치하세요.
정리
핵심 단계를 다시 살펴보겠습니다.
- Cloudflare가 기본적으로 HTML을 캐시하지 않는 이유 이해: 동적 콘텐츠와 민감한 페이지를 캐시하지 않으려는 보안 목적이 가장 큽니다.
- Page Rules에서 Cache Rules로 마이그레이션: Page Rules는 폐기될 예정이며 Cache Rules가 더 강력하고 유연합니다. ‘Eligible for cache’는 기존의 ‘Cache Everything’에 해당합니다.
- Cache Rules 3개 구성:
- 규칙 1(우선순위 1): 관리자 및 로그인 페이지 Bypass
- 규칙 2(우선순위 2): 정적 리소스 캐시
- 규칙 3(우선순위 3): 나머지 모든 콘텐츠(HTML)를 강제로 캐시하고 TTL은 1주로 설정
- 올바른 Edge TTL 모드 선택: HTML에는 ‘Ignore cache-control and use this TTL’을 사용해 강제로 캐시하고 업데이트 빈도에 따라 기간을 조정합니다.
- 효과 검증: 브라우저 개발자 도구에서
cf-cache-status를 확인하고 Analytics에서 캐시 적중률을 확인합니다. 목표는 80% 이상입니다.
저도 구성을 마친 뒤 캐시 적중률이 30%에서 90%로 상승했고, TTFB는 500밀리초에서 100여 밀리초로 줄었으며, 서버 부하는 90% 감소했습니다. 특히 트래픽이 많은 사이트에서 효과가 매우 큽니다.
지금 바로 적용해 보세요:
- 먼저 Cloudflare Analytics에서 현재 캐시 적중률을 확인합니다.
- 이 글의 절차대로 Cache Rules 3개를 구성합니다. 반드시 관리자 화면부터 제외하세요.
- 하루나 이틀 뒤 Analytics에서 효과를 확인합니다.
문제가 생기면 다음 항목을 확인하세요.
- 관리자 페이지가 Bypass되었나요?
- Cache Rules의 우선순위가 올바른가요?
- 올바른 Edge TTL 모드를 선택했나요?
WordPress를 사용한다면 글을 발행할 때 캐시를 자동으로 삭제하는 Cloudflare 공식 플러그인을 설치하는 것을 적극 권장합니다. 훨씬 편리합니다.
질문이나 최적화 경험이 있다면 댓글로 공유해 주세요. 함께 이야기해 봅시다!
Cloudflare Cache Rules를 구성해 캐시 적중률을 높이는 전체 절차
HTML이 캐시되지 않는 이유를 이해하는 단계부터 Cache Rules 3개를 구성하는 단계까지 따라 하며 캐시 적중률을 30%에서 90%로 높입니다.
Estimated time: PT1H
-
1
Step 1: Cloudflare의 기본 캐시 동작과 HTML을 캐시하지 않는 이유 이해
Cloudflare 기본 캐시 전략: -
2
Step 2: Page Rules에서 Cache Rules로 마이그레이션
Page Rules는 폐기되었습니다. -
3
Step 3: 규칙 1 구성: 관리자 및 관리 페이지 우회(가장 높은 우선순위)
왜 첫 번째여야 할까요? 보안이 가장 중요하기 때문입니다. 이 규칙은 관리자 화면과 로그인 페이지가 절대 캐시되지 않도록 합니다. -
4
Step 4: 규칙 2 구성: 정적 리소스 캐시(중간 우선순위)
Cloudflare는 기본적으로 정적 리소스를 캐시하므로 이 규칙은 선택 사항입니다. 하지만 명시적으로 구성하면 TTL을 더 정확하게 제어할 수 있습니다. -
5
Step 5: 규칙 3 구성: 나머지 모든 콘텐츠 캐시(가장 낮은 우선순위)
이 규칙은 HTML을 포함한 나머지 모든 콘텐츠를 캐시합니다. -
6
Step 6: 효과 검증과 최적화 팁
브라우저 개발자 도구에서 확인:
FAQ
Cloudflare는 왜 기본적으로 HTML을 캐시하지 않으며, HTML 캐시로 어느 정도 개선할 수 있나요?
HTML 페이지는 일반적으로 사용자별 정보를 포함할 수 있는 ‘동적 콘텐츠’로 간주되므로 기본적으로 캐시되지 않습니다. 사이트에 로그인 기능이 있다면 HTML에 사용자 이름과 개인 정보가 포함될 수 있으므로, CDN이 이를 캐시해 다른 사람에게 보여서는 안 됩니다.
커뮤니티 포럼에서 사이트 전체 캐시를 바로 켰다가 wp-login.php 로그인 페이지와 로그인 계정 정보까지 모두 캐시된 사례를 본 적이 있습니다. 그 결과 어떤 방문자든 캐시된 페이지를 통해 WordPress 관리자 화면에 바로 들어갈 수 있었습니다.
HTML 캐시로 얻을 수 있는 개선:
Medium에서 HTML 캐시를 구성한 뒤 TTFB가 500밀리초에서 100~160밀리초로 줄고 서버 부하가 90% 감소했다는 데이터를 본 적이 있습니다. 효과가 매우 큽니다.
왜 이렇게 큰 차이가 날까요?
간단합니다. 이전에는 방문자가 사이트를 열 때마다 HTML을 원본 서버에서 가져와야 했고, 서버는 요청 처리, 데이터베이스 조회, 페이지 렌더링을 수행해야 했습니다. 이제는 CDN이 캐시된 HTML을 방문자에게 바로 전달하므로 원본 서버가 처리할 일이 없습니다. 트래픽이 많을수록 차이는 더 커집니다.
저도 구성을 마친 뒤 캐시 적중률이 30%에서 90%로 상승했고, TTFB는 500밀리초에서 100여 밀리초로 줄었으며, 서버 부하는 90% 감소했습니다.
Page Rules와 Cache Rules의 차이는 무엇이며, 어떻게 마이그레이션하나요?
• 2024년 7월부터 새로 가입한 무료 계정은 Page Rules를 사용할 수 없습니다.
• Cloudflare는 2025년에 기존 Page Rules를 새 시스템으로 자동 마이그레이션합니다.
• 앞으로 새 구성은 모두 Cache Rules를 사용해야 합니다.
왜 폐기할까요?
Page Rules는 기능이 오래되었고 구성 유연성이 부족하며, 무료 플랜에서는 규칙을 3개만 만들 수 있습니다. 복잡한 캐시 전략에는 충분하지 않습니다.
Cache Rules의 장점:
• 훨씬 강력한 기능
• 더 유연한 일치 조건(URI 경로, 파일 확장자, 호스트 이름 등 여러 조건에 따라 일치시키고 정규 표현식을 지원하며 여러 조건을 조합할 수 있음)
가장 큰 차이:
• Page Rules에서는 모든 콘텐츠를 캐시하려면 ‘Cache Everything’을 직접 선택해야 했습니다.
• Cache Rules에서는 ‘Eligible for cache’를 선택하면 Cache Everything 기능이 자동으로 활성화됩니다.
이 변화는 꽤 중요합니다. 처음에는 이를 모르고 ‘Cache Everything’ 옵션을 계속 찾다가 이름이 바뀌었다는 사실을 뒤늦게 알았습니다.
마이그레이션 주의 사항:
• Cloudflare가 마이그레이션을 지원합니다(2025년에 Page Rules를 Cache Rules로 자동 변환하므로 직접 작업할 필요가 없음).
• 일부 설정은 마이그레이션되지 않습니다(특히 이미 폐기된 ‘Disable Security’와 ‘Disable Performance’).
• 동작에 약간의 차이가 있습니다(Cache Rules의 ‘Eligible for cache’는 Page Rules의 ‘Cache Everything’에 해당하지만 구현 논리는 조금 다름).
어차피 전환해야 하므로 지금부터 Cache Rules를 사용하는 것이 좋습니다.
사이트 전체를 캐시하는 3개의 Cache Rules는 어떻게 구성하며, 실행 순서는 어떻게 되나요?
• Rule name에 ‘Bypass Admin Pages’ 입력
• When incoming requests match에서 ‘Custom filter expression’ 선택
• Field에서 ‘URI Path’, Operator에서 ‘contains’를 선택하고 Value에 /wp-admin 입력
• 제외 경로 추가(/wp-login.php, /admin/, /api/auth/ 등)
• Then에서 ‘Bypass cache’ 선택
• 우선순위를 1로 설정
이 규칙은 해당 경로가 포함된 모든 요청이 캐시를 거치지 않고 원본 서버로 바로 전달되도록 합니다.
규칙 2(중간 우선순위): 정적 리소스 캐시
• Rule name에 ‘Cache Static Assets’ 입력
• When incoming requests match에서 ‘File extension’ 선택
• Operator에서 ‘is in’을 선택하고 Value에 jpg png gif css js woff woff2 ttf svg ico 입력
• Then에서 ‘Eligible for cache’ 선택
• Edge cache TTL에서 ‘Use cache-control header if present, use default Cloudflare caching behavior if not’ 선택
• 우선순위를 2로 설정
규칙 3(가장 낮은 우선순위): 나머지 모든 콘텐츠 캐시
• Rule name에 ‘Cache Everything Else’ 입력
• When incoming requests match에서 ‘All incoming requests’ 선택
• Then에서 ‘Eligible for cache’ 선택
• Edge cache TTL에서 ‘Ignore cache-control header and use this TTL’ 선택
• 기간을 7 days(1주)로 선택
• 우선순위를 3으로 설정
규칙 실행 순서:
Cloudflare는 우선순위 숫자가 작은 규칙부터 실행합니다. 먼저 규칙 1로 관리자 페이지인지 확인하고, 이어서 규칙 2로 정적 리소스인지 확인한 다음, 규칙 3으로 나머지 모든 요청을 1주간 캐시합니다. 이 순서로 관리자 페이지는 확실하게 캐시하지 않고, 정적 리소스에는 적절한 TTL을 적용하며, HTML 페이지는 1주간 강제로 캐시할 수 있습니다.
Edge TTL의 세 가지 모드는 어떻게 다르며, 무엇을 선택해야 하나요?
• 의미: Cache-Control이 있으면 따르고, 없으면 캐시하지 않음
• 적합한 상황: 원본 서버에 완전한 Cache-Control 헤더가 구성되어 있음
• 평가: 많은 소규모 사이트에는 원본 서버의 Cache-Control 설정이 없어 사실상 캐시되지 않으므로 지나치게 엄격함
모드 2: Use cache-control header if present, use default Cloudflare caching behavior if not
• 의미: Cache-Control이 있으면 따르고, 없으면 Cloudflare 기본 규칙 사용
• 적합한 상황: 원본 서버 일부에만 Cache-Control이 구성되어 있고 나머지는 Cloudflare가 처리하기를 원함
• 평가: 대부분의 사이트에 적합한 가장 균형 잡힌 선택
모드 3: Ignore cache-control header and use this TTL
• 의미: 원본 서버 설정과 관계없이 지정한 시간만큼 강제로 캐시
• 적합한 상황: 정적 사이트이거나 캐시 전략을 정확히 알고 있음
• 평가: 강제적이지만 효과적이며 사이트 전체 HTML 캐시에 적합함
HTML 캐시에는 모드 3을 권장합니다. 많은 사이트의 HTML 페이지에는 Cache-Control이 전혀 없거나 보안을 위해 no-cache가 설정되어 있어 모드 1과 2로는 캐시되지 않기 때문입니다. 모드 3은 간단하게 강제 캐시할 수 있습니다.
TTL 기간 선택:
• 정적 리소스(이미지, CSS, JS): 1개월 권장
• 블로그 글 HTML: 1주 권장
• 제품 페이지 HTML: 1~3일 권장
• 홈페이지 HTML: 1일 권장
• API 엔드포인트: 캐시하지 않거나 5분
무료 플랜의 최소값은 2시간입니다. 더 짧게 설정할 수 없다면 플랜 제한 때문입니다.
캐시가 적용되었는지 어떻게 검증하고 캐시 적중률을 높이나요?
1. Chrome을 열고 F12로 개발자 도구를 엽니다.
2. ‘Network’ 탭으로 이동합니다.
3. 사이트 홈페이지에 접속합니다.
4. Network 목록에서 HTML 문서를 찾아 클릭하고 ‘Headers’를 확인합니다.
cf-cache-status에서 확인할 값:
• HIT: 캐시 적중. 콘텐츠가 원본 서버가 아닌 CDN에서 제공됨
• MISS: 캐시 미적중. 이번에는 원본 서버에 요청했지만 콘텐츠가 캐시에 저장됨
• DYNAMIC: 캐시하지 않는 동적 콘텐츠
• BYPASS: 명시적으로 캐시를 우회함. 관리자 페이지에 해당해야 함
• EXPIRED: 캐시가 만료되어 CDN이 원본 서버에서 갱신함
첫 번째 요청은 보통 MISS이고 두 번째 요청부터 HIT가 되어야 합니다. 계속 DYNAMIC 또는 BYPASS라면 구성에 문제가 있습니다.
curl 명령으로 검증:
curl -I https://your-website.com
출력된 모든 response headers에서 cf-cache-status가 HIT인지 MISS인지 확인합니다.
Cloudflare Analytics에서 확인:
1. 도메인을 선택하고 왼쪽 ‘Analytics’ 메뉴를 클릭합니다.
2. ‘Caching’ 탭을 찾습니다.
3. ‘Cache Hit Ratio’를 확인합니다.
구성 전에는 적중률이 30%였지만 구성 다음 날 85%까지 올랐고, 현재는 약 90%로 안정적으로 유지됩니다.
정상 지표 참고:
• 캐시 적중률 목표 80% 이상
• 대역폭 사용량이 눈에 띄게 감소해야 함
• 요청 수: CDN이 처리하는 요청은 크게 늘고 원본 서버 요청은 크게 줄어야 함
캐시 적중률을 높이는 고급 팁:
• 캐시 예열(새 콘텐츠를 발행한 뒤 모든 페이지를 한 번씩 방문해 CDN이 콘텐츠를 캐시하도록 함)
• URL 형식 통일(같은 페이지라도 URL이 다르면 서로 다른 캐시 객체로 취급됨)
• 불필요한 Query String 제거(Cloudflare Transform Rules로 콘텐츠에 영향을 주지 않는 query 매개변수를 제거)
캐시 구성 후 콘텐츠가 업데이트되면 어떻게 하나요? 캐시는 어떻게 수동으로 삭제하나요?
1. Cloudflare 대시보드에서 ‘Caching’ 메뉴로 이동합니다.
2. ‘Purge Cache’ 영역을 찾습니다.
3. 다음 중 하나를 선택합니다.
• Purge Everything(사이트 전체 캐시 삭제, 간단하지만 영향이 큼)
• Custom Purge(특정 URL의 캐시만 정확히 삭제)
저는 보통 Custom Purge로 업데이트된 몇 개의 페이지만 삭제합니다. 사이트 전체 캐시를 삭제하면 잠시 모든 요청이 원본 서버로 몰려 서버 부하가 급격히 증가합니다.
팁: WordPress를 사용한다면 Cloudflare 플러그인을 설치해 글을 발행할 때 관련 페이지의 캐시를 자동으로 Purge할 수 있습니다.
TTL을 너무 길게 설정해 콘텐츠가 제때 갱신되지 않는 문제:
TTL을 1개월로 설정한 적이 있는데, 글 제목을 바꿨는데도 방문자에게는 이전 제목이 계속 보였습니다. 며칠 뒤에야 캐시가 원인이라는 것을 떠올렸습니다.
해결 방법:
• 업데이트 빈도에 맞춰 TTL 설정
• 자주 업데이트하면 짧게, 드물게 업데이트하면 길게 설정
• 확신이 없다면 우선 1주로 테스트
• 콘텐츠 발행 후 수동으로 Purge Cache하거나 자동화 플러그인 설치(WordPress용 플러그인이 다양함)
Edge TTL과 Browser TTL을 혼동하는 문제:
Edge TTL은 CDN 노드의 캐시 기간이고 Browser TTL은 방문자 브라우저의 캐시 기간입니다. 둘은 서로 독립적입니다.
• Edge TTL: Cloudflare CDN 노드가 새 콘텐츠를 가져오기 위해 원본 서버에 다시 요청하는 주기를 제어
• Browser TTL: 방문자 브라우저가 CDN에 새 콘텐츠를 다시 요청하는 주기를 제어
Edge TTL만 설정하고 Browser TTL을 설정하지 않으면 방문자 브라우저는 계속 CDN에 자주 요청합니다. CDN이 원본 서버에 요청하지는 않지만 방문자 입장에서의 속도 개선은 제한적입니다.
해결 방법: Browser TTL은 ‘Respect origin’으로 설정하거나 1일 같은 적절한 값으로 설정할 수 있습니다.
3분 읽기 · 게시일: 2025년 12월 1일 · 수정일: 2026년 9월 4일
Cloudflare 풀스택
검색으로 들어왔다면 같은 시리즈의 이전 글이나 다음 글로 이동하는 것이 가장 빠릅니다.
이전
CF Pages 빌드 실패? 반나절의 디버깅 시간을 아껴 주는 8가지 일반적인 문제와 해결 방법
의존성 설치, Node 버전, 빌드 시간 초과, 모듈 해석 등 Cloudflare Pages 빌드 실패의 대표적인 8가지 상황을 체계적으로 정리하고, 검증된 해결 방법과 예방 조치를 통해 개발자가 문제를 빠르게 찾아 디버깅 시간을 줄일 수 있도록 돕습니다.
15편 중 4편
다음
Cloudflare 방화벽 규칙 초보자 가이드: 무료 규칙 5개로 악성 트래픽 80% 차단하기(템플릿 포함)
Cloudflare 무료 요금제의 방화벽 규칙은 5개뿐일까요? IP, ASN, UA, 경로 필터 조건을 다루는 실전 검증 WAF 규칙 템플릿과 우선순위 설정 방법을 소개합니다. 30분 만에 악성 트래픽의 80%를 차단할 수 있는 전체 코드를 제공합니다.
15편 중 6편



댓글
GitHub로 로그인하여 댓글을 남기세요