Nginx로 정적 자산 캐싱하여 빠른 웹사이트 만들기
정적 자산 캐싱이 중요한 이유
사용자가 웹사이트를 방문할 때마다 브라우저는 CSS 파일, JavaScript, 이미지, 폰트 등 수십 개의 정적 자산을 요청합니다. 적절한 캐싱이 없으면 각 요청이 서버에 도달하여 로드 시간과 대역폭 사용량이 증가합니다. 고성능 웹 서버인 Nginx는 브라우저가 이러한 자산을 로컬에 캐시하도록 지시하고 서버 측에서도 캐시함으로써 이를 극적으로 개선할 수 있습니다.
이 가이드에서는 Nginx를 구성하여 정적 자산을 효과적으로 캐시하고 지연 시간과 서버 부하를 줄이는 방법을 배웁니다.
브라우저 캐싱 vs. 서버 측 캐싱 이해하기
여기서 관련된 두 가지 주요 캐싱 유형이 있습니다:
- 브라우저 캐싱: 브라우저는
Cache-Control및Expires와 같은 HTTP 헤더를 기반으로 자산을 로컬에 저장합니다. 이후 방문 시 디스크에서 자산을 로드하여 네트워크 요청을 피합니다. - 서버 측 캐싱: Nginx는 응답을 메모리나 디스크에 저장하고 반복 요청에 대해 직접 제공하여 백엔드 부하를 줄입니다.
둘 다 성능에 중요합니다. 우리는 둘 다 다룰 것입니다.
1단계: Expires 헤더로 브라우저 캐싱 구성하기
브라우저 캐싱을 활성화하는 가장 간단한 방법은 Nginx 구성에 expires 지시문을 추가하는 것입니다. 이는 Expires 및 Cache-Control 헤더를 설정합니다.
사이트의 구성 파일(예: /etc/nginx/sites-available/example.com)을 열고 정적 자산에 대한 location 블록을 추가하세요:
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
이것은 브라우저에게 이 파일들을 1년 동안 캐시하도록 지시합니다. immutable 지시문은 파일이 절대 변경되지 않을 것임을 나타내므로 브라우저는 새로고침 시 재검증조차 하지 않습니다.
모범 사례: 버전이 지정된 파일 이름(예: style.abc123.css)을 사용하여 캐싱을 깨지 않고 자산을 업데이트할 수 있습니다. 파일이 변경되면 파일 이름이 변경되고 브라우저는 새 버전을 가져옵니다.
2단계: 프록시 캐시로 서버 측 캐싱 활성화하기
Nginx 뒤에서 애플리케이션 서버(예: Node.js, Python 또는 PHP)를 실행 중인 경우 Nginx에서 정적 응답을 캐시하여 백엔드 요청을 줄일 수 있습니다.
먼저 nginx.conf의 http 블록에서 캐시 경로를 정의하세요:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=static_cache:10m max_size=1g inactive=60m use_temp_path=off;
그런 다음 서버 블록에서 사용하세요:
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg)$ {
proxy_cache static_cache;
proxy_cache_valid 200 302 1y;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://backend;
}
이것은 성공적인 응답을 1년 동안 캐시하고 백엔드가 다운된 경우 오래된 콘텐츠를 제공합니다. X-Cache-Status 헤더는 디버깅에 도움이 됩니다(HIT, MISS 등).
3단계: 압축 및 HTTP/2로 최적화하기
캐싱은 요청을 줄이지만 gzip 압축과 HTTP/2를 활성화하여 전송 속도를 더 높일 수 있습니다.
nginx.conf에서 gzip을 활성화하세요:
gzip on;
gzip_types text/css application/javascript image/svg+xml;
gzip_min_length 1000;
HTTP/2는 요청을 다중화하며 listen 지시문에 http2를 추가하여 활성화됩니다:
listen 443 ssl http2;
참고: HTTP/2는 HTTPS가 필요합니다. 아직 TLS를 설정하지 않았다면 HTTPS와 TLS가 실제로 작동하는 방식에 대한 가이드를 참조하세요.
비교: Cache-Control 지시문
| 지시문 | 의미 | 권장 대상 |
|---|---|---|
public |
응답은 모든 캐시에 의해 캐시될 수 있음 | 정적 자산 |
private |
응답은 단일 사용자를 위한 것 | 사용자별 데이터 |
no-cache |
서버와 재검증해야 함 | HTML 페이지 |
no-store |
절대 캐시하지 않음 | 민감한 데이터 |
immutable |
콘텐츠가 변경되지 않음 | 버전이 지정된 자산 |
4단계: 테스트 및 검증하기
변경 사항을 적용한 후 Nginx를 다시 로드하세요: sudo nginx -s reload. 그런 다음 curl로 테스트하세요:
curl -I https://example.com/style.css
Cache-Control 및 Expires 헤더를 확인하세요. 브라우저 DevTools(Network 탭)를 사용하여 자산이 캐시에서 제공되는지(상태 200 또는 304) 확인할 수도 있습니다.
서버 측 캐시의 경우 X-Cache-Status 헤더를 모니터링하세요.
일반적인 함정과 모범 사례
- HTML을 캐시하지 마세요: HTML은 동적이거나 업데이트를 반영하기 위해 짧은 캐시 시간을 가져야 합니다.
- 버전 관리 사용: 콘텐츠가 변경될 때 캐시를 무효화하기 위해 파일 이름에 해시를 추가하세요.
- 적절한 max-age 설정: 버전이 지정된 자산의 경우 1년이 안전합니다.
- 캐시 크기 모니터링: 서버 측 캐시는 커질 수 있으므로
max_size및inactive를 설정하세요. - CDN 고려: 글로벌 사용자의 경우 CDN이 사용자에게 더 가까운 곳에 자산을 캐시할 수 있습니다.
자주 묻는 질문
자산이 캐시되고 있는지 어떻게 알 수 있나요?
curl -I 또는 브라우저 DevTools로 응답 헤더를 확인하세요. Cache-Control: public, max-age=31536000 및 Expires 헤더를 찾으세요. DevTools에서 Size 열은 캐시된 자산에 대해 "(from disk cache)"를 표시합니다.
expires와 Cache-Control의 차이점은 무엇인가요?
expires는 절대 날짜를 설정하는 반면 Cache-Control은 상대 초를 사용합니다. 최신 브라우저에서는 Cache-Control이 우선합니다. Nginx의 expires 지시문은 호환성을 위해 둘 다 설정합니다.
동적 콘텐츠를 캐시할 수 있나요?
예, 하지만 주의해야 합니다. 짧은 TTL로 proxy_cache를 사용하고 쿠키나 헤더를 기반으로 한 캐시 키를 고려하세요. 사용자별 콘텐츠의 경우 private을 사용하거나 캐싱을 피하세요.
TryQuickToolBox로 워크플로우 속도 높이기
사이트 성능을 최적화하는 동안 이미지나 PDF를 압축해야 할 수 있습니다. 이미지 압축기를 사용하여 품질 손실 없이 이미지 크기를 줄여 Nginx 캐싱 전략을 보완하세요.