turin.blog
← 전체 글로 돌아가기

practical debugging note

Nginx 정적 파일 캐시 헤더를 붙일 때 내가 정한 선

정적 파일에 긴 캐시를 주다가 HTML까지 늦게 갱신될 뻔한 경험을 바탕으로 Nginx 캐시 헤더 설정 기준을 정리했습니다.

빠른 요약

같은 캐시라도 파일마다 다르게 봐야 했다 프론트 배포 후 Lighthouse 점수를 보다가 정적 파일 캐시 경고를 봤다.

이 글에서 확인할 것
  • 같은 캐시라도 파일마다 다르게 봐야 했다
  • 설정 예시
  • 적용 전에 확인한 명령어
  • 내가 피한 설정
  • 기준은 단순하게 남겼다

같은 캐시라도 파일마다 다르게 봐야 했다

프론트 배포 후 Lighthouse 점수를 보다가 정적 파일 캐시 경고를 봤다. 처음에는 expires 1y를 넓게 넣으면 끝이라고 생각했다. 하지만 HTML까지 오래 캐시되면 새 배포가 사용자에게 늦게 보일 수 있다.

그때 헷갈린 기준은 "브라우저가 오래 들고 있어도 안전한 파일인가"였다. 해시가 붙은 JS, CSS와 /index.html은 같은 방식으로 다루면 안 됐다.

설정 예시

내가 정리한 Nginx 설정은 이런 형태다.

location /_next/static/ {
  add_header Cache-Control "public, max-age=31536000, immutable";
  try_files $uri =404;
}

location ~* \.(png|jpg|jpeg|webp|svg|ico)$ {
  add_header Cache-Control "public, max-age=604800";
  try_files $uri =404;
}

location / {
  add_header Cache-Control "no-cache";
  try_files $uri $uri/ /index.html;
}

Next.js처럼 빌드 결과물에 해시가 붙는 정적 파일은 길게 캐시해도 새 배포 때 URL이 바뀐다. 반대로 HTML은 같은 URL로 새 내용을 받아야 하니 재검증이 필요하다.

적용 전에 확인한 명령어

설정을 바꾼 뒤에는 브라우저보다 curl로 먼저 확인했다.

curl -I https://example.com/_next/static/chunks/main.js
curl -I https://example.com/

여기서 봐야 할 것은 상태 코드만이 아니다.

  • Cache-Control 값이 의도한 위치에만 붙었는지
  • 404 응답에도 이상한 캐시가 붙지 않는지
  • 프록시가 같은 헤더를 중복으로 추가하지 않는지

내가 피한 설정

아래처럼 모든 응답에 긴 캐시를 주는 방식은 피했다.

add_header Cache-Control "public, max-age=31536000" always;

처음 보면 간단하지만, 로그인 페이지나 HTML 문서까지 오래 남을 수 있다. 특히 학생 프로젝트에서는 설정 파일을 복사해 쓰는 일이 많아서 더 위험하다.

기준은 단순하게 남겼다

해시가 있는 빌드 파일은 길게, 사람이 같은 URL로 다시 보는 문서는 짧게. 이 한 줄 기준만 있어도 다음에 배포 캐시 문제가 생겼을 때 어디부터 확인할지 훨씬 빨라진다.