CDN 캐시 흐름을 상징하는 방패와 박스 일러스트
Cloudflare를 붙이고 나면 기본적으로 빨라지지만, 운영을 하다 보면 “어떤 페이지는 즉시 바뀌고 어떤 페이지는 예전 내용이 남는다” 같은 캐시 불일치가 꽤 자주 나옵니다. 특히 정적 파일(CSS/JS/이미지)과 HTML, 로그인/관리자 페이지가 섞여 있으면 더 복잡해지고요.

아래는 Cloudflare 포함한 실전 운영 관점에서, 캐시/CDN을 성능에 도움이 되게 정리하는 점검 루트입니다.

1) 증상 먼저 분류하기: “느림”이 아니라 “캐시 정책 충돌”일 때

캐시 이슈는 단순히 서버가 느린 게 아니라, 어디에서 무엇을 얼마나 저장하는지가 꼬여서 생기는 경우가 많습니다. 먼저 증상을 아래처럼 나눠 보면 원인 추적이 빨라집니다.

  • HTML만 가끔 옛날로 보인다: Cloudflare HTML 캐시 규칙, origin의 Cache-Control, 쿠키/로그인 구분 문제 가능
  • CSS/JS만 반영이 늦다: 파일명 버전 관리(해시), 브라우저 캐시, Cloudflare Edge 캐시 TTL 문제 가능
  • 특정 지역/특정 네트워크에서만 다르다: Edge PoP별 캐시 편차, DNS/프록시 상태, 캐시 워밍 영향 가능
  • 관리자만 다르게 보인다: 쿠키 존재 시 캐시 우회/비우회 정책 충돌 가능

2) Chrome에서 3단 확인: 브라우저 캐시 vs Cloudflare 캐시 vs Nginx(origin)

운영 중 가장 안전한 접근은 “어디 캐시가 문제인지”를 먼저 분리하는 것입니다. Chrome DevTools에서 아래 순서로 확인하세요.

  • DevTools → Network에서 해당 요청을 선택하고 Response Headers 확인
  • cache-control, etag, last-modified, age(있으면) 체크
  • cf-cache-status 확인: HIT / MISS / EXPIRED / BYPASS / DYNAMIC
  • Disable cache(DevTools 상단) 체크 후 새로고침: 브라우저 캐시 영향 제거

해석은 보통 이렇게 합니다.

  • cf-cache-status: HIT인데 내용이 오래됨 → Cloudflare Edge 캐시가 오래된 것
  • cf-cache-status: BYPASS/DYNAMIC인데 느림 → Cloudflare가 캐시를 안 하고 origin(Nginx)로 매번 가는 구조
  • Disable cache를 꺼야만 최신이 보임 → 브라우저 캐시 정책(파일명/TTL)이 핵심

브라우저 헤더 확인과 캐시 상태 점검 개념도

3) Cloudflare에서 캐시를 “잘” 먹이는 기준: HTML과 정적 리소스를 분리

Cloudflare 운영에서 자주 하는 실수는, HTML과 정적 리소스를 같은 감각으로 캐시하려는 겁니다. 실무에서는 보통 다음 원칙이 안전합니다.

  • 정적 파일(CSS/JS/이미지): 길게 캐시(예: 7일~1년) + 파일명에 버전(해시) 적용
  • HTML(페이지): 원칙적으로 짧게 캐시하거나, 조건부 캐시(로그인/쿠키 제외)로 제한
  • /admin, /login, 결제/장바구니: 캐시 금지(또는 BYPASS) 고정

Cloudflare 쪽에서는 “모든 걸 캐시”보다 Cache Rules(또는 Page Rules)로 경로별 정책을 나누는 편이 운영 안정성이 높습니다. 특히 쿠키가 있는 요청을 캐시 대상으로 잡아버리면, 사용자별 페이지가 섞이는 사고로 이어질 수 있으니 조심하세요.

4) Nginx에서 헤더를 정리해 Cloudflare가 오해하지 않게 만들기

Cloudflare는 origin(Nginx)의 응답 헤더를 강하게 참고합니다. 즉, Nginx가 애매한 헤더를 주면 Cloudflare도 애매하게 동작할 수 있습니다. 아래 체크리스트로 “의도”를 명확히 하는 게 핵심입니다.

  • 정적 파일에는 명확한 Cache-Control 설정(예: public, max-age)
  • HTML에는 상황에 맞는 Cache-Control(예: no-cache 또는 짧은 max-age)
  • ETag를 쓸지 말지 결정(중간 캐시가 있을 때는 일관성이 중요)
  • gzip/brotli 적용 시 Vary 헤더와 조합 확인(특히 Accept-Encoding)

실전 팁으로는, 정적 파일은 “파일명 버전화 + 장기 캐시”를 기본으로 두고, HTML은 운영 성격에 맞게 보수적으로 가는 게 트러블이 적습니다. (예: 정적 사이트/문서 성격이면 HTML도 캐시 가능, 게시판/개인화가 많으면 HTML 캐시는 신중)

Nginx와 Cloudflare 사이 캐시 계층 흐름 도식

5) “업데이트가 늦게 보임”을 줄이는 운영 루틴: Purge에 의존하지 않기

운영자가 자주 겪는 패턴이 “배포 후 Purge Cache를 눌러야 정상”입니다. 이 상태가 계속되면, 결국 Purge가 누락되는 순간 장애처럼 보이게 됩니다. Purge 의존도를 낮추려면 아래 순서로 구조를 바꾸는 게 좋습니다.

  • 정적 파일 파일명에 버전(해시) 적용: 새 파일은 새 URL로 배포되어 캐시 충돌이 줄어듦
  • HTML은 짧은 TTL 또는 조건부 캐시: “조금 늦어도 괜찮은 범위”만 캐시
  • Cloudflare 캐시 규칙을 경로 기준으로 단순화: 예외가 많을수록 누락/충돌 가능성이 커짐
  • 배포 후 확인 루틴을 Chrome 헤더 점검으로 표준화: cf-cache-status, cache-control만 봐도 대부분 판단 가능

6) 성능 개선 루트(캐시/CDN 포함) 최종 점검 체크리스트

  • Chrome에서 cf-cache-status가 기대대로 나오나? (정적=HIT 유도, 개인화=우회)
  • 정적 파일에 긴 Cache-Control을 주고, 파일명은 버전 관리하는가?
  • HTML은 캐시해도 되는 범위만 캐시하고, admin/login은 확실히 제외했나?
  • Nginx 응답에 cache-control/etag/last-modified가 일관되게 설정되어 있나?
  • 문제 재현 시 DevTools Disable cache로 브라우저 캐시를 분리해 확인했나?
  • 배포 절차가 Purge를 누르는 사람에 의존하지 않게 설계되어 있나?

마무리

Cloudflare+Nginx 조합에서 캐시는 성능을 크게 올려주지만, HTML/정적/개인화가 섞이는 순간부터는 “정책 설계”가 필요해집니다. 크롬에서 헤더를 기준으로 캐시 위치를 분리해 보고, 정적 파일은 버전화+장기 캐시로, HTML은 보수적으로 가져가면 운영 스트레스가 확 줄어듭니다.

지금 겪는 증상(특정 URL/확장자/쿠키 유무/지역)을 기준으로 캐시 규칙과 Nginx 헤더를 함께 조정해 보세요.