FE가 알아야하는 Nginx 주요설정

Jinmin Kim·2025년 5월 16일

Nginx

1. 캐싱·압축

정적 자원 캐싱

location ~* \.(js|css|png|jpg|jpeg|svg|woff2?)$ {
  expires 7d;                                # 7일간 캐시
  add_header Cache-Control "public, max-age=604800";
}

1️⃣ expires 7d;

  • 브라우저에게 “이 리소스는 7일 동안 새로 요청하지 말라”고 지시합니다.
  • 7일 이내 재방문 시 서버 대신 브라우저 로컬 캐시에서 즉시 로드 → 네트워크 트래픽 절감, 로드 속도 개선

2️⃣ add_header Cache-Control "public, max-age=604800";

  • public: 공유 캐시(CDN 등)도 리소스를 저장할 수 있게 허용
  • max-age=604800: 초 단위(7일×24h×3600s)로 유효 기간 지정

🔥정적 자원 캐싱의 부작용

1️⃣오래된 리소스 제공 (Stale Content)

문제: 브라우저가 7일간 캐시를 사용하면서, 파일을 업데이트해도 클라이언트가 구버전을 계속 볼 수 있음

  • 대처: 파일명에 해시(bundle.abc123.js) 적용
    → 파일이 변경될 때마다 새로운이름으로 배포

  • 파일명 해시 적용

//webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    // [name]: 진입점 이름, [contenthash]: 파일 내용 기반 해시
    filename: '[name].[contenthash].js',
    clean: true,            // 배포 전 dist 폴더 정리
    publicPath: '/',       
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      // 스크립트 태그에 자동으로 해시된 파일명 삽입
    }),
  ],
  mode: 'production',
};
immutable 지시어
add_header Cache-Control "public, max-age=604800, immutable";
  • 기존: public, max-age=604800 → 7일 동안 재검증 없이 캐시
    그러나 일부 브라우저/CDN은 만료 전에도 ETag/Last-Modified 조건 요청을 보낼 수 있음

  • immutable 추가 시:“이 리소스는 절대 변경되지 않는다” 고 강력히 선언
    브라우저/프록시는 만료 기간 내내 (max-age 동안) 절대
    서버에 조건부 요청(If-None-Match/If-Modified-Since)도 보내지 않습니다

결과적으로 네트워크 왕복(왕복 시간) 완전 제거
캐시 적중률·성능 최상. 오직 파일명이 바뀔 때(해시 변경)만 새 리소스를 요청

⚠️ 주의:
1. 해시 전략과 함께 사용해야 안전합니다.
2. 파일 내용이 바뀌어도 이름이 같다면, 브라우저는 갱신하지 않습니다!

3️⃣ 동적 리소스 과도 캐싱
  • 동적 리소스 과도 캐싱
    동적 리소스(예: API 응답 JSON, XML, HTML 조각 등)는 서버 상태나 사용자 입력에 따라 수시로 변경됩니다.
해결 전략: 캐싱 대상 분리
  • 3-1. 정적 리소스만 별도 location으로 캐싱
# 오직 js, css, 이미지 파일만 7일간 캐싱
location ~* \.(?:js|css|png|jpg|jpeg|svg|woff2?)$ {
  expires 7d;
  add_header Cache-Control "public, max-age=604800, immutable";
}
  • 3-2. 동적 리소스엔 no-cache 헤더 적용
# 예: API 응답(JSON/XML) 또는 HTML 조각
location ~* \.(?:json|xml|html)$ {
  # 1) 브라우저에 캐시 저장은 허용하되 매 요청마다 서버 재검증
  add_header Cache-Control "no-cache, must-revalidate";
  # 또는
  # add_header Cache-Control "no-store";

  # 실제 파일 서빙 시
  root /var/www/myapp/data;
}

# 또는 API 엔드포인트 전체
location /api/ {
  proxy_pass http://backend;
  add_header Cache-Control "no-cache, must-revalidate";
}
  • no-cache: 로컬 저장은 가능하나, 매번 ETag/Last-Modified 로 조건부 GET 재검증
  • must-revalidate: 서버가 캐시 만료 후 반드시 유효성 확인
  • no-store: 어떤 상황에도 저장 금지(가장 강력)

Gzip 압축

http {
  gzip on;
  gzip_min_length 1024;
  gzip_types text/plain application/javascript text/css application/json;
  gzip_proxied any;
}

1️⃣ gzip on;

  • HTTP 응답 바디를 gzip 알고리즘으로 압축 전송

2️⃣ gzip_min_length 1024;

  • 1 KB 이하의 작은 파일은 압축하지 않도록 하여, 오히려 압축 오버헤드를 줄임

3️⃣ gzip_types …

  • 텍스트, JS, CSS, JSON 등 압축 효과가 큰 MIME 타입만 지정

4️⃣ gzip_proxied any;

  • 클라이언트가 프록시 뒤에 있어도 모든 응답을 압축 전송

5️⃣ 효과

  • 평균 전송 크기 60–80% 감소 → 페이지 로드 시간 단축, 대역폭 절약
profile
Let's do it developer

0개의 댓글