서버 운영
Nginx에서 정적 파일 캐시 헤더 제대로 설정하기
정적 파일은 캐시해서 빠르게 제공해야 하는데, 헤더 설정을 잘못하면 유저가 오래된 파일을 계속 본다.
Next.js나 React를 배포할 때, Nginx는 정적 파일을 빠르게 제공하는 역할을 한다. 하지만 캐시 헤더를 제대로 설정하지 않으면, 유저가 며칠 전 파일을 계속 보거나, 매번 새로 받아야 하는 비효율이 생긴다.
정적 파일 종류별 캐시 전략
웹 애플리케이션의 정적 파일은 두 종류로 나뉜다.
Hashed 파일 (내용이 바뀔 때마다 이름이 바뀜): CSS, JS 번들, 이미지
- 캐시: 오래 (1년 이상)
- 예:
bundle.abc123.js,style.def456.css
Non-hashed 파일 (이름이 항상 같음): HTML, 폰트, 메타데이터
- 캐시: 짧거나 없음 (몇 시간, 또는 항상 재검증)
- 예:
index.html,/robots.txt
Nginx 설정 예시
location ~* ^/static/(.+)\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2)$ {
# Hashed 파일은 오래 캐시
expires 365d;
add_header Cache-Control "public, immutable";
}
location ~* \.(html|json|txt|xml)$ {
# HTML과 메타데이터는 항상 재검증
add_header Cache-Control "public, max-age=0, must-revalidate";
}
location / {
# SPA의 index.html은 항상 fresh해야 함
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
실제 배포 때 확인하기
설정이 제대로 적용되었는지 확인하려면 curl로 헤더를 보면 된다.
# Hashed 파일 확인
curl -I https://example.com/static/bundle.abc123.js | grep -i cache-control
# 출력: Cache-Control: public, immutable
# HTML 파일 확인
curl -I https://example.com/index.html | grep -i cache-control
# 출력: Cache-Control: no-cache, no-store, must-revalidate
자주 실수하는 부분
1. 모든 파일에 같은 캐시 정책 적용
Nginx의 기본 설정을 그대로 쓰면, 모든 파일에 짧은 캐시만 적용된다. 이러면 hashed 파일도 매번 재다운로드해야 한다.
2. Gzip과 캐시 헤더를 함께 고려하지 않음
Gzip으로 압축한 파일을 캐시할 때는 Vary: Accept-Encoding 헤더를 추가해야 한다. 그렇지 않으면 Gzip을 지원하지 않는 클라이언트가 압축 파일을 받을 수 있다.
add_header Vary "Accept-Encoding" always;
3. CDN 없이 Nginx에만 의존
캐시 헤더가 완벽해도, Nginx 하나만으로는 지역별 성능이 떨어진다. 대규모 트래픽이 있으면 CDN을 앞에 두는 게 낫다.
빌드 시점에 파일 구분하기
Next.js와 같은 프레임워크는 빌드할 때 hashed 파일을 자동으로 생성한다. 설정에서 이를 활용하자.
# Next.js의 출력 구조
.next/static/chunks/ # Hashed 파일들
.next/public/ # Non-hashed 파일들
Nginx에서는 이 구조에 맞춰 다른 캐시 정책을 적용하면 된다.
모니터링
배포 후 실제로 유저가 받는 캐시가 맞는지 확인해야 한다.
# 브라우저 DevTools에서 Network 탭 확인
# Age: 헤더가 0이면 fresh, 높으면 캐시에서 온 것
# X-Cache: HIT/MISS 헤더가 있으면 프록시 캐시 상태도 확인 가능
정리
정적 파일 캐시는 한 번 제대로 설정하면 운영 비용을 크게 줄인다. Hashed 파일은 오래, HTML은 짧게 하는 기본 원칙을 따르고, 배포할 때마다 설정을 검증하자. CDN을 쓰면 더 좋지만, Nginx의 캐시 헤더만 제대로 설정해도 대부분의 성능 문제는 해결된다.